diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 000000000..a872639f8 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,22 @@ +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) + +{{ range .CommitGroups -}} +### {{ .Title }} + +{{ range .Commits -}} +* {{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} + +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 000000000..a0f3b6f75 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,27 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/interlay/polkabtc-clients +options: + commits: + # filters: + # Type: + # - feat + # - fix + # - perf + # - refactor + commit_groups: + # title_maps: + # feat: Features + # fix: Bug Fixes + # perf: Performance Improvements + # refactor: Code Refactoring + header: + pattern: "^(\\w*)\\:\\s(.*)$" + pattern_maps: + - Type + - Subject + notes: + keywords: + - BREAKING CHANGE \ No newline at end of file diff --git a/.deploy/charts/README.md b/.deploy/charts/README.md deleted file mode 100644 index aa84bd8e9..000000000 --- a/.deploy/charts/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# PolkaBTC Kubernetes Helm Charts - -A collection of Helm Charts to deploy specialized PolkaBTC services to a Kubernetes cluster. - -## Staked Relayer - -### Install - -To install the chart with the release name `my-release` into namespace `my-namespace` from within this directory: - -```bash -helm install --namespace my-namespace my-release staked-relayer/ -``` - -### Upgrade - -To upgrade the `my-release` deployment: - -```bash -helm upgrade --namespace my-namespace my-release staked-relayer/ -``` diff --git a/.deploy/charts/oracle/.helmignore b/.deploy/charts/oracle/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/.deploy/charts/oracle/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/.deploy/charts/oracle/Chart.yaml b/.deploy/charts/oracle/Chart.yaml deleted file mode 100644 index 78d76339a..000000000 --- a/.deploy/charts/oracle/Chart.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v2 -name: oracle -description: Helm chart for the Oracle - -type: application -version: 0.1.0 -appVersion: 1.16.0 diff --git a/.deploy/charts/oracle/templates/_helpers.tpl b/.deploy/charts/oracle/templates/_helpers.tpl deleted file mode 100644 index b046476ea..000000000 --- a/.deploy/charts/oracle/templates/_helpers.tpl +++ /dev/null @@ -1,63 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "oracle.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "oracle.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "oracle.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "oracle.labels" -}} -helm.sh/chart: {{ include "oracle.chart" . }} -{{ include "oracle.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "oracle.selectorLabels" -}} -app.kubernetes.io/name: {{ include "oracle.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "oracle.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "oracle.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/.deploy/charts/oracle/templates/_settings.yaml b/.deploy/charts/oracle/templates/_settings.yaml deleted file mode 100644 index e622d19fe..000000000 --- a/.deploy/charts/oracle/templates/_settings.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- define "settings" -}} -{{- range $.Values.environment.secrets }} -- name: {{ .name }} - valueFrom: - secretKeyRef: - name: {{ .secret }} - key: {{ .key }} -{{- end }} -{{- range $key, $val := $.Values.environment.inline }} -- name: {{ $key }} - value: {{ $val | quote }} -{{- end }} -{{- end -}} \ No newline at end of file diff --git a/.deploy/charts/oracle/templates/deployment.yaml b/.deploy/charts/oracle/templates/deployment.yaml deleted file mode 100644 index 319b88edd..000000000 --- a/.deploy/charts/oracle/templates/deployment.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "oracle.fullname" . }} - labels: - {{- include "oracle.labels" . | nindent 4 }} -spec: -{{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} -{{- end }} - selector: - matchLabels: - {{- include "oracle.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "oracle.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "oracle.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - {{- include "settings" $ | nindent 10 }} - command: - - oracle - - --polka-btc-url - - "ws://parachain-polkabtc-rpc:9944" - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/.deploy/charts/oracle/templates/serviceaccount.yaml b/.deploy/charts/oracle/templates/serviceaccount.yaml deleted file mode 100644 index e3a5a4010..000000000 --- a/.deploy/charts/oracle/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "oracle.serviceAccountName" . }} - labels: - {{- include "oracle.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/.deploy/charts/oracle/values.yaml b/.deploy/charts/oracle/values.yaml deleted file mode 100644 index 65f1035ef..000000000 --- a/.deploy/charts/oracle/values.yaml +++ /dev/null @@ -1,81 +0,0 @@ -replicaCount: 1 - -image: - repository: "registry.gitlab.com/interlay/polkabtc-clients" - pullPolicy: Always - tag: "oracle-latest" - -imagePullSecrets: - - name: regcred - -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -ingress: - enabled: false - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: [] - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -environment: - inline: - RUST_LOG: info - secrets: [] diff --git a/.deploy/charts/staked-relayer/.helmignore b/.deploy/charts/staked-relayer/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/.deploy/charts/staked-relayer/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/.deploy/charts/staked-relayer/Chart.lock b/.deploy/charts/staked-relayer/Chart.lock deleted file mode 100644 index 6bc12af8d..000000000 --- a/.deploy/charts/staked-relayer/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: parachain - repository: file://../parachain - version: 0.1.0 -digest: sha256:7765173c3bd30d0dea2f1731948a5f7bd5d4a3d8e06374192a3aedcd83a7c211 -generated: "2020-09-29T12:09:19.718768236+01:00" diff --git a/.deploy/charts/staked-relayer/Chart.yaml b/.deploy/charts/staked-relayer/Chart.yaml deleted file mode 100644 index 275b6277e..000000000 --- a/.deploy/charts/staked-relayer/Chart.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v2 -name: staked-relayer -description: Helm chart for the Staked Relayer client - -type: application - -version: 0.1.0 - -appVersion: 1.16.0 diff --git a/.deploy/charts/staked-relayer/templates/_helpers.tpl b/.deploy/charts/staked-relayer/templates/_helpers.tpl deleted file mode 100644 index 96ca6a4e1..000000000 --- a/.deploy/charts/staked-relayer/templates/_helpers.tpl +++ /dev/null @@ -1,63 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "staked-relayer.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "staked-relayer.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "staked-relayer.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "staked-relayer.labels" -}} -helm.sh/chart: {{ include "staked-relayer.chart" . }} -{{ include "staked-relayer.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "staked-relayer.selectorLabels" -}} -app.kubernetes.io/name: {{ include "staked-relayer.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "staked-relayer.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "staked-relayer.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/.deploy/charts/staked-relayer/templates/_settings.yaml b/.deploy/charts/staked-relayer/templates/_settings.yaml deleted file mode 100644 index e622d19fe..000000000 --- a/.deploy/charts/staked-relayer/templates/_settings.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- define "settings" -}} -{{- range $.Values.environment.secrets }} -- name: {{ .name }} - valueFrom: - secretKeyRef: - name: {{ .secret }} - key: {{ .key }} -{{- end }} -{{- range $key, $val := $.Values.environment.inline }} -- name: {{ $key }} - value: {{ $val | quote }} -{{- end }} -{{- end -}} \ No newline at end of file diff --git a/.deploy/charts/staked-relayer/templates/deployment.yaml b/.deploy/charts/staked-relayer/templates/deployment.yaml deleted file mode 100644 index e573da8bd..000000000 --- a/.deploy/charts/staked-relayer/templates/deployment.yaml +++ /dev/null @@ -1,72 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "staked-relayer.fullname" . }} - labels: - {{- include "staked-relayer.labels" . | nindent 4 }} -spec: -{{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} -{{- end }} - selector: - matchLabels: - {{- include "staked-relayer.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "staked-relayer.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "staked-relayer.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - {{- include "settings" $ | nindent 10 }} - command: - - staked-relayer - - --polka-btc-url - - "ws://parachain-polkabtc-rpc:9944" - - --http-addr - - "[::0]:{{ .Values.service.port }}" - ports: - - name: http-rpc - containerPort: {{ .Values.service.port }} - readinessProbe: - httpGet: - path: /health - port: http-rpc - initialDelaySeconds: 10 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /health - port: http-rpc - initialDelaySeconds: 10 - periodSeconds: 10 - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/.deploy/charts/staked-relayer/templates/service.yaml b/.deploy/charts/staked-relayer/templates/service.yaml deleted file mode 100644 index 31ef08b16..000000000 --- a/.deploy/charts/staked-relayer/templates/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "staked-relayer.fullname" . }} - labels: - {{- include "staked-relayer.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - {{ if eq .Values.service.type "NodePort" -}} - nodePort: {{ .Values.service.nodePort }} - {{- end }} - name: http-rpc - selector: - {{- include "staked-relayer.selectorLabels" . | nindent 4 }} diff --git a/.deploy/charts/staked-relayer/templates/serviceaccount.yaml b/.deploy/charts/staked-relayer/templates/serviceaccount.yaml deleted file mode 100644 index 54c391aa1..000000000 --- a/.deploy/charts/staked-relayer/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "staked-relayer.serviceAccountName" . }} - labels: - {{- include "staked-relayer.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/.deploy/charts/staked-relayer/values.yaml b/.deploy/charts/staked-relayer/values.yaml deleted file mode 100644 index 07823a175..000000000 --- a/.deploy/charts/staked-relayer/values.yaml +++ /dev/null @@ -1,85 +0,0 @@ -replicaCount: 1 - -image: - repository: "registry.gitlab.com/interlay/polkabtc-clients" - pullPolicy: Always - tag: "staked-relayer-latest" - -imagePullSecrets: - - name: regcred - -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: NodePort - nodePort: 32700 - port: 3030 - -ingress: - enabled: false - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: [] - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -environment: - inline: - RUST_LOG: info - BITCOIN_RPC_URL: http://bitcoin-bitcoind:18332 - BITCOIN_RPC_USER: rpcuser - BITCOIN_RPC_PASS: rpcpassword - secrets: [] diff --git a/.gitignore b/.gitignore index ea7856e21..4dcf66312 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ **.tgz **/.vscode/ event-logs +faucet/kv \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 63525531c..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,116 +0,0 @@ -image: "registry.gitlab.com/interlay/containers/rust-base:nightly-2021-01-25" - -variables: - CARGO_HOME: $CI_PROJECT_DIR/.cargo - -stages: - - test - - build - - deploy - -.rust-before-script: &rustup_sscache - before_script: - - rustup show - - rustc --version - - rustfmt --version - - cargo --version - - SCCACHE_START_SERVER=1 SCCACHE_IDLE_TIMEOUT=0 sccache - - sccache -s - -.docker-script: &build_docker - image: - name: gcr.io/kaniko-project/executor:debug - entrypoint: [""] - script: - - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json - - | - /kaniko/executor \ - --build-arg BINARY=${IMAGE} \ - --context ${CI_PROJECT_DIR} \ - --dockerfile ${CI_PROJECT_DIR}/.deploy/Dockerfile \ - --destination ${CI_REGISTRY_IMAGE}/${IMAGE}:${CI_COMMIT_SHORT_SHA} \ - --destination ${CI_REGISTRY_IMAGE}/${IMAGE}:${CI_COMMIT_REF_SLUG} - -.only-refs: &only_refs - only: - - tags - - master - - dev - - kaniko # debug - -test-clients: - stage: test - variables: - CARGO_HOME: $CI_PROJECT_DIR/.cargo - RUSTC_WRAPPER: /usr/local/bin/sccache - SCCACHE_GCS_RW_MODE: READ_WRITE - <<: *rustup_sscache - script: - - cargo fmt -- --check - - cargo check --all - - cargo test --all - - - sccache -s - cache: - key: cargo - paths: - - .cargo - only: - - merge_requests - -build-clients: - stage: build - variables: - CARGO_HOME: $CI_PROJECT_DIR/.cargo - RUSTC_WRAPPER: /usr/local/bin/sccache - SCCACHE_GCS_RW_MODE: READ_WRITE - <<: *rustup_sscache - <<: *only_refs - script: - - cargo build --workspace --release - - sccache -s - artifacts: - name: "${CI_COMMIT_REF_SLUG}" - paths: - - target/release/staked-relayer - - target/release/oracle - - target/release/vault - - target/release/testdata-gen - - target/release/faucet - - -docker-publish-staked-relayer: - stage: deploy - variables: - IMAGE: staked-relayer - <<: *build_docker - <<: *only_refs - -docker-publish-oracle: - stage: deploy - variables: - IMAGE: oracle - <<: *build_docker - <<: *only_refs - -docker-publish-vault: - stage: deploy - variables: - IMAGE: vault - <<: *build_docker - <<: *only_refs - -docker-publish-testdata-gen: - stage: deploy - variables: - IMAGE: testdata-gen - <<: *build_docker - <<: *only_refs - -docker-publish-faucet: - stage: deploy - variables: - IMAGE: faucet - <<: *build_docker - <<: *only_refs - diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 000000000..a77308f50 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,11 @@ +# https://rust-lang.github.io/rustfmt/ + +hard_tabs = false +max_width = 120 +edition = "2018" +wrap_comments = true +comment_width = 120 +imports_granularity = "Crate" + +# TODO: https://github.com/rust-lang/rustfmt/issues/3382#issuecomment-536034758 +blank_lines_lower_bound = 0 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 04065b359..286164128 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,9 +23,9 @@ dependencies = [ [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" @@ -81,12 +81,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "ahash" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" - [[package]] name = "ahash" version = "0.4.7" @@ -175,6 +169,16 @@ dependencies = [ "syn", ] +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "async-channel" version = "1.6.1" @@ -276,12 +280,13 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" dependencies = [ + "async-attributes", "async-channel", "async-global-executor", "async-io", "async-lock", "async-process", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", "futures-channel", "futures-core", "futures-io", @@ -292,7 +297,7 @@ dependencies = [ "memchr", "num_cpus", "once_cell", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", "pin-utils", "slab", "wasm-bindgen-futures", @@ -306,21 +311,22 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-tls" -version = "0.6.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce6977f57fa68da77ffe5542950d47e9c23d65f5bc7cb0a9f8700996913eec7" +checksum = "2f23d769dbf1838d5df5156e7b1ad404f4c463d1ac2c6aeb6cd943630f8a8400" dependencies = [ - "futures 0.3.12", - "rustls 0.16.0", + "futures-core", + "futures-io", + "rustls 0.19.0", "webpki", - "webpki-roots 0.17.0", + "webpki-roots", ] [[package]] name = "async-trait" -version = "0.1.42" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" +checksum = "36ea56748e10732c49404c153638a15ec3d6211ec5ff35d9bb20e13b93576adf" dependencies = [ "proc-macro2", "quote", @@ -337,7 +343,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", ] [[package]] @@ -350,7 +356,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", ] [[package]] @@ -440,21 +446,6 @@ dependencies = [ "safemem", ] -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -dependencies = [ - "byteorder", -] - -[[package]] -name = "base64" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" - [[package]] name = "base64" version = "0.12.3" @@ -475,9 +466,9 @@ checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" [[package]] name = "bincode" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" dependencies = [ "byteorder", "serde", @@ -509,15 +500,35 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.2.0" +version = "0.5.0" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" +dependencies = [ + "bitcoin_hashes 0.7.6", + "frame-support", + "hex 0.4.3", + "impl-serde", + "parity-scale-codec", + "primitive-types", + "secp256k1", + "serde", + "sha2 0.8.2", + "sp-core", + "sp-std", + "spin 0.7.1", +] + +[[package]] +name = "bitcoin" +version = "0.5.0" dependencies = [ "async-trait", "backoff", - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "bitcoincore-rpc", "clap 3.0.0-beta.2", - "futures 0.3.12", - "hex 0.4.2", + "futures 0.3.13", + "hex 0.4.3", + "hyper 0.10.16", "log 0.4.14", "mockall", "num", @@ -529,25 +540,6 @@ dependencies = [ "tokio 0.2.25", ] -[[package]] -name = "bitcoin" -version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" -dependencies = [ - "bitcoin_hashes 0.7.6", - "frame-support", - "hex 0.4.2", - "impl-serde", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", - "secp256k1", - "serde", - "sha2 0.8.2", - "sp-core", - "sp-std", - "spin 0.7.1", -] - [[package]] name = "bitcoin" version = "0.26.0" @@ -605,9 +597,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitvec" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5011ffc90248764d7005b0e10c7294f5aa1bd87d9dd7248f4ad475b347c294d" +checksum = "1f682656975d3a682daff957be4ddeb65d6ad656737cd821f2d00685ae466af1" dependencies = [ "funty", "radium", @@ -682,7 +674,7 @@ dependencies = [ "block-padding 0.1.5", "byte-tools", "byteorder", - "generic-array 0.12.3", + "generic-array 0.12.4", ] [[package]] @@ -733,12 +725,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "bs58" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" - [[package]] name = "bs58" version = "0.4.0" @@ -757,7 +743,7 @@ dependencies = [ [[package]] name = "btc-parachain" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "btc-parachain-rpc", "btc-parachain-runtime", @@ -767,7 +753,7 @@ dependencies = [ "funty", "hex-literal 0.2.1", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-chain-spec", "sc-cli", "sc-service", @@ -786,7 +772,7 @@ dependencies = [ [[package]] name = "btc-parachain-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "btc-parachain-runtime", "jsonrpc-core 15.1.0", @@ -813,7 +799,7 @@ dependencies = [ [[package]] name = "btc-parachain-runtime" version = "0.5.1" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "btc-relay", "collateral", @@ -849,7 +835,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parachain-info", "parachain-tokens", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-parachain", "redeem", "refund", @@ -883,7 +869,7 @@ dependencies = [ [[package]] name = "btc-parachain-service" version = "0.5.1" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "btc-parachain-rpc", "btc-parachain-runtime", @@ -925,16 +911,16 @@ dependencies = [ [[package]] name = "btc-relay" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "frame-benchmarking", "frame-support", "frame-system", - "hex 0.4.2", + "hex 0.4.3", "pallet-timestamp", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "security", "serde", "sla", @@ -942,7 +928,6 @@ dependencies = [ "sp-core", "sp-io", "sp-std", - "util", ] [[package]] @@ -956,15 +941,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" - -[[package]] -name = "byte-slice-cast" -version = "0.3.5" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byte-slice-cast" @@ -980,9 +959,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.4.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "bytes" @@ -1037,9 +1016,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" dependencies = [ "jobserver", ] @@ -1103,9 +1082,9 @@ dependencies = [ [[package]] name = "cid" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d88f30b1e74e7063df5711496f3ee6e74a9735d62062242d70cddf77717f18e" +checksum = "ff0e3bc0b6446b3f9663c1a6aba6ef06c5aeaa1bc92bd18077be337198ab9768" dependencies = [ "multibase", "multihash", @@ -1191,12 +1170,12 @@ dependencies = [ [[package]] name = "collateral" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", "frame-system", "pallet-balances", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", ] @@ -1209,12 +1188,6 @@ dependencies = [ "cache-padded", ] -[[package]] -name = "const_fn" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1385,7 +1358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", ] [[package]] @@ -1406,8 +1379,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", - "crossbeam-epoch 0.9.1", - "crossbeam-utils 0.8.1", + "crossbeam-epoch 0.9.3", + "crossbeam-utils 0.8.3", ] [[package]] @@ -1427,13 +1400,12 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" dependencies = [ "cfg-if 1.0.0", - "const_fn", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", "lazy_static", "memoffset 0.6.1", "scopeguard", @@ -1463,9 +1435,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg 1.0.1", "cfg-if 1.0.0", @@ -1484,7 +1456,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ - "generic-array 0.12.3", + "generic-array 0.12.4", "subtle 1.0.0", ] @@ -1507,6 +1479,15 @@ dependencies = [ "sct", ] +[[package]] +name = "ct-logs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" +dependencies = [ + "sct", +] + [[package]] name = "ctor" version = "0.1.19" @@ -1531,17 +1512,18 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#0a0dc9b80b62a8c0591f4c8b12cf7af2a9263ae3" +source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#24b1ee6bd1d96f255889f167e59ef9c9399a6305" dependencies = [ "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", - "frame-executive", + "environmental", "frame-support", "frame-system", "hash-db", + "log 0.4.14", "memory-db", "pallet-balances", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-parachain", "serde", "sp-core", @@ -1559,23 +1541,25 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm-handler" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#0a0dc9b80b62a8c0591f4c8b12cf7af2a9263ae3" +source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#24b1ee6bd1d96f255889f167e59ef9c9399a6305" dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "sp-std", "xcm", + "xcm-executor", ] [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#0a0dc9b80b62a8c0591f4c8b12cf7af2a9263ae3" +source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#24b1ee6bd1d96f255889f167e59ef9c9399a6305" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-primitives", @@ -1587,10 +1571,10 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#0a0dc9b80b62a8c0591f4c8b12cf7af2a9263ae3" +source = "git+https://github.com/paritytech/cumulus?branch=rococo-v1#24b1ee6bd1d96f255889f167e59ef9c9399a6305" dependencies = [ "cumulus-primitives-core", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-client-api", "sp-api", "sp-core", @@ -1677,7 +1661,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3", + "generic-array 0.12.4", ] [[package]] @@ -1916,8 +1900,8 @@ dependencies = [ "fixed-hash 0.7.0", "impl-rlp", "impl-serde", - "primitive-types 0.9.0", - "uint 0.9.0", + "primitive-types", + "uint", ] [[package]] @@ -1929,7 +1913,7 @@ checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "exchange-rate-oracle" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "collateral", "frame-benchmarking", @@ -1937,7 +1921,7 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-timestamp", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "security", "serde", "sp-arithmetic", @@ -1946,7 +1930,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", ] [[package]] @@ -1955,7 +1938,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", ] [[package]] @@ -2003,29 +1986,21 @@ dependencies = [ [[package]] name = "faucet" -version = "0.2.0" +version = "0.5.0" dependencies = [ - "bitcoin 0.2.0", - "btc-parachain", - "btc-parachain-service", + "async-trait", "chrono", "clap 3.0.0-beta.2", "env_logger 0.6.2", - "futures 0.3.12", - "hex 0.4.2", - "jsonrpc-http-server 16.0.0", - "jsonrpsee", + "hex 0.4.3", + "jsonrpc-http-server 17.0.0", "kv", "log 0.4.14", - "parity-scale-codec 2.0.0", - "pin-project-lite 0.2.4", + "parity-scale-codec", "runtime", "serde", "serde_json", - "sp-core", "sp-keyring", - "substrate-subxt-client", - "tempdir", "thiserror", "tokio 0.2.25", ] @@ -2042,14 +2017,14 @@ dependencies = [ [[package]] name = "fee" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "collateral", "frame-benchmarking", "frame-support", "frame-system", "pallet-balances", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sla", "sp-arithmetic", @@ -2058,7 +2033,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", ] [[package]] @@ -2078,11 +2052,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6447e2f8178843749e8c8003206def83ec124a7859475395777a28b5338647c" dependencies = [ "either", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "log 0.4.14", "num-traits", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", ] @@ -2162,16 +2136,16 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", ] [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding 2.1.0", @@ -2185,14 +2159,15 @@ checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2" [[package]] name = "frame-benchmarking" -version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +version = "3.1.0" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", "linregress", - "parity-scale-codec 2.0.0", - "paste 1.0.4", + "log 0.4.14", + "parity-scale-codec", + "paste 1.0.5", "sp-api", "sp-io", "sp-runtime", @@ -2204,13 +2179,13 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "Inflector", "chrono", "frame-benchmarking", "handlebars", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-cli", "sc-client-db", "sc-executor", @@ -2227,11 +2202,11 @@ dependencies = [ [[package]] name = "frame-executive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -2243,9 +2218,9 @@ dependencies = [ [[package]] name = "frame-metadata" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-core", "sp-std", @@ -2254,7 +2229,7 @@ dependencies = [ [[package]] name = "frame-support" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "bitflags", "frame-metadata", @@ -2262,8 +2237,8 @@ dependencies = [ "impl-trait-for-tuples", "log 0.4.14", "once_cell", - "parity-scale-codec 2.0.0", - "paste 1.0.4", + "parity-scale-codec", + "paste 1.0.5", "serde", "smallvec 1.6.1", "sp-arithmetic", @@ -2280,7 +2255,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -2292,7 +2267,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2304,7 +2279,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "proc-macro2", "quote", @@ -2314,11 +2289,12 @@ dependencies = [ [[package]] name = "frame-system" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -2330,12 +2306,12 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-core", "sp-runtime", "sp-std", @@ -2344,9 +2320,9 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", ] @@ -2402,15 +2378,15 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" dependencies = [ "futures-channel", "futures-core", @@ -2423,9 +2399,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", "futures-sink", @@ -2433,9 +2409,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" +checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" [[package]] name = "futures-cpupool" @@ -2443,7 +2419,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "num_cpus", ] @@ -2453,8 +2429,8 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdcef58a173af8148b182684c9f2d5250875adbcaff7b5794073894f9d8634a9" dependencies = [ - "futures 0.1.30", - "futures 0.3.12", + "futures 0.1.31", + "futures 0.3.13", "lazy_static", "log 0.4.14", "parking_lot 0.9.0", @@ -2465,9 +2441,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" +checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" dependencies = [ "futures-core", "futures-task", @@ -2477,9 +2453,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" +checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" [[package]] name = "futures-lite" @@ -2492,15 +2468,15 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" +checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -2521,18 +2497,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" +checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" [[package]] name = "futures-task" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" -dependencies = [ - "once_cell", -] +checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" [[package]] name = "futures-timer" @@ -2548,11 +2521,11 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "futures-channel", "futures-core", "futures-io", @@ -2560,7 +2533,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -2584,18 +2557,18 @@ checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "generic-array" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ "typenum", ] [[package]] name = "generic-array" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed1e761351b56f54eb9dcd0cfaca9fd0daecf93918e1cfc01c8a3d26ee7adcd" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" dependencies = [ "typenum", ] @@ -2607,7 +2580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check 0.9.2", + "version_check 0.9.3", ] [[package]] @@ -2694,7 +2667,7 @@ dependencies = [ "byteorder", "bytes 0.4.12", "fnv", - "futures 0.1.30", + "futures 0.1.31", "http 0.1.21", "indexmap", "log 0.4.14", @@ -2718,16 +2691,35 @@ dependencies = [ "indexmap", "slab", "tokio 0.2.25", - "tokio-util", + "tokio-util 0.3.1", "tracing", "tracing-futures", ] +[[package]] +name = "h2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832b01df74254fe364568d6ddc294443f61cbec82816b60904303af87efae78" +dependencies = [ + "bytes 1.0.1", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.3", + "indexmap", + "slab", + "tokio 1.3.0", + "tokio-util 0.6.4", + "tracing", +] + [[package]] name = "handlebars" -version = "3.5.2" +version = "3.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964d0e99a61fe9b1b347389b77ebf8b7e1587b70293676aaca7d27e59b9073b2" +checksum = "cdb0867bbc5a3da37a753e78021d5fcf8a4db00e18dd2dd90fd36e24190e162d" dependencies = [ "log 0.4.14", "pest", @@ -2752,23 +2744,13 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" -dependencies = [ - "ahash 0.3.8", - "autocfg 1.0.1", -] - [[package]] name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" dependencies = [ - "ahash 0.4.7", + "ahash", ] [[package]] @@ -2797,9 +2779,9 @@ checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] name = "hex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-literal" @@ -2859,7 +2841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" dependencies = [ "digest 0.8.1", - "generic-array 0.12.3", + "generic-array 0.12.4", "hmac 0.7.1", ] @@ -2892,7 +2874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "http 0.1.21", "tokio-buf", ] @@ -2907,6 +2889,16 @@ dependencies = [ "http 0.2.3", ] +[[package]] +name = "http-body" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" +dependencies = [ + "bytes 1.0.1", + "http 0.2.3", +] + [[package]] name = "httparse" version = "1.3.5" @@ -2954,7 +2946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c843caf6296fc1f93444735205af9ed4e109a539005abb2564ae1d6fad34c52" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "futures-cpupool", "h2 0.1.26", "http 0.1.21", @@ -3001,6 +2993,30 @@ dependencies = [ "want 0.3.0", ] +[[package]] +name = "hyper" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7" +dependencies = [ + "bytes 1.0.1", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.1", + "http 0.2.3", + "http-body 0.4.0", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.5", + "socket2", + "tokio 1.3.0", + "tower-service", + "tracing", + "want 0.3.0", +] + [[package]] name = "hyper-rustls" version = "0.21.0" @@ -3008,14 +3024,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6" dependencies = [ "bytes 0.5.6", - "ct-logs", + "ct-logs 0.7.0", "futures-util", "hyper 0.13.10", "log 0.4.14", "rustls 0.18.1", - "rustls-native-certs", + "rustls-native-certs 0.4.0", "tokio 0.2.25", - "tokio-rustls", + "tokio-rustls 0.14.1", + "webpki", +] + +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "ct-logs 0.8.0", + "futures-util", + "hyper 0.14.4", + "log 0.4.14", + "rustls 0.19.0", + "rustls-native-certs 0.5.0", + "tokio 1.3.0", + "tokio-rustls 0.22.0", "webpki", ] @@ -3082,7 +3115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b8538953a3f0d0d3868f0a706eb4273535e10d72acb5c82c1c23ae48835c85" dependencies = [ "async-io", - "futures 0.3.12", + "futures 0.3.13", "futures-lite", "if-addrs", "ipnet", @@ -3091,22 +3124,13 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "impl-codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" -dependencies = [ - "parity-scale-codec 1.3.6", -] - [[package]] name = "impl-codec" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df170efa359aebdd5cb7fe78edcc67107748e4737bdca8a8fb40d15ea7a877ed" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", ] [[package]] @@ -3140,12 +3164,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.9.1", + "hashbrown", "serde", ] @@ -3173,7 +3197,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-timer 2.0.2", ] @@ -3201,9 +3225,9 @@ checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" [[package]] name = "issue" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "btc-relay", "collateral", "exchange-rate-oracle", @@ -3213,8 +3237,8 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-timestamp", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "refund", "security", "serde", @@ -3226,7 +3250,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", "vault-registry", ] @@ -3256,9 +3279,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.47" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" dependencies = [ "wasm-bindgen", ] @@ -3282,7 +3305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "489b9c612e60c766f751ab40fcb43cbb55a1e10bb44a9b4307ed510ca598cbd7" dependencies = [ "failure", - "futures 0.1.30", + "futures 0.1.31", "jsonrpc-core 15.1.0", "jsonrpc-pubsub 15.1.0", "log 0.4.14", @@ -3293,19 +3316,20 @@ dependencies = [ [[package]] name = "jsonrpc-client-transports" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320acafbc911d7ef8cc056fee6affbed348dc8aaf76709bfda83d3665d092ad4" +checksum = "15b6c6ad01c7354d60de493148c30ac8a82b759e22ae678c8705e9b8e0c566a4" dependencies = [ "derive_more", - "futures 0.1.30", - "futures 0.3.12", - "hyper 0.12.36", - "jsonrpc-core 16.0.0", - "jsonrpc-pubsub 16.0.0", + "futures 0.3.13", + "hyper 0.13.10", + "hyper-tls", + "jsonrpc-core 17.0.0", + "jsonrpc-pubsub 17.0.0", "log 0.4.14", "serde", "serde_json", + "tokio 0.2.25", "url 1.7.2", ] @@ -3315,7 +3339,7 @@ version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0745a6379e3edc893c84ec203589790774e4247420033e71a76d3ab4687991fa" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "log 0.4.14", "serde", "serde_derive", @@ -3324,11 +3348,11 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a47c4c3ac843f9a4238943f97620619033dadef4b378cd1e8addd170de396b3" +checksum = "07569945133257ff557eb37b015497104cea61a2c9edaf126c1cbd6e8332397f" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", "serde", "serde_derive", @@ -3346,13 +3370,12 @@ dependencies = [ [[package]] name = "jsonrpc-core-client" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "289d049ac6a6c69e8d2023ad420934d236badda8375f1fd9960a2f67beedb42e" +checksum = "7ac9d56dc729912796637c30f475bbf834594607b27740dfea6e5fa7ba40d1f1" dependencies = [ - "futures 0.1.30", - "futures 0.3.12", - "jsonrpc-client-transports 16.0.0", + "futures 0.3.13", + "jsonrpc-client-transports 17.0.0", ] [[package]] @@ -3384,15 +3407,14 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf0d9a2b5a7396ea4847b39c2f91504013eaeac8b49681efb5b4bcb0ab27651" +checksum = "eff2303c4f0562afcbd2dae75e3e21815095f8994749a80fbcd365877e44ed64" dependencies = [ - "futures 0.1.30", - "futures 0.3.12", - "hyper 0.12.36", - "jsonrpc-core 16.0.0", - "jsonrpc-server-utils 16.0.0", + "futures 0.3.13", + "hyper 0.13.10", + "jsonrpc-core 17.0.0", + "jsonrpc-server-utils 17.0.0", "log 0.4.14", "net2", "parking_lot 0.11.1", @@ -3428,12 +3450,12 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1132f6d03de286dd21bde88191af63b5189214574f7b9cbac8e0027c732394" +checksum = "0c48dbebce7a9c88ab272a4db7d6478aa4c6d9596e6c086366e89efc4e9ed89e" dependencies = [ - "futures 0.3.12", - "jsonrpc-core 16.0.0", + "futures 0.3.13", + "jsonrpc-core 17.0.0", "lazy_static", "log 0.4.14", "parking_lot 0.11.1", @@ -3459,18 +3481,18 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d199e3780083bd0798911be3cc0543515a57a98e97f6051957af36fb11852939" +checksum = "f4207cce738bf713a82525065b750a008f28351324f438f56b33d698ada95bb4" dependencies = [ - "bytes 0.4.12", - "futures 0.1.30", + "bytes 0.5.6", + "futures 0.3.13", "globset", - "jsonrpc-core 16.0.0", + "jsonrpc-core 17.0.0", "lazy_static", "log 0.4.14", - "tokio 0.1.22", - "tokio-codec", + "tokio 0.2.25", + "tokio-util 0.3.1", "unicase 2.6.0", ] @@ -3489,46 +3511,71 @@ dependencies = [ ] [[package]] -name = "jsonrpsee" -version = "0.1.0" -source = "git+https://github.com/interlay/jsonrpsee?rev=5b35d10b5ae45a1776a8dcf761ecbe8d6e288646#5b35d10b5ae45a1776a8dcf761ecbe8d6e288646" +name = "jsonrpsee-http-client" +version = "0.2.0-alpha.2" +source = "git+https://github.com/interlay/jsonrpsee?rev=1c2ba33#1c2ba33e7d9187d687c9ee5ff219108b23fdc1a2" dependencies = [ - "async-std", - "async-tls", - "bs58 0.3.1", - "bytes 0.5.6", - "fnv", - "futures 0.3.12", - "futures-timer 3.0.2", - "globset", - "hashbrown 0.7.2", - "hyper 0.13.10", - "jsonrpsee-proc-macros", - "lazy_static", + "async-trait", + "futures 0.3.13", + "hyper 0.14.4", + "hyper-rustls 0.22.1", + "jsonrpsee-types", + "jsonrpsee-utils", + "log 0.4.14", + "serde", + "serde_json", + "thiserror", + "unicase 2.6.0", + "url 2.2.1", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.2.0-alpha.2" +source = "git+https://github.com/interlay/jsonrpsee?rev=1c2ba33#1c2ba33e7d9187d687c9ee5ff219108b23fdc1a2" +dependencies = [ + "async-trait", + "futures 0.3.13", "log 0.4.14", - "parking_lot 0.10.2", - "pin-project 0.4.27", - "rand 0.7.3", "serde", "serde_json", "smallvec 1.6.1", - "soketto 0.3.2", "thiserror", - "tokio 0.2.25", +] + +[[package]] +name = "jsonrpsee-utils" +version = "0.2.0-alpha.2" +source = "git+https://github.com/interlay/jsonrpsee?rev=1c2ba33#1c2ba33e7d9187d687c9ee5ff219108b23fdc1a2" +dependencies = [ + "futures 0.3.13", + "globset", + "hyper 0.14.4", + "jsonrpsee-types", + "lazy_static", + "log 0.4.14", "unicase 2.6.0", - "url 2.2.0", - "webpki", ] [[package]] -name = "jsonrpsee-proc-macros" -version = "1.0.0" -source = "git+https://github.com/interlay/jsonrpsee?rev=5b35d10b5ae45a1776a8dcf761ecbe8d6e288646#5b35d10b5ae45a1776a8dcf761ecbe8d6e288646" +name = "jsonrpsee-ws-client" +version = "0.2.0-alpha.2" +source = "git+https://github.com/interlay/jsonrpsee?rev=1c2ba33#1c2ba33e7d9187d687c9ee5ff219108b23fdc1a2" dependencies = [ - "Inflector", - "proc-macro2", - "quote", - "syn", + "async-std", + "async-tls", + "async-trait", + "fnv", + "futures 0.3.13", + "jsonrpsee-types", + "log 0.4.14", + "pin-project 1.0.5", + "serde", + "serde_json", + "soketto", + "thiserror", + "url 2.2.1", + "webpki", ] [[package]] @@ -3634,9 +3681,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.86" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6" [[package]] name = "libloading" @@ -3656,16 +3703,15 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.34.0" +version = "0.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5133112ce42be9482f6a87be92a605dd6bbc9e93c297aee77d172ff06908f3a" +checksum = "adc225a49973cf9ab10d0cdd6a4b8f0cda299df9b760824bbb623f15f8f0c95a" dependencies = [ "atomic", "bytes 1.0.1", - "futures 0.3.12", + "futures 0.3.13", "lazy_static", "libp2p-core", - "libp2p-core-derive", "libp2p-deflate", "libp2p-dns", "libp2p-floodsub", @@ -3680,6 +3726,7 @@ dependencies = [ "libp2p-pnet", "libp2p-request-response", "libp2p-swarm", + "libp2p-swarm-derive", "libp2p-tcp", "libp2p-uds", "libp2p-wasm-ext", @@ -3699,11 +3746,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2d56aadc2c2bf22cd7797f86e56a65b5b3994a0136b65be3106938acae7a26" dependencies = [ "asn1_der", - "bs58 0.4.0", + "bs58", "ed25519-dalek", "either", "fnv", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "lazy_static", "libsecp256k1", @@ -3719,21 +3766,11 @@ dependencies = [ "ring", "rw-stream-sink", "sha2 0.9.3", - "smallvec 1.6.1", - "thiserror", - "unsigned-varint 0.7.0", - "void", - "zeroize", -] - -[[package]] -name = "libp2p-core-derive" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4bc40943156e42138d22ed3c57ff0e1a147237742715937622a99b10fbe0156" -dependencies = [ - "quote", - "syn", + "smallvec 1.6.1", + "thiserror", + "unsigned-varint 0.7.0", + "void", + "zeroize", ] [[package]] @@ -3743,7 +3780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d42eed63305f0420736fa487f9acef720c4528bd7852a6a760f5ccde4813345" dependencies = [ "flate2", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", ] @@ -3753,7 +3790,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5153b6db68fd4baa3b304e377db744dd8fea8ff4e4504509ee636abcde88d3e3" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "log 0.4.14", ] @@ -3766,7 +3803,7 @@ checksum = "b3c63dfa06581b24b1d12bf9815b43689a784424be217d6545c800c7c75a207f" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3778,16 +3815,16 @@ dependencies = [ [[package]] name = "libp2p-gossipsub" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12451ba9493e87c91baf2a6dffce9ddf1fbc807a0861532d7cf477954f8ebbee" +checksum = "502dc5fcbfec4aa1c63ef3f7307ffe20e90c1a1387bf23ed0bec087f2dde58a1" dependencies = [ - "asynchronous-codec 0.5.0", + "asynchronous-codec 0.6.0", "base64 0.13.0", "byteorder", "bytes 1.0.1", "fnv", - "futures 0.3.12", + "futures 0.3.13", "hex_fmt", "libp2p-core", "libp2p-swarm", @@ -3798,7 +3835,7 @@ dependencies = [ "regex", "sha2 0.9.3", "smallvec 1.6.1", - "unsigned-varint 0.6.0", + "unsigned-varint 0.7.0", "wasm-timer", ] @@ -3808,7 +3845,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40fb36a059b7a8cce1514bd8b546fa612e006c9937caa7f5950cb20021fe91e" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3829,7 +3866,7 @@ dependencies = [ "bytes 1.0.1", "either", "fnv", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3838,7 +3875,7 @@ dependencies = [ "rand 0.7.3", "sha2 0.9.3", "smallvec 1.6.1", - "uint 0.9.0", + "uint", "unsigned-varint 0.7.0", "void", "wasm-timer", @@ -3853,7 +3890,7 @@ dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.12", + "futures 0.3.13", "if-watch", "lazy_static", "libp2p-core", @@ -3873,7 +3910,7 @@ checksum = "350ce8b3923594aedabd5d6e3f875d058435052a29c3f32df378bc70d10be464" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.0.1", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "log 0.4.14", "nohash-hasher", @@ -3891,7 +3928,7 @@ checksum = "4aca322b52a0c5136142a7c3971446fb1e9964923a526c9cc6ef3b7c94e57778" dependencies = [ "bytes 1.0.1", "curve25519-dalek 3.0.2", - "futures 0.3.12", + "futures 0.3.13", "lazy_static", "libp2p-core", "log 0.4.14", @@ -3911,7 +3948,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f3813276d0708c8db0f500d8beda1bda9ad955723b9cb272c41f4727256f73c" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3928,7 +3965,7 @@ checksum = "9d58defcadb646ae4b033e130b48d87410bf76394dc3335496cae99dac803e61" dependencies = [ "asynchronous-codec 0.6.0", "bytes 1.0.1", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "log 0.4.14", "prost", @@ -3943,7 +3980,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce3374f3b28162db9d3442c9347c4f14cb01e8290052615c7d341d40eae0599" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", "pin-project 1.0.5", "rand 0.7.3", @@ -3959,7 +3996,7 @@ checksum = "10e5552827c33d8326502682da73a0ba4bfa40c1b55b216af3c303f32169dd89" dependencies = [ "async-trait", "bytes 1.0.1", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "libp2p-swarm", "log 0.4.14", @@ -3978,7 +4015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7955b973e1fd2bd61ffd43ce261c1223f61f4aacd5bae362a924993f9a25fd98" dependencies = [ "either", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "log 0.4.14", "rand 0.7.3", @@ -3987,6 +4024,16 @@ dependencies = [ "wasm-timer", ] +[[package]] +name = "libp2p-swarm-derive" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c564ebaa36a64839f51eaddb0243aaaa29ce64affb56129193cc3248b72af273" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "libp2p-tcp" version = "0.27.1" @@ -3994,7 +4041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88a5aef80e519a6cb8e2663605142f97baaaea1a252eecbf8756184765f7471b" dependencies = [ "async-io", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "if-watch", "ipnet", @@ -4011,7 +4058,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80ac51ce419f60be966e02103c17f67ff5dc4422ba83ba54d251d6c62a4ed487" dependencies = [ "async-std", - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "log 0.4.14", ] @@ -4022,7 +4069,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6149c46cb76935c80bc8be6ec6e3ebd5f5e1679765a255fb34331d54610f15dd" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -4037,15 +4084,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3b1c6a3431045da8b925ed83384e4c5163e14b990572307fca9c507435d4d22" dependencies = [ "either", - "futures 0.3.12", + "futures 0.3.13", "futures-rustls", "libp2p-core", "log 0.4.14", "quicksink", "rw-stream-sink", - "soketto 0.4.2", - "url 2.2.0", - "webpki-roots 0.21.0", + "soketto", + "url 2.2.1", + "webpki-roots", ] [[package]] @@ -4054,7 +4101,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4819358c542a86ff95f6ae691efb4b94ddaf477079b01a686f5705b79bfc232a" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "libp2p-core", "parking_lot 0.11.1", "thiserror", @@ -4168,7 +4215,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f374d42cdfc1d7dbf3d3dec28afab2eb97ffbf43a3234d795b5986dbf4b90ba" dependencies = [ - "hashbrown 0.9.1", + "hashbrown", ] [[package]] @@ -4256,7 +4303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "814bbecfc0451fc314eeea34f05bbcd5b98a7ad7af37faee088b86a1e633f1d4" dependencies = [ "hash-db", - "hashbrown 0.9.1", + "hashbrown", "parity-util-mem", ] @@ -4305,18 +4352,18 @@ dependencies = [ [[package]] name = "minicbor" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3265a9f5210bb726f81ef9c456ae0aff5321cd95748c0e71889b0e19d8f0332b" +checksum = "1c2b2c73f9640fccab53947e2b3474d5071fcbc8f82cac51ddf6c8041a30a9ea" dependencies = [ "minicbor-derive", ] [[package]] name = "minicbor-derive" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130b9455e28a3f308f6579671816a6f2621e2e0cbf55dc2f886345bef699481e" +checksum = "19ce18b5423c573a13e80cb3046ea0af6379ef725dc3af4886bdb8f4e5093068" dependencies = [ "proc-macro2", "quote", @@ -4325,9 +4372,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg 1.0.1", @@ -4352,6 +4399,19 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2182a122f3b7f3f5329cb1972cee089ba2459a0a80a56935e6e674f096f8d839" +dependencies = [ + "libc", + "log 0.4.14", + "miow 0.3.6", + "ntapi", + "winapi 0.3.9", +] + [[package]] name = "mio-extras" version = "2.0.6" @@ -4360,7 +4420,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ "lazycell", "log 0.4.14", - "mio", + "mio 0.6.23", "slab", ] @@ -4371,7 +4431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log 0.4.14", - "mio", + "mio 0.6.23", "miow 0.3.6", "winapi 0.3.9", ] @@ -4384,7 +4444,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio", + "mio 0.6.23", ] [[package]] @@ -4439,13 +4499,13 @@ dependencies = [ [[package]] name = "module-exchange-rate-oracle-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-exchange-rate-oracle-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4455,10 +4515,10 @@ dependencies = [ [[package]] name = "module-exchange-rate-oracle-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-std", @@ -4467,13 +4527,13 @@ dependencies = [ [[package]] name = "module-issue-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-issue-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4483,10 +4543,10 @@ dependencies = [ [[package]] name = "module-issue-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4494,13 +4554,13 @@ dependencies = [ [[package]] name = "module-redeem-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-redeem-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4510,10 +4570,10 @@ dependencies = [ [[package]] name = "module-redeem-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4521,13 +4581,13 @@ dependencies = [ [[package]] name = "module-refund-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-refund-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4537,10 +4597,10 @@ dependencies = [ [[package]] name = "module-refund-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4548,13 +4608,13 @@ dependencies = [ [[package]] name = "module-replace-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-replace-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4564,10 +4624,10 @@ dependencies = [ [[package]] name = "module-replace-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4575,14 +4635,14 @@ dependencies = [ [[package]] name = "module-sla-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-exchange-rate-oracle-rpc-runtime-api", "module-sla-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4592,11 +4652,11 @@ dependencies = [ [[package]] name = "module-sla-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", "module-exchange-rate-oracle-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4604,13 +4664,13 @@ dependencies = [ [[package]] name = "module-staked-relayers-rpc" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-staked-relayers-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4620,10 +4680,10 @@ dependencies = [ [[package]] name = "module-staked-relayers-rpc-runtime-api" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4631,14 +4691,14 @@ dependencies = [ [[package]] name = "module-vault-registry-rpc" version = "0.3.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "module-exchange-rate-oracle-rpc-runtime-api", "module-vault-registry-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -4648,11 +4708,11 @@ dependencies = [ [[package]] name = "module-vault-registry-rpc-runtime-api" version = "0.3.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", "module-exchange-rate-oracle-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -4707,18 +4767,18 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df70763c86c98487451f307e1b68b4100da9076f4c12146905fc2054277f4e8" +checksum = "7d91ec0a2440aaff5f78ec35631a7027d50386c6163aa975f7caa0d5da4b6ff8" dependencies = [ "bytes 1.0.1", - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", "pin-project 1.0.5", "smallvec 1.6.1", @@ -4732,7 +4792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b6147c3d50b4f3cdabfe2ecc94a0191fd3d6ad58aefd9664cf396285883486" dependencies = [ "approx", - "generic-array 0.13.2", + "generic-array 0.13.3", "matrixmultiply", "num-complex", "num-rational", @@ -4765,8 +4825,8 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.0.0", - "security-framework-sys 2.0.0", + "security-framework 2.1.2", + "security-framework-sys 2.1.1", "tempfile", ] @@ -4793,9 +4853,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" dependencies = [ "bitflags", "cc", @@ -4822,7 +4882,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ "memchr", - "version_check 0.9.2", + "version_check 0.9.3", ] [[package]] @@ -4831,6 +4891,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "num" version = "0.2.1" @@ -4948,9 +5017,9 @@ checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" -version = "1.5.2" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" dependencies = [ "parking_lot 0.11.1", ] @@ -4969,15 +5038,15 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.32" +version = "0.10.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", "openssl-sys", ] @@ -4989,9 +5058,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.60" +version = "0.9.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" dependencies = [ "autocfg 1.0.1", "cc", @@ -5002,7 +5071,7 @@ dependencies = [ [[package]] name = "oracle" -version = "0.2.2" +version = "0.5.0" dependencies = [ "chrono", "clap 3.0.0-beta.2", @@ -5010,7 +5079,6 @@ dependencies = [ "log 0.4.14", "reqwest", "runtime", - "sp-keyring", "thiserror", "tokio 0.2.25", ] @@ -5033,13 +5101,13 @@ dependencies = [ [[package]] name = "pallet-aura" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", "pallet-session", "pallet-timestamp", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-application-crypto", "sp-consensus-aura", @@ -5051,12 +5119,12 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-application-crypto", "sp-authority-discovery", @@ -5067,12 +5135,12 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-authorship", "sp-inherents", "sp-runtime", @@ -5082,15 +5150,16 @@ dependencies = [ [[package]] name = "pallet-babe" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log 0.4.14", "pallet-authorship", "pallet-session", "pallet-timestamp", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-application-crypto", "sp-consensus-babe", @@ -5106,12 +5175,13 @@ dependencies = [ [[package]] name = "pallet-balances" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "serde", "sp-runtime", "sp-std", @@ -5120,11 +5190,12 @@ dependencies = [ [[package]] name = "pallet-collective" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -5135,14 +5206,15 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log 0.4.14", "pallet-authorship", "pallet-session", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-application-crypto", "sp-core", @@ -5156,12 +5228,13 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", + "log 0.4.14", "pallet-authorship", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-application-crypto", "sp-core", @@ -5174,11 +5247,11 @@ dependencies = [ [[package]] name = "pallet-indices" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -5190,12 +5263,13 @@ dependencies = [ [[package]] name = "pallet-offences" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", + "log 0.4.14", "pallet-balances", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-runtime", "sp-staking", @@ -5205,11 +5279,11 @@ dependencies = [ [[package]] name = "pallet-randomness-collective-flip" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "safe-mix", "sp-runtime", "sp-std", @@ -5218,13 +5292,13 @@ dependencies = [ [[package]] name = "pallet-session" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", "pallet-timestamp", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -5238,11 +5312,11 @@ dependencies = [ [[package]] name = "pallet-society" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "rand_chacha 0.2.2", "serde", "sp-runtime", @@ -5252,15 +5326,17 @@ dependencies = [ [[package]] name = "pallet-staking" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", + "log 0.4.14", "pallet-authorship", "pallet-session", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-application-crypto", + "sp-election-providers", "sp-io", "sp-npos-elections", "sp-runtime", @@ -5272,7 +5348,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5283,11 +5359,11 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-io", "sp-runtime", @@ -5297,13 +5373,14 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "serde", "sp-inherents", "sp-runtime", @@ -5314,11 +5391,11 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "smallvec 1.6.1", "sp-core", @@ -5330,13 +5407,13 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-blockchain", "sp-core", @@ -5347,10 +5424,10 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "pallet-transaction-payment", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-runtime", ] @@ -5358,13 +5435,13 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", "pallet-balances", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-runtime", "sp-std", ] @@ -5372,12 +5449,12 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "enumflags2", "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-runtime", "sp-std", @@ -5386,44 +5463,44 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", ] [[package]] name = "parachain-tokens" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "collateral", "cumulus-primitives-core", "frame-support", "frame-system", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-arithmetic", "sp-runtime", "sp-std", "treasury", - "util", "xcm", "xcm-executor", ] [[package]] name = "parity-db" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111e193c96758d476d272093a853882668da17489f76bf4361b8decae0b6c515" +checksum = "495197c078e54b8735181aa35c00a327f7f3a3cc00a1ee8c95926dd010f0ec6b" dependencies = [ "blake2-rfc", "crc32fast", - "hex 0.4.2", + "fs2", + "hex 0.4.3", "libc", "log 0.4.14", "memmap2", @@ -5438,7 +5515,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c6805f98667a3828afb2ec2c396a8d610497e8d546f5447188aae47c5a79ec" dependencies = [ "arrayref", - "bs58 0.4.0", + "bs58", "byteorder", "data-encoding", "multihash", @@ -5446,37 +5523,27 @@ dependencies = [ "serde", "static_assertions", "unsigned-varint 0.7.0", - "url 2.2.0", -] - -[[package]] -name = "parity-scale-codec" -version = "1.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79602888a81ace83e3d1d4b2873286c1f5f906c84db667594e8db8da3506c383" -dependencies = [ - "arrayvec 0.5.2", - "byte-slice-cast 0.3.5", + "url 2.2.1", ] [[package]] name = "parity-scale-codec" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c823fdae1bb5ff5708ee61a62697e6296175dc671710876871c853f48592b3" +checksum = "0cd3dab59b5cf4bc81069ade0fc470341a1ef3ad5fa73e5a8943bed2ec12b2e8" dependencies = [ "arrayvec 0.5.2", "bitvec", - "byte-slice-cast 1.0.0", + "byte-slice-cast", "parity-scale-codec-derive", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9029e65297c7fd6d7013f0579e193ec2b34ae78eabca854c9417504ad8a2d214" +checksum = "fa04976a81fde04924b40cc4036c4d12841e8bb04325a5cf2ada75731a150a7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5497,7 +5564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e57fea504fea33f9fbb5f49f378359030e7e026a6ab849bb9e8f0787376f1bf" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "libc", "log 0.4.14", "mio-named-pipes", @@ -5517,12 +5584,12 @@ checksum = "664a8c6b8e62d8f9f2f937e391982eb433ab285b4cd9545b342441e04a906e42" dependencies = [ "cfg-if 1.0.0", "ethereum-types", - "hashbrown 0.9.1", + "hashbrown", "impl-trait-for-tuples", "lru", "parity-util-mem-derive", "parking_lot 0.11.1", - "primitive-types 0.9.0", + "primitive-types", "smallvec 1.6.1", "winapi 0.3.9", ] @@ -5563,12 +5630,12 @@ dependencies = [ "bytes 0.4.12", "httparse", "log 0.4.14", - "mio", + "mio 0.6.23", "mio-extras", "rand 0.7.3", "sha-1 0.8.2", "slab", - "url 2.2.0", + "url 2.2.1", ] [[package]] @@ -5664,9 +5731,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" [[package]] name = "paste-impl" @@ -5815,15 +5882,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" [[package]] name = "pin-utils" @@ -5846,9 +5913,9 @@ checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" [[package]] name = "polkadot-core-primitives" version = "0.7.30" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "sp-core", "sp-runtime", @@ -5857,14 +5924,14 @@ dependencies = [ [[package]] name = "polkadot-parachain" -version = "0.8.28" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +version = "0.8.29" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "derive_more", - "futures 0.3.12", + "futures 0.3.13", "libc", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", "polkadot-core-primitives", @@ -5884,13 +5951,13 @@ dependencies = [ [[package]] name = "polkadot-primitives" -version = "0.8.28" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +version = "0.8.29" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "bitvec", "frame-system", "hex-literal 0.3.1", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "polkadot-core-primitives", "polkadot-parachain", @@ -5912,8 +5979,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" -version = "0.8.28" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +version = "0.8.29" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "bitvec", "frame-support", @@ -5928,7 +5995,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-parachains", "rustc-hex", @@ -5949,7 +6016,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.8.0" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "bitvec", "derive_more", @@ -5964,7 +6031,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "pallet-vesting", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-primitives", "rand 0.8.3", "rand_chacha 0.3.0", @@ -6052,17 +6119,6 @@ dependencies = [ "treeline", ] -[[package]] -name = "primitive-types" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd39dcacf71411ba488570da7bbc89b717225e46478b30ba99b92db6b149809" -dependencies = [ - "fixed-hash 0.6.1", - "impl-codec 0.4.2", - "uint 0.8.5", -] - [[package]] name = "primitive-types" version = "0.9.0" @@ -6070,10 +6126,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2415937401cb030a2a0a4d922483f945fa068f52a7dbb22ce0fe5f2b6f6adace" dependencies = [ "fixed-hash 0.7.0", - "impl-codec 0.5.0", + "impl-codec", "impl-rlp", "impl-serde", - "uint 0.9.0", + "uint", ] [[package]] @@ -6095,7 +6151,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "version_check 0.9.2", + "version_check 0.9.3", ] [[package]] @@ -6106,7 +6162,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check 0.9.2", + "version_check 0.9.3", ] [[package]] @@ -6235,7 +6291,7 @@ checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" dependencies = [ "futures-core", "futures-sink", - "pin-project-lite 0.1.11", + "pin-project-lite 0.1.12", ] [[package]] @@ -6532,7 +6588,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque 0.8.0", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", "lazy_static", "num_cpus", ] @@ -6549,9 +6605,9 @@ dependencies = [ [[package]] name = "redeem" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "btc-relay", "collateral", "exchange-rate-oracle", @@ -6561,8 +6617,8 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-timestamp", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "security", "serde", "sha2 0.8.2", @@ -6573,7 +6629,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", "vault-registry", ] @@ -6636,9 +6691,9 @@ dependencies = [ [[package]] name = "refund" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "btc-relay", "collateral", "exchange-rate-oracle", @@ -6648,8 +6703,8 @@ dependencies = [ "pallet-balances", "pallet-randomness-collective-flip", "pallet-timestamp", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "redeem", "security", "serde", @@ -6661,7 +6716,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", "vault-registry", ] @@ -6678,14 +6732,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.3" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] @@ -6700,9 +6753,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "region" @@ -6716,26 +6769,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "relayer-core" -version = "0.3.0" -source = "git+https://gitlab.com/interlay/relayer-core?rev=49deea6c1219d3a0e682e35444a08055a238fed7#49deea6c1219d3a0e682e35444a08055a238fed7" -dependencies = [ - "hex 0.4.2", - "log 0.4.14", - "thiserror", -] - -[[package]] -name = "relayer-core" -version = "0.3.0" -source = "git+https://gitlab.com/interlay/relayer-core?rev=7a99a32e#7a99a32ea03f4308d41ed66f277f20a4cca8270c" -dependencies = [ - "hex 0.4.2", - "log 0.4.14", - "thiserror", -] - [[package]] name = "remove_dir_all" version = "0.5.3" @@ -6748,9 +6781,9 @@ dependencies = [ [[package]] name = "replace" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "btc-relay", "collateral", "exchange-rate-oracle", @@ -6760,8 +6793,8 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-timestamp", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "security", "serde", "sha2 0.8.2", @@ -6772,7 +6805,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", "vault-registry", ] @@ -6799,13 +6831,13 @@ dependencies = [ "mime_guess", "native-tls", "percent-encoding 2.1.0", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", "serde", "serde_json", "serde_urlencoded", "tokio 0.2.25", "tokio-tls", - "url 2.2.0", + "url 2.2.1", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -6855,14 +6887,15 @@ dependencies = [ [[package]] name = "rococo-runtime" -version = "0.8.28" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +version = "0.8.29" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "frame-executive", "frame-support", "frame-system", "frame-system-rpc-runtime-api", "hex-literal 0.3.1", + "log 0.4.14", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", @@ -6878,7 +6911,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -6918,11 +6951,11 @@ dependencies = [ [[package]] name = "runtime" -version = "0.3.0" +version = "0.5.0" dependencies = [ "async-trait", - "bitcoin 0.2.0", "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "btc-parachain", "btc-parachain-service", "btc-relay", @@ -6930,12 +6963,14 @@ dependencies = [ "exchange-rate-oracle", "frame-support", "frame-system", - "futures 0.3.12", + "futures 0.3.13", "issue", - "jsonrpsee", + "jsonrpsee-types", + "jsonrpsee-ws-client", "log 0.4.14", "module-exchange-rate-oracle-rpc-runtime-api", - "parity-scale-codec 2.0.0", + "parity-scale-codec", + "polkadot-parachain", "rand 0.7.3", "redeem", "refund", @@ -6954,7 +6989,9 @@ dependencies = [ "tempdir", "thiserror", "tokio 0.2.25", + "url 2.2.1", "vault-registry", + "xcm", ] [[package]] @@ -6966,7 +7003,7 @@ dependencies = [ "base64 0.13.0", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", ] [[package]] @@ -6996,19 +7033,6 @@ dependencies = [ "semver 0.9.0", ] -[[package]] -name = "rustls" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" -dependencies = [ - "base64 0.10.1", - "log 0.4.14", - "ring", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.18.1" @@ -7047,13 +7071,25 @@ dependencies = [ "security-framework 1.0.0", ] +[[package]] +name = "rustls-native-certs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +dependencies = [ + "openssl-probe", + "rustls 0.19.0", + "schannel", + "security-framework 2.1.2", +] + [[package]] name = "rw-stream-sink" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "pin-project 0.4.27", "static_assertions", ] @@ -7100,12 +7136,12 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -7123,14 +7159,13 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-client-api", "sp-api", "sp-block-builder", "sp-blockchain", - "sp-consensus", "sp-core", "sp-inherents", "sp-runtime", @@ -7140,10 +7175,10 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-chain-spec-derive", "sc-consensus-babe", "sc-consensus-epochs", @@ -7161,7 +7196,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7172,16 +7207,16 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "chrono", "fdlimit", - "futures 0.3.12", - "hex 0.4.2", + "futures 0.3.13", + "hex 0.4.3", "libp2p", "log 0.4.14", "names", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "rand 0.7.3", "regex", "rpassword", @@ -7210,16 +7245,16 @@ dependencies = [ [[package]] name = "sc-client-api" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", "fnv", - "futures 0.3.12", + "futures 0.3.13", "hash-db", "kvdb", "lazy_static", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sc-executor", "sp-api", @@ -7244,7 +7279,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "blake2-rfc", "hash-db", @@ -7254,7 +7289,7 @@ dependencies = [ "linked-hash-map", "log 0.4.14", "parity-db", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", "sc-client-api", @@ -7274,7 +7309,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "sc-client-api", "sp-blockchain", @@ -7285,13 +7320,13 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sc-block-builder", "sc-client-api", @@ -7317,18 +7352,18 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", "fork-tree", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "log 0.4.14", "merlin", "num-bigint", "num-rational", "num-traits", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "pdqselect", "rand 0.7.3", @@ -7363,10 +7398,10 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "fork-tree", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sc-client-api", "sp-blockchain", @@ -7376,12 +7411,12 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sc-client-api", "sc-telemetry", @@ -7402,7 +7437,7 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", "sc-client-api", @@ -7416,13 +7451,13 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", "lazy_static", "libsecp256k1", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-wasm 0.41.0", "parking_lot 0.11.1", "sc-executor-common", @@ -7445,10 +7480,10 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-wasm 0.41.0", "sp-allocator", "sp-core", @@ -7461,10 +7496,10 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-executor-common", "sp-allocator", "sp-core", @@ -7476,10 +7511,10 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-wasm 0.41.0", "pwasm-utils", "sc-executor-common", @@ -7494,17 +7529,17 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", "dyn-clone", "finality-grandpa", "fork-tree", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "linked-hash-map", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "pin-project 1.0.5", "rand 0.7.3", @@ -7533,10 +7568,10 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "ansi_term 0.12.1", - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", "parity-util-mem", "sc-client-api", @@ -7551,13 +7586,13 @@ dependencies = [ [[package]] name = "sc-keystore" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "async-trait", "derive_more", - "futures 0.3.12", + "futures 0.3.13", "futures-util", - "hex 0.4.2", + "hex 0.4.3", "merlin", "parking_lot 0.11.1", "rand 0.7.3", @@ -7571,11 +7606,11 @@ dependencies = [ [[package]] name = "sc-light" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "hash-db", "lazy_static", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sc-client-api", "sc-executor", @@ -7590,13 +7625,13 @@ dependencies = [ [[package]] name = "sc-network" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "async-std", "async-trait", "asynchronous-codec 0.5.0", "bitflags", - "bs58 0.4.0", + "bs58", "bytes 1.0.1", "cid", "derive_more", @@ -7604,9 +7639,9 @@ dependencies = [ "erased-serde", "fnv", "fork-tree", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", - "hex 0.4.2", + "hex 0.4.3", "ip_network", "libp2p", "linked-hash-map", @@ -7614,7 +7649,7 @@ dependencies = [ "log 0.4.14", "lru", "nohash-hasher", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "pin-project 1.0.5", "prost", @@ -7643,9 +7678,9 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "libp2p", "log 0.4.14", @@ -7659,17 +7694,17 @@ dependencies = [ [[package]] name = "sc-offchain" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "bytes 0.5.6", "fnv", - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "hyper 0.13.10", - "hyper-rustls", + "hyper-rustls 0.21.0", "log 0.4.14", "num_cpus", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "rand 0.7.3", "sc-client-api", @@ -7686,9 +7721,9 @@ dependencies = [ [[package]] name = "sc-peerset" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "libp2p", "log 0.4.14", "serde_json", @@ -7699,7 +7734,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", "substrate-prometheus-endpoint", @@ -7708,14 +7743,14 @@ dependencies = [ [[package]] name = "sc-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "hash-db", "jsonrpc-core 15.1.0", "jsonrpc-pubsub 15.1.0", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sc-block-builder", "sc-client-api", @@ -7742,16 +7777,16 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", - "futures 0.3.12", + "futures 0.3.13", "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "jsonrpc-pubsub 15.1.0", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "serde", "serde_json", @@ -7766,9 +7801,9 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "jsonrpc-core 15.1.0", "jsonrpc-http-server 15.1.0", "jsonrpc-ipc-server", @@ -7784,19 +7819,19 @@ dependencies = [ [[package]] name = "sc-service" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "directories", "exit-future", - "futures 0.1.30", - "futures 0.3.12", + "futures 0.1.31", + "futures 0.3.13", "futures-timer 3.0.2", "hash-db", "jsonrpc-core 15.1.0", "jsonrpc-pubsub 15.1.0", "lazy_static", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", "pin-project 1.0.5", @@ -7847,10 +7882,10 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", "parking_lot 0.11.1", @@ -7862,10 +7897,10 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "chrono", - "futures 0.3.12", + "futures 0.3.13", "libp2p", "log 0.4.14", "parking_lot 0.11.1", @@ -7884,7 +7919,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "ansi_term 0.12.1", "atty", @@ -7912,7 +7947,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7923,10 +7958,10 @@ dependencies = [ [[package]] name = "sc-transaction-graph" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", - "futures 0.3.12", + "futures 0.3.13", "linked-hash-map", "log 0.4.14", "parity-util-mem", @@ -7945,13 +7980,13 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-diagnose", "intervalier", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", "sc-client-api", @@ -8069,12 +8104,12 @@ dependencies = [ [[package]] name = "security" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "serde", "sha2 0.8.2", "sp-core", @@ -8096,15 +8131,15 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.0.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +checksum = "d493c5f39e02dfb062cd8f33301f90f9b13b650e8c1b1d0fd75c19dd64bff69d" dependencies = [ "bitflags", "core-foundation 0.9.1", "core-foundation-sys 0.8.2", "libc", - "security-framework-sys 2.0.0", + "security-framework-sys 2.1.1", ] [[package]] @@ -8119,9 +8154,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +checksum = "dee48cdde5ed250b0d3252818f646e174ab414036edb884dde62d80a3ac6082d" dependencies = [ "core-foundation-sys 0.8.2", "libc", @@ -8172,18 +8207,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.123" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" dependencies = [ "proc-macro2", "quote", @@ -8192,9 +8227,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.62" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -8238,12 +8273,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - [[package]] name = "sha2" version = "0.8.2" @@ -8312,9 +8341,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "signal-hook" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f5e3fe0c66f67197236097d89de1e86216f1f6fdeaf47c442f854ab46c240" +checksum = "6aa894ef3fade0ee7243422f4fbbd6c2b48e6de767e621d37ef65f2310f53cea" dependencies = [ "libc", "signal-hook-registry", @@ -8350,7 +8379,7 @@ dependencies = [ [[package]] name = "sla" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "collateral", "exchange-rate-oracle", @@ -8358,7 +8387,7 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-timestamp", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "security", "serde", "sp-arithmetic", @@ -8383,8 +8412,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d0132f3e393bcb7390c60bb45769498cf4550bcb7a21d7f95c02b69f6362cdc" dependencies = [ "crc32fast", - "crossbeam-epoch 0.9.1", - "crossbeam-utils 0.8.1", + "crossbeam-epoch 0.9.3", + "crossbeam-utils 0.8.3", "fs2", "fxhash", "libc", @@ -8436,25 +8465,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "soketto" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9dab3f95c9ebdf3a88268c19af668f637a3c5039c2c56ff2d40b1b2d64a25b" -dependencies = [ - "base64 0.11.0", - "bytes 0.5.6", - "futures 0.3.12", - "http 0.2.3", - "httparse", - "log 0.4.14", - "rand 0.7.3", - "sha1", - "smallvec 1.6.1", - "static_assertions", - "thiserror", -] - [[package]] name = "soketto" version = "0.4.2" @@ -8464,7 +8474,7 @@ dependencies = [ "base64 0.12.3", "bytes 0.5.6", "flate2", - "futures 0.3.12", + "futures 0.3.13", "httparse", "log 0.4.14", "rand 0.7.3", @@ -8474,7 +8484,7 @@ dependencies = [ [[package]] name = "sp-allocator" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", "sp-core", @@ -8486,10 +8496,11 @@ dependencies = [ [[package]] name = "sp-api" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "hash-db", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "sp-api-proc-macro", "sp-core", "sp-runtime", @@ -8502,7 +8513,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "blake2-rfc", "proc-macro-crate", @@ -8514,9 +8525,9 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -8526,11 +8537,11 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "integer-sqrt", "num-traits", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-debug-derive", "sp-std", @@ -8539,9 +8550,9 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-application-crypto", "sp-runtime", @@ -8551,9 +8562,9 @@ dependencies = [ [[package]] name = "sp-authorship" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-inherents", "sp-runtime", "sp-std", @@ -8562,9 +8573,9 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-inherents", "sp-runtime", @@ -8574,12 +8585,12 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", "lru", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sp-api", "sp-consensus", @@ -8592,7 +8603,7 @@ dependencies = [ [[package]] name = "sp-chain-spec" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "serde", "serde_json", @@ -8601,13 +8612,13 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-timer 3.0.2", "libp2p", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "serde", "sp-api", @@ -8627,9 +8638,9 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-application-crypto", "sp-consensus-slots", @@ -8642,10 +8653,10 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "merlin", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-application-crypto", "sp-consensus", @@ -8662,9 +8673,9 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-arithmetic", "sp-runtime", ] @@ -8672,9 +8683,9 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "schnorrkel", "sp-core", "sp-runtime", @@ -8684,27 +8695,27 @@ dependencies = [ [[package]] name = "sp-core" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "base58", "blake2-rfc", "byteorder", "dyn-clonable", "ed25519-dalek", - "futures 0.3.12", + "futures 0.3.13", "hash-db", "hash256-std-hasher", - "hex 0.4.2", + "hex 0.4.3", "impl-serde", "lazy_static", "libsecp256k1", "log 0.4.14", "merlin", "num-traits", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", - "primitive-types 0.9.0", + "primitive-types", "rand 0.7.3", "regex", "schnorrkel", @@ -8728,7 +8739,7 @@ dependencies = [ [[package]] name = "sp-database" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "kvdb", "parking_lot 0.11.1", @@ -8737,20 +8748,31 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "sp-election-providers" +version = "3.0.0" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" +dependencies = [ + "parity-scale-codec", + "sp-arithmetic", + "sp-npos-elections", + "sp-std", +] + [[package]] name = "sp-externalities" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "environmental", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-std", "sp-storage", ] @@ -8758,11 +8780,11 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "finality-grandpa", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-application-crypto", @@ -8775,9 +8797,9 @@ dependencies = [ [[package]] name = "sp-inherents" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sp-core", "sp-std", @@ -8787,13 +8809,13 @@ dependencies = [ [[package]] name = "sp-io" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "hash-db", "libsecp256k1", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "sp-core", "sp-externalities", @@ -8811,7 +8833,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "lazy_static", "sp-core", @@ -8822,13 +8844,13 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "async-trait", "derive_more", - "futures 0.3.12", + "futures 0.3.13", "merlin", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "schnorrkel", "serde", @@ -8839,9 +8861,9 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-arithmetic", "sp-core", @@ -8852,7 +8874,7 @@ dependencies = [ [[package]] name = "sp-npos-elections-compact" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8863,7 +8885,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "sp-api", "sp-core", @@ -8873,7 +8895,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "backtrace", ] @@ -8881,7 +8903,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "serde", "sp-core", @@ -8890,15 +8912,15 @@ dependencies = [ [[package]] name = "sp-runtime" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "either", "hash256-std-hasher", "impl-trait-for-tuples", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parity-util-mem", - "paste 1.0.4", + "paste 1.0.5", "rand 0.7.3", "serde", "sp-application-crypto", @@ -8911,11 +8933,11 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "sp-externalities", "sp-runtime-interface-proc-macro", "sp-std", @@ -8928,7 +8950,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "Inflector", "proc-macro-crate", @@ -8940,7 +8962,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "serde", "serde_json", @@ -8949,9 +8971,9 @@ dependencies = [ [[package]] name = "sp-session" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-core", "sp-runtime", @@ -8962,9 +8984,9 @@ dependencies = [ [[package]] name = "sp-staking" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-runtime", "sp-std", ] @@ -8972,12 +8994,12 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "hash-db", "log 0.4.14", "num-traits", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "parking_lot 0.11.1", "rand 0.7.3", "smallvec 1.6.1", @@ -8994,15 +9016,15 @@ dependencies = [ [[package]] name = "sp-std" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" [[package]] name = "sp-storage" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "impl-serde", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "ref-cast", "serde", "sp-debug-derive", @@ -9012,7 +9034,7 @@ dependencies = [ [[package]] name = "sp-tasks" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", "sp-core", @@ -9025,10 +9047,10 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-api", "sp-inherents", "sp-runtime", @@ -9039,10 +9061,10 @@ dependencies = [ [[package]] name = "sp-tracing" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-std", "tracing", "tracing-core", @@ -9052,12 +9074,12 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "derive_more", - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -9068,11 +9090,11 @@ dependencies = [ [[package]] name = "sp-trie" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "hash-db", "memory-db", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-core", "sp-std", "trie-db", @@ -9082,9 +9104,9 @@ dependencies = [ [[package]] name = "sp-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "futures-core", "futures-timer 3.0.2", "lazy_static", @@ -9094,10 +9116,10 @@ dependencies = [ [[package]] name = "sp-version" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "impl-serde", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "sp-runtime", "sp-std", @@ -9106,10 +9128,10 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sp-std", "wasmi", ] @@ -9134,26 +9156,21 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "staked-relayer" -version = "0.2.0" +version = "0.5.0" dependencies = [ "async-trait", "backoff", - "bitcoin 0.2.0", + "bitcoin 0.5.0", "clap 3.0.0-beta.2", "env_logger 0.7.1", - "frame-system", - "futures 0.3.12", - "hex 0.4.2", - "jsonrpc-core-client 16.0.0", - "jsonrpc-http-server 16.0.0", - "jsonrpsee", + "futures 0.3.13", + "hex 0.4.3", + "jsonrpc-core-client 17.0.0", + "jsonrpc-http-server 17.0.0", "log 0.4.14", "mockall", - "parity-scale-codec 2.0.0", - "rand 0.7.3", - "relayer-core 0.3.0 (git+https://gitlab.com/interlay/relayer-core?rev=7a99a32e)", + "parity-scale-codec", "runtime", - "schnorrkel", "serde", "sp-core", "sp-keyring", @@ -9164,9 +9181,9 @@ dependencies = [ [[package]] name = "staked-relayers" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "btc-relay", "collateral", "exchange-rate-oracle", @@ -9174,9 +9191,9 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex 0.4.2", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "hex 0.4.3", + "parity-scale-codec", + "primitive-types", "redeem", "refund", "replace", @@ -9190,7 +9207,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", "vault-registry", ] @@ -9310,15 +9326,15 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.12", + "futures 0.3.13", "jsonrpc-core 15.1.0", "jsonrpc-core-client 15.1.0", "jsonrpc-derive", "log 0.4.14", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "sc-client-api", "sc-rpc-api", "serde", @@ -9333,7 +9349,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#743accbe3256de2fc615adcaa3ab03ebdbbb4dbd" +source = "git+https://github.com/paritytech/substrate?branch=rococo-v1#645299e8b23ec5fa52935b1a6edbf36886e80141" dependencies = [ "async-std", "derive_more", @@ -9347,20 +9363,22 @@ dependencies = [ [[package]] name = "substrate-subxt" version = "0.14.0" -source = "git+https://github.com/interlay/substrate-subxt?rev=9ef6ed9#9ef6ed9116c2e4d45df70c1c6c41210b891ced68" +source = "git+https://github.com/interlay/substrate-subxt?rev=0283aa0#0283aa0845792e3b951c39bcc67c19d83cc12a67" dependencies = [ "dyn-clone", "frame-metadata", "frame-support", "funty", - "futures 0.3.12", - "hex 0.4.2", - "jsonrpsee", + "futures 0.3.13", + "hex 0.4.3", + "jsonrpsee-http-client", + "jsonrpsee-types", + "jsonrpsee-ws-client", "log 0.4.14", "num-traits", "pallet-indices", "pallet-staking", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "serde", "serde_json", "sp-application-crypto", @@ -9369,20 +9387,22 @@ dependencies = [ "sp-runtime", "sp-std", "sp-version", + "substrate-subxt-client", "substrate-subxt-proc-macro", "thiserror", - "url 2.2.0", + "url 2.2.1", ] [[package]] name = "substrate-subxt-client" version = "0.6.0" -source = "git+https://github.com/interlay/substrate-subxt?rev=9ef6ed9#9ef6ed9116c2e4d45df70c1c6c41210b891ced68" +source = "git+https://github.com/interlay/substrate-subxt?rev=0283aa0#0283aa0845792e3b951c39bcc67c19d83cc12a67" dependencies = [ "async-std", - "futures 0.1.30", - "futures 0.3.12", - "jsonrpsee", + "futures 0.1.31", + "futures 0.3.13", + "jsonrpsee-types", + "jsonrpsee-ws-client", "log 0.4.14", "sc-client-db", "sc-network", @@ -9395,7 +9415,7 @@ dependencies = [ [[package]] name = "substrate-subxt-proc-macro" version = "0.14.0" -source = "git+https://github.com/interlay/substrate-subxt?rev=9ef6ed9#9ef6ed9116c2e4d45df70c1c6c41210b891ced68" +source = "git+https://github.com/interlay/substrate-subxt?rev=0283aa0#0283aa0845792e3b951c39bcc67c19d83cc12a67" dependencies = [ "heck", "proc-macro-crate", @@ -9436,9 +9456,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" dependencies = [ "proc-macro2", "quote", @@ -9510,18 +9530,16 @@ dependencies = [ [[package]] name = "testdata-gen" -version = "0.1.0" +version = "0.5.0" dependencies = [ - "bitcoin 0.2.0", + "bitcoin 0.5.0", "clap 3.0.0-beta.2", "env_logger 0.7.1", - "frame-system", - "hex 0.4.2", - "jsonrpc-core 16.0.0", + "futures 0.3.13", + "hex 0.4.3", + "jsonrpc-core 17.0.0", "log 0.4.14", - "parity-scale-codec 2.0.0", - "primitive-types 0.7.3", - "relayer-core 0.3.0 (git+https://gitlab.com/interlay/relayer-core?rev=49deea6c1219d3a0e682e35444a08055a238fed7)", + "parity-scale-codec", "reqwest", "runtime", "serde", @@ -9552,18 +9570,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", @@ -9648,8 +9666,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", - "mio", + "futures 0.1.31", + "mio 0.6.23", "num_cpus", "tokio-codec", "tokio-current-thread", @@ -9678,17 +9696,31 @@ dependencies = [ "lazy_static", "libc", "memchr", - "mio", + "mio 0.6.23", "mio-named-pipes", "mio-uds", "num_cpus", - "pin-project-lite 0.1.11", + "pin-project-lite 0.1.12", "signal-hook-registry", "slab", "tokio-macros", "winapi 0.3.9", ] +[[package]] +name = "tokio" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d56477f6ed99e10225f38f9f75f872f29b8b8bd8c0b946f63345bb144e9eeda" +dependencies = [ + "autocfg 1.0.1", + "bytes 1.0.1", + "libc", + "memchr", + "mio 0.7.10", + "pin-project-lite 0.2.6", +] + [[package]] name = "tokio-buf" version = "0.1.1" @@ -9697,7 +9729,7 @@ checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ "bytes 0.4.12", "either", - "futures 0.1.30", + "futures 0.1.31", ] [[package]] @@ -9707,7 +9739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "tokio-io", ] @@ -9717,7 +9749,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "tokio-executor", ] @@ -9728,7 +9760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" dependencies = [ "crossbeam-utils 0.7.2", - "futures 0.1.30", + "futures 0.1.31", ] [[package]] @@ -9737,7 +9769,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "tokio-io", "tokio-threadpool", ] @@ -9749,7 +9781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "log 0.4.14", ] @@ -9771,8 +9803,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d282d483052288b2308ba5ee795f5673b159c9bdf63c385a05609da782a5eae" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", - "mio", + "futures 0.1.31", + "mio 0.6.23", "mio-named-pipes", "tokio 0.1.22", ] @@ -9784,10 +9816,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" dependencies = [ "crossbeam-utils 0.7.2", - "futures 0.1.30", + "futures 0.1.31", "lazy_static", "log 0.4.14", - "mio", + "mio 0.6.23", "num_cpus", "parking_lot 0.9.0", "slab", @@ -9808,13 +9840,24 @@ dependencies = [ "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls 0.19.0", + "tokio 1.3.0", + "webpki", +] + [[package]] name = "tokio-service" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", ] [[package]] @@ -9824,7 +9867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" dependencies = [ "fnv", - "futures 0.1.30", + "futures 0.1.31", ] [[package]] @@ -9834,9 +9877,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "iovec", - "mio", + "mio 0.6.23", "tokio-io", "tokio-reactor", ] @@ -9850,7 +9893,7 @@ dependencies = [ "crossbeam-deque 0.7.3", "crossbeam-queue", "crossbeam-utils 0.7.2", - "futures 0.1.30", + "futures 0.1.31", "lazy_static", "log 0.4.14", "num_cpus", @@ -9865,7 +9908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ "crossbeam-utils 0.7.2", - "futures 0.1.30", + "futures 0.1.31", "slab", "tokio-executor", ] @@ -9887,9 +9930,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "log 0.4.14", - "mio", + "mio 0.6.23", "tokio-codec", "tokio-io", "tokio-reactor", @@ -9902,11 +9945,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" dependencies = [ "bytes 0.4.12", - "futures 0.1.30", + "futures 0.1.31", "iovec", "libc", "log 0.4.14", - "mio", + "mio 0.6.23", "mio-uds", "tokio-codec", "tokio-io", @@ -9923,10 +9966,24 @@ dependencies = [ "futures-core", "futures-sink", "log 0.4.14", - "pin-project-lite 0.1.11", + "pin-project-lite 0.1.12", "tokio 0.2.25", ] +[[package]] +name = "tokio-util" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec31e5cc6b46e653cf57762f36f71d5e6386391d88a72fd6db4508f8f676fb29" +dependencies = [ + "bytes 1.0.1", + "futures-core", + "futures-sink", + "log 0.4.14", + "pin-project-lite 0.2.6", + "tokio 1.3.0", +] + [[package]] name = "toml" version = "0.5.8" @@ -9944,22 +10001,22 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f77d3842f76ca899ff2dbcf231c5c65813dea431301d6eb686279c15c4464f12" +checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" dependencies = [ "cfg-if 1.0.0", "log 0.4.14", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.6", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a9bd1db7706f2373a190b0d067146caa39350c486f3d455b0e33b431f94c07" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" dependencies = [ "proc-macro2", "quote", @@ -9987,9 +10044,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9" +checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" dependencies = [ "lazy_static", "log 0.4.14", @@ -10008,9 +10065,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fa8f0c8f4c594e4fc9debc1990deab13238077271ba84dd853d54902ee3401" +checksum = "705096c6f83bf68ea5d357a6aa01829ddbdac531b357b45abeca842938085baa" dependencies = [ "ansi_term 0.12.1", "chrono", @@ -10037,13 +10094,14 @@ checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] name = "treasury" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ "frame-support", "frame-system", "pallet-balances", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "safe-mix", + "serde", "sp-core", "sp-io", "sp-runtime", @@ -10063,7 +10121,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec051edf7f0fc9499a2cb0947652cab2148b9d7f61cee7605e312e9f970dacaf" dependencies = [ "hash-db", - "hashbrown 0.9.1", + "hashbrown", "log 0.4.14", "rustc-hex", "smallvec 1.6.1", @@ -10103,9 +10161,9 @@ checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" [[package]] name = "typenum" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] name = "ucd-trie" @@ -10113,18 +10171,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" -[[package]] -name = "uint" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db035e67dfaf7edd9aebfe8676afcd63eed53c8a4044fed514c8cccf1835177" -dependencies = [ - "byteorder", - "crunchy", - "rustc-hex", - "static_assertions", -] - [[package]] name = "uint" version = "0.9.0" @@ -10133,7 +10179,7 @@ checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e" dependencies = [ "byteorder", "crunchy", - "hex 0.4.2", + "hex 0.4.3", "static_assertions", ] @@ -10152,7 +10198,7 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.2", + "version_check 0.9.3", ] [[package]] @@ -10250,9 +10296,9 @@ dependencies = [ [[package]] name = "url" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", "idna 0.2.2", @@ -10260,16 +10306,6 @@ dependencies = [ "percent-encoding 2.1.0", ] -[[package]] -name = "util" -version = "0.3.3" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "value-bag" version = "1.0.0-alpha.6" @@ -10281,32 +10317,28 @@ dependencies = [ [[package]] name = "vault" -version = "0.2.6" +version = "0.5.0" dependencies = [ "async-trait", "backoff", - "bitcoin 0.2.0", + "bitcoin 0.5.0", "clap 3.0.0-beta.2", "env_logger 0.7.1", - "futures 0.3.12", - "hex 0.4.2", - "jsonrpc-core 16.0.0", - "jsonrpc-core-client 16.0.0", - "jsonrpc-http-server 16.0.0", - "jsonrpsee", + "futures 0.3.13", + "hex 0.4.3", + "jsonrpc-core 17.0.0", + "jsonrpc-core-client 17.0.0", + "jsonrpc-http-server 17.0.0", "log 0.4.14", "mockall", - "parity-scale-codec 2.0.0", - "rand 0.7.3", + "parity-scale-codec", "runtime", - "schnorrkel", "serde", "serde_json", "sha2 0.8.2", "sp-arithmetic", "sp-core", "sp-keyring", - "tempdir", "thiserror", "tokio 0.2.25", ] @@ -10314,9 +10346,9 @@ dependencies = [ [[package]] name = "vault-registry" version = "0.5.0" -source = "git+https://gitlab.com/interlay/btc-parachain?branch=dev#d4e416109b2277ff6488288f52bee77dca0ae80b" +source = "git+https://github.com/interlay/btc-parachain?branch=master#cc5c16b28ef705e0774654dd94b813d9d35e12ec" dependencies = [ - "bitcoin 0.5.0", + "bitcoin 0.5.0 (git+https://github.com/interlay/btc-parachain?branch=master)", "collateral", "exchange-rate-oracle", "fixed-hash 0.6.1", @@ -10326,8 +10358,8 @@ dependencies = [ "pallet-balances", "pallet-randomness-collective-flip", "pallet-timestamp", - "parity-scale-codec 2.0.0", - "primitive-types 0.9.0", + "parity-scale-codec", + "primitive-types", "security", "serde", "sp-arithmetic", @@ -10336,7 +10368,6 @@ dependencies = [ "sp-runtime", "sp-std", "treasury", - "util", ] [[package]] @@ -10365,9 +10396,9 @@ checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "void" @@ -10398,7 +10429,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "futures 0.1.30", + "futures 0.1.31", "log 0.4.14", "try-lock", ] @@ -10427,9 +10458,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" dependencies = [ "cfg-if 1.0.0", "serde", @@ -10439,9 +10470,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" dependencies = [ "bumpalo", "lazy_static", @@ -10454,9 +10485,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94" +checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -10466,9 +10497,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10476,9 +10507,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" dependencies = [ "proc-macro2", "quote", @@ -10489,9 +10520,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" [[package]] name = "wasm-gc-api" @@ -10510,7 +10541,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "js-sys", "parking_lot 0.11.1", "pin-utils", @@ -10737,27 +10768,27 @@ dependencies = [ [[package]] name = "wast" -version = "33.0.0" +version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d04fe175c7f78214971293e7d8875673804e736092206a3a4544dbc12811c1b" +checksum = "db5ae96da18bb5926341516fd409b5a8ce4e4714da7f0a1063d3b20ac9f9a1e1" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.34" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec9c6ee01ae07a26adadcdfed22c7a97e0b8cbee9c06e0e96076ece5aeb5cfe" +checksum = "0b0fa059022c5dabe129f02b429d67086400deb8277f89c975555dacc1dadbcc" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" dependencies = [ "js-sys", "wasm-bindgen", @@ -10773,15 +10804,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "webpki-roots" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b" -dependencies = [ - "webpki", -] - [[package]] name = "webpki-roots" version = "0.21.0" @@ -10901,18 +10923,18 @@ dependencies = [ [[package]] name = "xcm" version = "0.8.22" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ - "parity-scale-codec 2.0.0", + "parity-scale-codec", ] [[package]] name = "xcm-builder" version = "0.8.22" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "frame-support", - "parity-scale-codec 2.0.0", + "parity-scale-codec", "polkadot-parachain", "sp-arithmetic", "sp-io", @@ -10925,11 +10947,12 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.8.22" -source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#0591066a0a36d0d44649b6159a49c71b2f0a3e69" +source = "git+https://github.com/paritytech/polkadot?branch=rococo-v1#bf7aa8921c1ccc2638c9465224b9b18bef33e35e" dependencies = [ "frame-support", "impl-trait-for-tuples", - "parity-scale-codec 2.0.0", + "log 0.4.14", + "parity-scale-codec", "sp-arithmetic", "sp-core", "sp-io", @@ -10944,7 +10967,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cc7bd8c983209ed5d527f44b01c41b7dc146fd960c61cf9e1d25399841dc271" dependencies = [ - "futures 0.3.12", + "futures 0.3.13", "log 0.4.14", "nohash-hasher", "parking_lot 0.11.1", diff --git a/Cargo.toml b/Cargo.toml index 68dfdd2b3..ec1a04365 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,3 @@ members = [ "bitcoin", "faucet" ] - -[patch.crates-io] -jsonrpsee = { git = "https://github.com/interlay/jsonrpsee", rev = "5b35d10b5ae45a1776a8dcf761ecbe8d6e288646" } \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 5e78af6da..5faf47266 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,19 +8,19 @@ pipeline { } environment { RUSTC_WRAPPER = '/usr/local/bin/sccache' + CI = 'true' + GITHUB_TOKEN = credentials('ns212-github-token') } options { - gitLabConnection 'Gitlab-Interlay' - gitlabBuilds(builds: ['test', 'build']) + timestamps() + ansiColor('xterm') } stages { stage('Test') { steps { container('rust') { - updateGitlabCommitStatus name: 'test', state: 'running' - sh 'rustc --version' sh 'SCCACHE_START_SERVER=1 SCCACHE_IDLE_TIMEOUT=0 /usr/local/bin/sccache' sh '/usr/local/bin/sccache -s' @@ -32,20 +32,6 @@ pipeline { sh '/usr/local/bin/sccache -s' } } - post { - success { - updateGitlabCommitStatus name: 'test', state: 'success' - } - failure { - updateGitlabCommitStatus name: 'test', state: 'failed' - } - unstable { - updateGitlabCommitStatus name: 'test', state: 'failed' - } - aborted { - updateGitlabCommitStatus name: 'test', state: 'canceled' - } - } } stage('Build binaries') { @@ -68,28 +54,12 @@ pipeline { sh '/usr/local/bin/sccache -s' } } - post { - success { - updateGitlabCommitStatus name: 'build', state: 'success' - } - failure { - updateGitlabCommitStatus name: 'build', state: 'failed' - } - unstable { - updateGitlabCommitStatus name: 'build', state: 'failed' - } - aborted { - updateGitlabCommitStatus name: 'build', state: 'canceled' - } - } } stage('Build docker images') { when { anyOf { branch 'master' - branch 'dev' - branch 'jenkins' tag '*' } } @@ -113,6 +83,26 @@ pipeline { } } } + + stage('Create GitHub release') { + when { + anyOf { + branch 'github' + tag '*' + } + } + steps { + sh ''' + wget -q -O - https://github.com/cli/cli/releases/download/v1.6.2/gh_1.6.2_linux_amd64.tar.gz | tar xzf - + ./gh_1.6.2_linux_amd64/bin/gh auth status + wget -q -O - https://github.com/git-chglog/git-chglog/releases/download/v0.10.0/git-chglog_0.10.0_linux_amd64.tar.gz | tar xzf - + #export PREV_TAG=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`) + #export TAG_NAME=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=0 --max-count=1`) + ./git-chglog --output CHANGELOG.md $TAG_NAME + ''' + sh './gh_1.6.2_linux_amd64/bin/gh release -R $GIT_URL create $TAG_NAME --title $TAG_NAME -F CHANGELOG.md -d ' + output_files.collect { "target/release/$it" }.join(' ') + } + } } } diff --git a/README.md b/README.md index 6f0d58f9d..64be34030 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

PolkaBTC Clients

- Oracle, Vault & Staked Relayer + Faucet, Oracle, Vault & Staked Relayer

@@ -20,7 +20,7 @@ Download and start [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/): bitcoind -regtest -server ``` -Build and run the [PolkaBTC Parachain](https://gitlab.com/interlay/btc-parachain): +Build and run the [PolkaBTC Parachain](https://github.com/interlay/btc-parachain): ``` git clone git@gitlab.com:interlay/btc-parachain.git diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index 4891efb46..5951b4858 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -1,9 +1,16 @@ [package] name = "bitcoin" -version = "0.2.0" +version = "0.5.0" authors = ["Interlay "] edition = "2018" +[features] +default = ["polkabtc"] +regtest-mine-on-tx = [] +regtest-manual-mining = [] +cli = ["clap"] +polkabtc = ["polkabtc-bitcoin"] + [dependencies] thiserror = "1.0" bitcoincore-rpc = { git = "https://github.com/gregdhill/rust-bitcoincore-rpc", rev = "80ff27b" } @@ -18,23 +25,17 @@ num-derive = "0.3" futures = "0.3.5" serde_json = "1" log = "0.4.0" +hyper = "0.10" # Substrate dependencies sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } [dependencies.polkabtc-bitcoin] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "bitcoin" optional = true [dev-dependencies] mockall = "0.8.1" - -[features] -default = ["polkabtc"] -regtest-mine-on-tx = [] -regtest-manual-mining = [] -cli = ["clap"] -polkabtc = ["polkabtc-bitcoin"] diff --git a/bitcoin/src/addr.rs b/bitcoin/src/addr.rs index c6a214e07..f246241e3 100644 --- a/bitcoin/src/addr.rs +++ b/bitcoin/src/addr.rs @@ -1,6 +1,6 @@ use crate::{ - secp256k1::SecretKey, Address, ConversionError, Error, Hash, Network, Payload, PubkeyHash, - Script, ScriptHash, WPubkeyHash, + secp256k1::SecretKey, Address, ConversionError, Error, Hash, Network, Payload, PubkeyHash, Script, ScriptHash, + WPubkeyHash, }; use sp_core::H160; use std::str::FromStr; @@ -31,10 +31,7 @@ impl PartialAddress for polkabtc_bitcoin::Address { match payload { Payload::PubkeyHash(hash) => Ok(Self::P2PKH(H160::from(hash.as_hash().into_inner()))), Payload::ScriptHash(hash) => Ok(Self::P2SH(H160::from(hash.as_hash().into_inner()))), - Payload::WitnessProgram { - version: _, - program, - } => { + Payload::WitnessProgram { version: _, program } => { if program.len() == 20 { Ok(Self::P2WPKHv0(H160::from_slice(program.as_slice()))) } else { @@ -81,10 +78,7 @@ impl PartialAddress for Payload { } } -pub fn calculate_deposit_secret_key( - vault_key: SecretKey, - issue_key: SecretKey, -) -> Result { +pub fn calculate_deposit_secret_key(vault_key: SecretKey, issue_key: SecretKey) -> Result { let mut deposit_key = vault_key.clone(); deposit_key.mul_assign(&issue_key[..])?; Ok(deposit_key) @@ -94,8 +88,7 @@ pub fn calculate_deposit_secret_key( mod tests { use super::*; use crate::secp256k1; - use secp256k1::rand::rngs::OsRng; - use secp256k1::{PublicKey, Secp256k1, SecretKey}; + use secp256k1::{rand::rngs::OsRng, PublicKey, Secp256k1, SecretKey}; use sp_core::H256; #[test] @@ -103,10 +96,7 @@ mod tests { let addr = "bcrt1q6v2c7q7uv8vu6xle2k9ryfj3y3fuuy4rqnl50f"; assert_eq!( addr, - Payload::decode_str(addr) - .unwrap() - .encode_str(Network::Regtest) - .unwrap() + Payload::decode_str(addr).unwrap().encode_str(Network::Regtest).unwrap() ); } @@ -126,13 +116,10 @@ mod tests { // D = V * c let mut deposit_public_key = vault_public_key.clone(); - deposit_public_key - .mul_assign(&secp, &secret_key[..]) - .unwrap(); + deposit_public_key.mul_assign(&secp, &secret_key[..]).unwrap(); // d = v * c - let deposit_secret_key = - calculate_deposit_secret_key(vault_secret_key, secret_key).unwrap(); + let deposit_secret_key = calculate_deposit_secret_key(vault_secret_key, secret_key).unwrap(); assert_eq!( deposit_public_key, diff --git a/bitcoin/src/cli.rs b/bitcoin/src/cli.rs index 23d752a4a..7cf631fda 100644 --- a/bitcoin/src/cli.rs +++ b/bitcoin/src/cli.rs @@ -12,6 +12,10 @@ pub struct BitcoinOpts { #[clap(long, env = "BITCOIN_RPC_PASS")] pub bitcoin_rpc_pass: String, + + /// Timeout in milliseconds to wait for connection to bitcoin-core. + #[clap(long, default_value = "60000")] + pub bitcoin_connection_timeout_ms: u64, } impl BitcoinOpts { diff --git a/bitcoin/src/error.rs b/bitcoin/src/error.rs index e29bbce7f..08c4ddaa9 100644 --- a/bitcoin/src/error.rs +++ b/bitcoin/src/error.rs @@ -1,15 +1,17 @@ use crate::BitcoinError; use bitcoincore_rpc::{ bitcoin::{ - consensus::encode::Error as BitcoinEncodeError, hashes::Error as HashesError, - secp256k1::Error as Secp256k1Error, util::address::Error as AddressError, - util::key::Error as KeyError, + consensus::encode::Error as BitcoinEncodeError, + hashes::Error as HashesError, + secp256k1::Error as Secp256k1Error, + util::{address::Error as AddressError, key::Error as KeyError}, }, jsonrpc::error::RpcError, }; use hex::FromHexError; use serde_json::Error as SerdeJsonError; use thiserror::Error; +use tokio::time::Elapsed; #[derive(Error, Debug)] pub enum Error { @@ -27,6 +29,8 @@ pub enum Error { Secp256k1Error(#[from] Secp256k1Error), #[error("KeyError: {0}")] KeyError(#[from] KeyError), + #[error("Timeout: {0}")] + TimeElapsed(#[from] Elapsed), #[error("Could not confirm transaction")] ConfirmationError, @@ -57,7 +61,7 @@ pub enum ConversionError { } // https://github.com/bitcoin/bitcoin/blob/be3af4f31089726267ce2dbdd6c9c153bb5aeae1/src/rpc/protocol.h#L43 -#[derive(Debug, FromPrimitive)] +#[derive(Debug, FromPrimitive, PartialEq, Eq)] pub enum BitcoinRpcError { /// Standard JSON-RPC 2.0 errors RpcInvalidRequest = -32600, diff --git a/bitcoin/src/iter.rs b/bitcoin/src/iter.rs index 0e9a4f0a4..ff4b1cdca 100644 --- a/bitcoin/src/iter.rs +++ b/bitcoin/src/iter.rs @@ -3,12 +3,9 @@ use bitcoincore_rpc::{ bitcoin::{Block, BlockHash, Transaction}, json::GetBlockResult, }; -use futures::prelude::*; -use futures::stream::StreamExt; +use futures::{prelude::*, stream::StreamExt}; use log::trace; -use std::iter; -use std::sync::Arc; -use std::time::Duration; +use std::{iter, time::Duration}; const BLOCK_WAIT_TIMEOUT: u64 = 6; @@ -20,11 +17,11 @@ const BLOCK_WAIT_TIMEOUT: u64 = 6; /// /// * `rpc` - bitcoin rpc /// * `stop_height` - height of the last block the iterator will return transactions from -pub async fn get_transactions( - rpc: Arc, +pub async fn get_transactions( + rpc: &B, stop_height: u32, -) -> Result> + Unpin, Error> { - let mempool_transactions = stream::iter(rpc.clone().get_mempool_transactions().await?); +) -> Result> + Unpin + '_, Error> { + let mempool_transactions = stream::iter(rpc.get_mempool_transactions().await?); let in_chain_transactions = get_in_chain_transactions(rpc, stop_height).await; Ok(mempool_transactions.chain(in_chain_transactions)) } @@ -35,10 +32,10 @@ pub async fn get_transactions( /// /// * `rpc` - bitcoin rpc /// * `stop_height` - height of the last block the iterator will return transactions from -pub async fn get_in_chain_transactions( - rpc: Arc, +pub async fn get_in_chain_transactions( + rpc: &B, stop_height: u32, -) -> impl Stream> + Send + Unpin { +) -> impl Stream> + Send + Unpin + '_ { get_blocks(rpc, stop_height).await.flat_map(|block| { // unfortunately two different iterators don't have compatible types, so we have // to box them to trait objects @@ -50,10 +47,10 @@ pub async fn get_in_chain_transactions { +struct GetBlocksState { height: Option, prev_block: Option, - rpc: Arc, + rpc: B, stop_height: u32, } @@ -66,10 +63,10 @@ struct GetBlocksState { /// /// * `rpc` - bitcoin rpc /// * `stop_height` - height of the last block the iterator will return -pub async fn get_blocks( - rpc: Arc, +pub async fn get_blocks( + rpc: &B, stop_height: u32, -) -> impl Stream> + Unpin { +) -> impl Stream> + Unpin + '_ { let state = GetBlocksState { height: None, prev_block: None, @@ -81,7 +78,7 @@ pub async fn get_blocks( // get height and hash of the block we potentially are about to fetch let (next_height, next_hash) = match (&state.height, &state.prev_block) { (Some(height), Some(block)) => (height - 1, block.header.prev_blockhash), - _ => match get_best_block_info(state.rpc.clone()).await { + _ => match get_best_block_info(state.rpc).await { Ok(info) => (info.height, info.hash), Err(e) => return Some((Err(e), state)), // abort }, @@ -111,8 +108,8 @@ pub async fn get_blocks( /// /// * `rpc` - bitcoin rpc /// * `from_height` - height of the first block of the stream -pub async fn stream_in_chain_transactions( - rpc: Arc, +pub async fn stream_in_chain_transactions( + rpc: B, from_height: u32, num_confirmations: u32, ) -> impl Stream> + Unpin { @@ -124,11 +121,7 @@ pub async fn stream_in_chain_transactions( |err| vec![Err(err)], |block| { let block_hash = block.block_hash(); - block - .txdata - .into_iter() - .map(|tx| Ok((block_hash, tx))) - .collect() + block.txdata.into_iter().map(|tx| Ok((block_hash, tx))).collect() }, )) }), @@ -142,18 +135,18 @@ pub async fn stream_in_chain_transactions( /// /// * `rpc` - bitcoin rpc /// * `from_height` - height of the first block of the stream -pub async fn stream_blocks( - rpc: Arc, +pub async fn stream_blocks( + rpc: B, from_height: u32, num_confirmations: u32, ) -> impl Stream> + Unpin { - struct StreamState { - rpc: Arc, + struct StreamState { + rpc: B, next_height: u32, } let state = StreamState { - rpc: rpc.clone(), + rpc, next_height: from_height, }; @@ -163,11 +156,7 @@ pub async fn stream_blocks( let height = state.next_height; match state .rpc - .wait_for_block( - height, - Duration::from_secs(BLOCK_WAIT_TIMEOUT), - num_confirmations, - ) + .wait_for_block(height, Duration::from_secs(BLOCK_WAIT_TIMEOUT), num_confirmations) .await { Ok(block_hash) => match state.rpc.get_block(&block_hash).await { @@ -187,7 +176,7 @@ pub async fn stream_blocks( /// small helper function for getting the block info of the best block. This simplifies /// error handling a little bit -async fn get_best_block_info(rpc: Arc) -> Result { +async fn get_best_block_info(rpc: &B) -> Result { let hash = rpc.get_best_block_hash().await?; rpc.get_block_info(&hash).await } @@ -208,7 +197,7 @@ mod tests { async fn get_block_count(&self) -> Result; async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, Error>; async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, Error>; - async fn get_block_hash_for(&self, height: u32) -> Result; + async fn get_block_hash(&self, height: u32) -> Result; async fn is_block_known(&self, block_hash: BlockHash) -> Result; async fn get_new_address(&self) -> Result; async fn get_new_public_key + 'static>(&self) -> Result; @@ -219,10 +208,11 @@ mod tests { ) -> Result<(), Error>; async fn get_best_block_hash(&self) -> Result; async fn get_block(&self, hash: &BlockHash) -> Result; + async fn get_block_header(&self, hash: &BlockHash) -> Result; async fn get_block_info(&self, hash: &BlockHash) -> Result; async fn get_mempool_transactions<'a>( - self: Arc, - ) -> Result> + Send +'a>, Error>; + self: &'a Self, + ) -> Result> + Send + 'a>, Error>; async fn wait_for_transaction_metadata( &self, txid: Txid, @@ -257,6 +247,13 @@ mod tests { } } + impl Clone for MockBitcoin { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + fn dummy_block_info(height: usize, hash: BlockHash) -> GetBlockResult { GetBlockResult { height, @@ -317,9 +314,7 @@ mod tests { .expect_get_mempool_transactions() .times(1) .returning(|| Ok(Box::new(vec![Ok(dummy_tx(0))].into_iter()))); - bitcoin - .expect_get_best_block_hash() - .returning(|| Ok(dummy_hash(1))); + bitcoin.expect_get_best_block_hash().returning(|| Ok(dummy_hash(1))); bitcoin .expect_get_block() .withf(|&x| x == dummy_hash(1)) @@ -337,8 +332,8 @@ mod tests { .times(1) .returning(|&hash| Ok(dummy_block_info(21, hash))); - let btc_rpc = Arc::new(bitcoin); - let mut iter = get_transactions(btc_rpc, 20).await.unwrap(); + let btc_rpc = bitcoin; + let mut iter = get_transactions(&btc_rpc, 20).await.unwrap(); assert_eq!(iter.next().await.unwrap().unwrap().version, 0); assert_eq!(iter.next().await.unwrap().unwrap().version, 1); @@ -357,9 +352,7 @@ mod tests { .expect_get_mempool_transactions() .times(1) .returning(|| Ok(Box::new(vec![].into_iter()))); - bitcoin - .expect_get_best_block_hash() - .returning(|| Ok(dummy_hash(1))); + bitcoin.expect_get_best_block_hash().returning(|| Ok(dummy_hash(1))); bitcoin .expect_get_block() .withf(|&x| x == dummy_hash(1)) @@ -386,8 +379,8 @@ mod tests { .times(1) .returning(|&hash| Ok(dummy_block_info(23, hash))); - let btc_rpc = Arc::new(bitcoin); - let mut iter = get_transactions(btc_rpc, 20).await.unwrap(); + let btc_rpc = bitcoin; + let mut iter = get_transactions(&btc_rpc, 20).await.unwrap(); assert_eq!(iter.next().await.unwrap().unwrap().version, 1); assert_eq!(iter.next().await.unwrap().unwrap().version, 2); @@ -403,17 +396,15 @@ mod tests { .expect_get_mempool_transactions() .times(1) .returning(|| Ok(Box::new(vec![].into_iter()))); - bitcoin - .expect_get_best_block_hash() - .returning(|| Ok(dummy_hash(1))); + bitcoin.expect_get_best_block_hash().returning(|| Ok(dummy_hash(1))); bitcoin .expect_get_block_info() .times(1) .returning(|&hash| Ok(dummy_block_info(20, hash))); - let btc_rpc = Arc::new(bitcoin); + let btc_rpc = bitcoin; - let mut iter = get_transactions(btc_rpc, 21).await.unwrap(); + let mut iter = get_transactions(&btc_rpc, 21).await.unwrap(); assert!(iter.next().await.is_none()); } @@ -425,17 +416,15 @@ mod tests { .expect_get_mempool_transactions() .times(1) .returning(|| Ok(Box::new(vec![Ok(dummy_tx(1)), Ok(dummy_tx(2))].into_iter()))); - bitcoin - .expect_get_best_block_hash() - .returning(|| Ok(dummy_hash(1))); + bitcoin.expect_get_best_block_hash().returning(|| Ok(dummy_hash(1))); bitcoin .expect_get_block_info() .times(1) .returning(|&hash| Ok(dummy_block_info(20, hash))); - let btc_rpc = Arc::new(bitcoin); + let btc_rpc = bitcoin; - let mut iter = get_transactions(btc_rpc, 21).await.unwrap(); + let mut iter = get_transactions(&btc_rpc, 21).await.unwrap(); assert_eq!(iter.next().await.unwrap().unwrap().version, 1); assert_eq!(iter.next().await.unwrap().unwrap().version, 2); @@ -449,9 +438,7 @@ mod tests { .expect_get_mempool_transactions() .times(1) .returning(|| Ok(Box::new(vec![].into_iter()))); - bitcoin - .expect_get_best_block_hash() - .returning(|| Ok(dummy_hash(1))); + bitcoin.expect_get_best_block_hash().returning(|| Ok(dummy_hash(1))); bitcoin .expect_get_block() .withf(|&x| x == dummy_hash(1)) @@ -462,9 +449,9 @@ mod tests { .times(1) .returning(|&hash| Ok(dummy_block_info(20, hash))); - let btc_rpc = Arc::new(bitcoin); + let btc_rpc = bitcoin; - let mut iter = get_transactions(btc_rpc, 20).await.unwrap(); + let mut iter = get_transactions(&btc_rpc, 20).await.unwrap(); assert_eq!(iter.next().await.unwrap().unwrap().version, 1); assert!(iter.next().await.is_none()); diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index e558bb7e8..eb39cf48a 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -10,37 +10,39 @@ use async_trait::async_trait; use backoff::{future::FutureOperation as _, ExponentialBackoff}; pub use bitcoincore_rpc::{ bitcoin::{ - blockdata::opcodes::all as opcodes, - blockdata::script::Builder, + blockdata::{opcodes::all as opcodes, script::Builder}, consensus::encode::{deserialize, serialize}, hash_types::BlockHash, hashes::{hex::ToHex, Hash}, secp256k1, - secp256k1::constants::PUBLIC_KEY_SIZE, - secp256k1::SecretKey, - util::uint::Uint256, - util::{address::Payload, key, merkleblock::PartialMerkleTree, psbt::serialize::Serialize}, - Address, Amount, Block, BlockHeader, Network, OutPoint, PrivateKey, PubkeyHash, PublicKey, - Script, ScriptHash, Transaction, TxIn, TxMerkleNode, TxOut, Txid, WPubkeyHash, + secp256k1::{constants::PUBLIC_KEY_SIZE, SecretKey}, + util::{address::Payload, key, merkleblock::PartialMerkleTree, psbt::serialize::Serialize, uint::Uint256}, + Address, Amount, Block, BlockHeader, Network, OutPoint, PrivateKey, PubkeyHash, PublicKey, Script, ScriptHash, + Transaction, TxIn, TxMerkleNode, TxOut, Txid, WPubkeyHash, }, bitcoincore_rpc_json::{CreateRawTransactionInput, GetTransactionResult, WalletTxInfo}, json::{self, AddressType, GetBlockResult}, - jsonrpc::error::RpcError, - jsonrpc::Error as JsonRpcError, + jsonrpc::{error::RpcError, Error as JsonRpcError}, Auth, Client, Error as BitcoinError, RpcApi, }; pub use error::{BitcoinRpcError, ConversionError, Error}; +use hyper::Error as HyperError; pub use iter::{get_transactions, stream_blocks, stream_in_chain_transactions}; +use log::{info, trace}; use sp_core::H256; -use std::{sync::Arc, time::Duration}; -use tokio::sync::{Mutex, OwnedMutexGuard}; -use tokio::time::delay_for; +use std::{io::ErrorKind as IoErrorKind, sync::Arc, time::Duration}; +use tokio::{ + sync::{Mutex, OwnedMutexGuard}, + time::{delay_for, timeout}, +}; #[macro_use] extern crate num_derive; const NOT_IN_MEMPOOL_ERROR_CODE: i32 = BitcoinRpcError::RpcInvalidAddressOrKey as i32; +const RETRY_DURATION: Duration = Duration::from_millis(1000); + #[derive(Debug, Clone)] pub struct TransactionMetadata { pub txid: Txid, @@ -52,12 +54,7 @@ pub struct TransactionMetadata { #[async_trait] pub trait BitcoinCoreApi { - async fn wait_for_block( - &self, - height: u32, - delay: Duration, - num_confirmations: u32, - ) -> Result; + async fn wait_for_block(&self, height: u32, delay: Duration, num_confirmations: u32) -> Result; async fn get_block_count(&self) -> Result; @@ -65,15 +62,13 @@ pub trait BitcoinCoreApi { async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, Error>; - async fn get_block_hash_for(&self, height: u32) -> Result; + async fn get_block_hash(&self, height: u32) -> Result; async fn is_block_known(&self, block_hash: BlockHash) -> Result; async fn get_new_address(&self) -> Result; - async fn get_new_public_key + 'static>( - &self, - ) -> Result; + async fn get_new_public_key + 'static>(&self) -> Result; async fn add_new_deposit_key + Send + Sync + 'static>( &self, @@ -85,10 +80,12 @@ pub trait BitcoinCoreApi { async fn get_block(&self, hash: &BlockHash) -> Result; + async fn get_block_header(&self, hash: &BlockHash) -> Result; + async fn get_block_info(&self, hash: &BlockHash) -> Result; async fn get_mempool_transactions<'a>( - self: Arc, + self: &'a Self, ) -> Result> + Send + 'a>, Error>; async fn wait_for_transaction_metadata( @@ -127,35 +124,32 @@ pub trait BitcoinCoreApi { async fn wallet_has_public_key

(&self, public_key: P) -> Result where - P: Into<[u8; PUBLIC_KEY_SIZE]> - + From<[u8; PUBLIC_KEY_SIZE]> - + Clone - + PartialEq - + Send - + Sync - + 'static; + P: Into<[u8; PUBLIC_KEY_SIZE]> + From<[u8; PUBLIC_KEY_SIZE]> + Clone + PartialEq + Send + Sync + 'static; } pub struct LockedTransaction { pub transaction: Transaction, - _lock: OwnedMutexGuard<()>, + _lock: Option>, } + impl LockedTransaction { - pub fn new(transaction: Transaction, lock: OwnedMutexGuard<()>) -> Self { + pub fn new(transaction: Transaction, lock: Option>) -> Self { LockedTransaction { transaction, _lock: lock, } } } + +#[derive(Clone)] pub struct BitcoinCore { - rpc: Client, + rpc: Arc, transaction_creation_lock: Arc>, network: Network, } impl BitcoinCore { - pub fn new(rpc: Client, network: Network) -> Self { + pub fn new(rpc: Arc, network: Network) -> Self { Self { rpc, network, @@ -163,6 +157,67 @@ impl BitcoinCore { } } + pub async fn new_with_retry( + rpc: Arc, + network: Network, + connection_timeout: Duration, + ) -> Result { + let core = Self::new(rpc, network); + core.connect(connection_timeout).await?; + core.sync().await?; + Ok(core) + } + + /// Connect to a bitcoin-core full node or timeout. + /// + /// # Arguments + /// * `connection_timeout` - maximum duration before elapsing + async fn connect(&self, connection_timeout: Duration) -> Result<(), Error> { + info!("Connecting to bitcoin-core..."); + timeout(connection_timeout, async move { + loop { + match self.rpc.get_blockchain_info() { + Err(BitcoinError::JsonRpc(JsonRpcError::Hyper(HyperError::Io(err)))) + if err.kind() == IoErrorKind::ConnectionRefused => + { + trace!("could not connect to bitcoin-core"); + delay_for(RETRY_DURATION).await; + continue; + } + Err(BitcoinError::JsonRpc(JsonRpcError::Rpc(err))) + if BitcoinRpcError::from(err.clone()) == BitcoinRpcError::RpcInWarmup => + { + // may be loading block index or verifying wallet + trace!("bitcoin-core still in warm up"); + delay_for(RETRY_DURATION).await; + continue; + } + Ok(_) => { + info!("Connected!"); + return Ok(()); + } + Err(err) => return Err(err.into()), + } + } + }) + .await? + } + + /// Wait indefinitely for the node to sync. + async fn sync(&self) -> Result<(), Error> { + info!("Waiting for bitcoin-core to sync..."); + loop { + let info = self.rpc.get_blockchain_info()?; + // NOTE: initial_block_download is always true on regtest + if !info.initial_block_download || info.verification_progress == 1.0 { + info!("Synced!"); + return Ok(()); + } + trace!("bitcoin-core not synced"); + delay_for(RETRY_DURATION).await; + } + } + /// Wrapper of rust_bitcoincore_rpc::create_raw_transaction_hex that accepts an optional op_return fn create_raw_transaction_hex( &self, @@ -176,10 +231,7 @@ impl BitcoinCore { if let Some(request_id) = request_id { // add the op_return data - bitcoind will add op_return and the length automatically - outputs.insert( - "data".to_string(), - serde_json::Value::from(request_id.to_hex()), - ); + outputs.insert("data".to_string(), serde_json::Value::from(request_id.to_hex())); } let args = [ @@ -191,10 +243,8 @@ impl BitcoinCore { #[cfg(feature = "regtest-manual-mining")] pub fn mine_block(&self) -> Result<(), Error> { - self.rpc.generate_to_address( - 1, - &self.rpc.get_new_address(None, Some(AddressType::Bech32))?, - )?; + self.rpc + .generate_to_address(1, &self.rpc.get_new_address(None, Some(AddressType::Bech32))?)?; Ok(()) } } @@ -218,12 +268,7 @@ impl BitcoinCoreApi for BitcoinCore { /// # Arguments /// * `height` - block height to fetch /// * `delay` - wait period before re-checking - async fn wait_for_block( - &self, - height: u32, - delay: Duration, - num_confirmations: u32, - ) -> Result { + async fn wait_for_block(&self, height: u32, delay: Duration, num_confirmations: u32) -> Result { loop { match self.rpc.get_block_hash(height.into()) { Ok(hash) => { @@ -264,9 +309,7 @@ impl BitcoinCoreApi for BitcoinCore { /// * `txid` - transaction ID /// * `block_hash` - hash of the block tx is stored in async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, Error> { - Ok(serialize( - &self.rpc.get_raw_transaction(txid, Some(block_hash))?, - )) + Ok(serialize(&self.rpc.get_raw_transaction(txid, Some(block_hash))?)) } /// Get the merkle proof which can be used to validate transaction inclusion. @@ -282,20 +325,18 @@ impl BitcoinCoreApi for BitcoinCore { /// /// # Arguments /// * `height` - block height - async fn get_block_hash_for(&self, height: u32) -> Result { + async fn get_block_hash(&self, height: u32) -> Result { match self.rpc.get_block_hash(height.into()) { Ok(block_hash) => Ok(block_hash), - Err(e) => Err( - if let BitcoinError::JsonRpc(JsonRpcError::Rpc(rpc_error)) = &e { - match BitcoinRpcError::from(rpc_error.clone()) { - // block does not exist yet - BitcoinRpcError::RpcInvalidParameter => Error::InvalidBitcoinHeight, - _ => e.into(), - } - } else { - e.into() - }, - ), + Err(e) => Err(if let BitcoinError::JsonRpc(JsonRpcError::Rpc(rpc_error)) = &e { + match BitcoinRpcError::from(rpc_error.clone()) { + // block does not exist yet + BitcoinRpcError::RpcInvalidParameter => Error::InvalidBitcoinHeight, + _ => e.into(), + } + } else { + e.into() + }), } } @@ -322,9 +363,7 @@ impl BitcoinCoreApi for BitcoinCore { } /// Gets a new public key for an address in the wallet - async fn get_new_public_key + 'static>( - &self, - ) -> Result { + async fn get_new_public_key + 'static>(&self) -> Result { let address = self.rpc.get_new_address(None, Some(AddressType::Bech32))?; let address_info = self.rpc.get_address_info(&address)?; let public_key = address_info.pubkey.ok_or(Error::MissingPublicKey)?; @@ -340,10 +379,8 @@ impl BitcoinCoreApi for BitcoinCore { let address = Address::p2wpkh(&PublicKey::from_slice(&public_key.into())?, self.network) .map_err(|err| ConversionError::from(err))?; let private_key = self.rpc.dump_private_key(&address)?; - let deposit_secret_key = addr::calculate_deposit_secret_key( - private_key.key, - SecretKey::from_slice(&secret_key)?, - )?; + let deposit_secret_key = + addr::calculate_deposit_secret_key(private_key.key, SecretKey::from_slice(&secret_key)?)?; self.rpc.import_private_key( &PrivateKey { compressed: private_key.compressed, @@ -365,6 +402,10 @@ impl BitcoinCoreApi for BitcoinCore { Ok(self.rpc.get_block(hash)?) } + async fn get_block_header(&self, hash: &BlockHash) -> Result { + Ok(self.rpc.get_block_header(hash)?) + } + async fn get_block_info(&self, hash: &BlockHash) -> Result { Ok(self.rpc.get_block_info(hash)?) } @@ -372,7 +413,7 @@ impl BitcoinCoreApi for BitcoinCore { /// Get the transactions that are currently in the mempool. Since `impl trait` is not /// allowed within trait method, we have to use trait objects. async fn get_mempool_transactions<'a>( - self: Arc, + self: &'a Self, ) -> Result> + Send + 'a>, Error> { // get txids from the mempool let txids = self.rpc.get_raw_mempool()?; @@ -386,6 +427,7 @@ impl BitcoinCoreApi for BitcoinCore { }); Ok(Box::new(iterator)) } + /// Waits for the required number of confirmations, and collects data about the /// transaction /// @@ -421,9 +463,7 @@ impl BitcoinCoreApi for BitcoinCore { .. }, .. - }) if confirmations >= 0 && confirmations as u32 >= num_confirmations => { - Ok((height, hash)) - } + }) if confirmations >= 0 && confirmations as u32 >= num_confirmations => Ok((height, hash)), Ok(_) => Err(Error::ConfirmationError), Err(e) => Err(e.into()), }?) @@ -468,8 +508,7 @@ impl BitcoinCoreApi for BitcoinCore { // this function would be to call create_raw_transaction (without the _hex suffix), and // to add the op_return afterwards. However, this function fails if no inputs are // specified, as is the case for us prior to calling fund_raw_transaction. - let raw_tx = - self.create_raw_transaction_hex(address_string, Amount::from_sat(sat), request_id)?; + let raw_tx = self.create_raw_transaction_hex(address_string, Amount::from_sat(sat), request_id)?; // ensure no other fund_raw_transaction calls are made until we submitted the // transaction to the bitcoind. If we don't do this, the same uxto may be used @@ -491,7 +530,7 @@ impl BitcoinCoreApi for BitcoinCore { let transaction = signed_funded_raw_tx.transaction()?; - Ok(LockedTransaction::new(transaction, lock)) + Ok(LockedTransaction::new(transaction, Some(lock))) } /// Submits a transaction to the mempool @@ -540,15 +579,11 @@ impl BitcoinCoreApi for BitcoinCore { op_timeout: Duration, num_confirmations: u32, ) -> Result { - let txid = self - .create_and_send_transaction(address, sat, request_id) - .await?; + let txid = self.create_and_send_transaction(address, sat, request_id).await?; #[cfg(feature = "regtest-mine-on-tx")] - self.rpc.generate_to_address( - 1, - &self.rpc.get_new_address(None, Some(AddressType::Bech32))?, - )?; + self.rpc + .generate_to_address(1, &self.rpc.get_new_address(None, Some(AddressType::Bech32))?)?; Ok(self .wait_for_transaction_metadata(txid, op_timeout, num_confirmations) @@ -575,19 +610,10 @@ impl BitcoinCoreApi for BitcoinCore { async fn wallet_has_public_key

(&self, public_key: P) -> Result where - P: Into<[u8; PUBLIC_KEY_SIZE]> - + From<[u8; PUBLIC_KEY_SIZE]> - + Clone - + PartialEq - + Send - + Sync - + 'static, + P: Into<[u8; PUBLIC_KEY_SIZE]> + From<[u8; PUBLIC_KEY_SIZE]> + Clone + PartialEq + Send + Sync + 'static, { - let address = Address::p2wpkh( - &PublicKey::from_slice(&public_key.clone().into())?, - self.network, - ) - .map_err(|err| ConversionError::from(err))?; + let address = Address::p2wpkh(&PublicKey::from_slice(&public_key.clone().into())?, self.network) + .map_err(|err| ConversionError::from(err))?; let address_info = self.rpc.get_address_info(&address)?; let wallet_pubkey = address_info.pubkey.ok_or(Error::MissingPublicKey)?; Ok(P::from(wallet_pubkey.key.serialize()) == public_key) @@ -651,7 +677,7 @@ impl TransactionExt for Transaction { } } -// https://gitlab.com/interlay/btc-parachain/-/blob/dev/crates/bitcoin/src/parser.rs#L264 +// https://github.com/interlay/btc-parachain/blob/cc5c16b28ef705e0774654dd94b813d9d35e12ec/crates/bitcoin/src/parser.rs#L277 fn parse_compact_uint(varint: &[u8]) -> Result<(u64, usize), Error> { match varint.get(0).ok_or(Error::ParsingError)? { 0xfd => { @@ -693,15 +719,13 @@ fn vin_to_address(vin: TxIn) -> Result { // TODO: reuse logic from bitcoin crate let last = std::cmp::min(pos + 3, input_script.len()); - let (size, len) = - parse_compact_uint(input_script.get(pos..last).ok_or(Error::ParsingError)?)?; + let (size, len) = parse_compact_uint(input_script.get(pos..last).ok_or(Error::ParsingError)?)?; pos += len; // skip sigs pos += size as usize; // parse redeem_script or compressed public_key let last = std::cmp::min(pos + 3, input_script.len()); - let (_size, len) = - parse_compact_uint(input_script.get(pos..last).ok_or(Error::ParsingError)?)?; + let (_size, len) = parse_compact_uint(input_script.get(pos..last).ok_or(Error::ParsingError)?)?; pos += len; let bytes = input_script.get(pos..).ok_or(Error::ParsingError)?; diff --git a/faucet/Cargo.toml b/faucet/Cargo.toml index 6d7db40a0..da693bcdf 100644 --- a/faucet/Cargo.toml +++ b/faucet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "faucet" -version = "0.2.0" +version = "0.5.0" authors = ["Interlay "] edition = "2018" @@ -10,26 +10,22 @@ env_logger = "0.6.1" clap = "3.0.0-beta.2" chrono = "0.4.19" tokio = { version = "0.2.22", features = ["full"] } -runtime = { path = "../runtime" } -bitcoin = { path = "../bitcoin", features = ["cli"] } thiserror = "1.0" -jsonrpc-http-server = "16.0.0" -jsonrpsee = "0.1.0" +jsonrpc-http-server = "17.0.0" parity-scale-codec = "2.0.0" serde_json = "1.0.57" serde = "1.0.116" -futures = "0.3.5" hex = "0.4.2" kv = { version = "0.22.0", features = ["json-value"] } -pin-project-lite = "0.2.4" +async-trait = "0.1.40" -# Substrate dependencies -sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } -sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } +# Workspace dependencies +runtime = { path = "../runtime" } [dev-dependencies] -substrate-subxt-client = { git = "https://github.com/interlay/substrate-subxt", rev = "9ef6ed9" } -tempdir = "0.3.7" -btc-parachain = { git = "https://gitlab.com/interlay/btc-parachain", branch = "dev", version = "0.5.0", features = ["aura-grandpa"] } -btc-parachain-service = { git = "https://gitlab.com/interlay/btc-parachain", branch = "dev", version = "0.5.0", features = ["aura-grandpa"] } +# Workspace dependencies +runtime = { path = "../runtime", features = ["testing-utils"] } + +# Substrate dependencies +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } diff --git a/faucet/src/http.rs b/faucet/src/http.rs index 99a295969..fee024a41 100644 --- a/faucet/src/http.rs +++ b/faucet/src/http.rs @@ -1,21 +1,22 @@ use crate::Error; -use chrono::{DateTime, Duration, Utc}; -use futures::{self, executor::block_on}; +use chrono::{DateTime, Duration as ISO8601, Utc}; use hex::FromHex; -use jsonrpc_http_server::jsonrpc_core::serde_json::Value; -use jsonrpc_http_server::jsonrpc_core::{Error as JsonRpcError, ErrorCode as JsonRpcErrorCode}; -use jsonrpc_http_server::jsonrpc_core::{IoHandler, Params}; -use jsonrpc_http_server::{DomainsValidation, ServerBuilder}; +use jsonrpc_http_server::{ + jsonrpc_core::{serde_json::Value, Error as JsonRpcError, ErrorCode as JsonRpcErrorCode, IoHandler, Params}, + DomainsValidation, ServerBuilder, +}; use kv::*; -use log::error; +use log::{debug, info, warn}; use parity_scale_codec::{Decode, Encode}; use runtime::{ - AccountId, DotBalancesPallet, PolkaBtcProvider, SecurityPallet, StakedRelayerPallet, - VaultRegistryPallet, PLANCK_PER_DOT, + AccountId, DotBalancesPallet, Error as RuntimeError, PolkaBtcProvider, StakedRelayerPallet, VaultRegistryPallet, + PLANCK_PER_DOT, }; use serde::{Deserialize, Deserializer}; -use std::sync::Arc; -use std::{collections::HashMap, net::SocketAddr}; +use std::{collections::HashMap, net::SocketAddr, time::Duration}; +use tokio::time::timeout; + +const HEALTH_DURATION: Duration = Duration::from_millis(5000); const KV_STORE_NAME: &str = "store"; const FAUCET_COOLDOWN_HOURS: i64 = 6; @@ -26,6 +27,18 @@ struct FaucetRequest { account_type: FundingRequestAccountType, } +#[derive(Debug, Clone, Deserialize)] +struct RawBytes(#[serde(deserialize_with = "hex_to_buffer")] Vec); + +pub fn hex_to_buffer<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + use serde::de::Error; + String::deserialize(deserializer) + .and_then(|string| Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string()))) +} + fn parse_params(params: Params) -> Result { let raw: [RawBytes; 1] = params.parse()?; let req = Decode::decode(&mut &raw[0].0[..]).map_err(Error::CodecError)?; @@ -43,22 +56,11 @@ fn handle_resp(resp: Result) -> Result } } -#[derive(Debug, Clone, Deserialize)] -struct RawBytes(#[serde(deserialize_with = "hex_to_buffer")] Vec); - -pub fn hex_to_buffer<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - use serde::de::Error; - String::deserialize(deserializer).and_then(|string| { - Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string())) - }) -} - -fn _system_health(provider: &Arc) -> Result<(), Error> { - block_on(provider.get_parachain_status())?; - Ok(()) +async fn _system_health(provider: &PolkaBtcProvider) -> Result<(), Error> { + match timeout(HEALTH_DURATION, provider.get_latest_block_hash()).await { + Err(err) => Err(Error::RuntimeError(RuntimeError::from(err))), + _ => Ok(()), + } } #[derive(Encode, Decode, Debug, Clone)] @@ -74,7 +76,7 @@ enum FundingRequestAccountType { } async fn _fund_account_raw( - provider: &Arc, + provider: &PolkaBtcProvider, params: Params, store: Store, user_allowance: u128, @@ -85,21 +87,18 @@ async fn _fund_account_raw( let mut allowances = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance); allowances.insert(FundingRequestAccountType::Vault, vault_allowance); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance); fund_account(provider, req, store, allowances).await } async fn get_account_type( - provider: &Arc, + provider: &PolkaBtcProvider, account_id: AccountId, ) -> Result { if let Ok(_) = provider.get_vault(account_id.clone()).await { return Ok(FundingRequestAccountType::Vault); } - let active_stake = provider.get_stake_by_id(account_id.clone()).await?; + let active_stake = provider.get_active_stake_by_id(account_id.clone()).await?; let inactive_stake = provider.get_inactive_stake_by_id(account_id).await?; if active_stake.gt(&0) || inactive_stake.gt(&0) { return Ok(FundingRequestAccountType::StakedRelayer); @@ -122,7 +121,6 @@ fn update_kv_store( account_type, }; kv.set(account_id.to_string(), Json(faucet_request))?; - kv.flush()?; Ok(()) } @@ -131,8 +129,7 @@ fn is_type_and_was_user( current_account_type: FundingRequestAccountType, previous_account_type: FundingRequestAccountType, ) -> bool { - current_account_type.eq(&account_type) - && previous_account_type.eq(&FundingRequestAccountType::User) + current_account_type.eq(&account_type) && previous_account_type.eq(&FundingRequestAccountType::User) } fn has_request_expired( @@ -165,7 +162,7 @@ fn is_funding_allowed( // Unless there's a bug in the std lib implementation of Utc::now() or a false reading from the // system clock, unwrap will never panic let cooldown_threshold = Utc::now() - .checked_sub_signed(Duration::hours(FAUCET_COOLDOWN_HOURS)) + .checked_sub_signed(ISO8601::hours(FAUCET_COOLDOWN_HOURS)) .ok_or(Error::MathError)?; Ok(match last_request_json { @@ -180,7 +177,7 @@ fn is_funding_allowed( } async fn atomic_faucet_funding( - provider: &Arc, + provider: &PolkaBtcProvider, kv: Bucket<'_, String, Json>, account_id: AccountId, allowances: HashMap, @@ -188,70 +185,68 @@ async fn atomic_faucet_funding( let last_request_json = kv.get(account_id.to_string())?; let account_type = get_account_type(&provider, account_id.clone()).await?; if !is_funding_allowed(last_request_json, account_type.clone())? { + warn!("{} already funded", account_id); return Err(Error::FaucetOveruseError); } // Replace the previous, expired claim datetime with the datetime of the current claim - update_kv_store( - &kv, - account_id.clone(), - Utc::now().to_rfc2822(), - account_type.clone(), - )?; + update_kv_store(&kv, account_id.clone(), Utc::now().to_rfc2822(), account_type.clone())?; let amount = allowances .get(&account_type) .ok_or(Error::NoFaucetAllowance)? .checked_mul(PLANCK_PER_DOT) .ok_or(Error::MathError)?; + info!( + "AccountId: {}, Type: {:?}, Amount: {}", + account_id, account_type, amount + ); provider.transfer_to(account_id, amount).await?; Ok(()) } async fn fund_account( - provider: &Arc, + provider: &PolkaBtcProvider, req: FundAccountJsonRpcRequest, store: Store, allowances: HashMap, ) -> Result<(), Error> { let provider = provider.clone(); let kv = open_kv_store(store)?; - block_on(atomic_faucet_funding( - &provider, - kv, - req.account_id.clone(), - allowances, - ))?; + atomic_faucet_funding(&provider, kv, req.account_id.clone(), allowances).await?; Ok(()) } -pub async fn start( - provider: Arc, +pub async fn start_http( + provider: PolkaBtcProvider, addr: SocketAddr, origin: String, user_allowance: u128, vault_allowance: u128, staked_relayer_allowance: u128, -) { + handle: tokio::runtime::Handle, +) -> jsonrpc_http_server::CloseHandle { let mut io = IoHandler::default(); + let store = Store::new(Config::new("./kv")).expect("Unable to open kv store"); io.add_sync_method("user_allowance", move |_| handle_resp(Ok(user_allowance))); io.add_sync_method("vault_allowance", move |_| handle_resp(Ok(vault_allowance))); io.add_sync_method("staked_relayer_allowance", move |_| { handle_resp(Ok(staked_relayer_allowance)) }); - let provider = provider.clone(); { let provider = provider.clone(); - io.add_sync_method("system_health", move |_| { - handle_resp(_system_health(&provider)) + io.add_method("system_health", move |_| { + let provider = provider.clone(); + async move { handle_resp(_system_health(&provider).await) } }); } { let provider = provider.clone(); + let store = store.clone(); // an async closure is only FnOnce, so we need this workaround io.add_method("fund_account", move |params| { let provider = provider.clone(); + let store = store.clone(); async move { - let store = Store::new(Config::new("./kv")).expect("Unable to open kv store"); let result = _fund_account_raw( &provider.clone(), params, @@ -261,23 +256,28 @@ pub async fn start( staked_relayer_allowance, ) .await; + debug!("Result: {:?}", result); handle_resp(result) } }); }; let server = ServerBuilder::new(io) + .event_loop_executor(handle.clone()) .health_api(("/health", "system_health")) .rest_api(jsonrpc_http_server::RestApi::Unsecure) .cors(DomainsValidation::AllowOnly(vec![origin.into()])) .start_http(&addr) .expect("Unable to start RPC server"); - tokio::task::spawn_blocking(move || { + let close_handle = server.close_handle(); + + handle.spawn_blocking(move || { + info!("Starting http server..."); server.wait(); - }) - .await - .unwrap(); + }); + + close_handle } #[cfg(test)] @@ -286,18 +286,12 @@ mod tests { use std::{collections::HashMap, sync::Arc}; use super::{ - fund_account, open_kv_store, DotBalancesPallet, FundAccountJsonRpcRequest, - FundingRequestAccountType, PolkaBtcProvider, PLANCK_PER_DOT, + fund_account, open_kv_store, DotBalancesPallet, FundAccountJsonRpcRequest, FundingRequestAccountType, + PLANCK_PER_DOT, }; - use jsonrpsee::Client as JsonRpseeClient; use kv::{Config, Store}; - use runtime::{substrate_subxt::PairSigner, StakedRelayerPallet}; - use runtime::{AccountId, BtcPublicKey, PolkaBtcRuntime, VaultRegistryPallet}; + use runtime::{integration::*, AccountId, BtcPublicKey, StakedRelayerPallet, VaultRegistryPallet}; use sp_keyring::AccountKeyring; - use substrate_subxt_client::{ - DatabaseConfig, KeystoreConfig, Role, SubxtClient, SubxtClientConfig, - }; - use tempdir::TempDir; macro_rules! assert_err { ($result:expr, $err:pat) => {{ @@ -311,43 +305,11 @@ mod tests { fn dummy_public_key() -> BtcPublicKey { BtcPublicKey([ - 2, 205, 114, 218, 156, 16, 235, 172, 106, 37, 18, 153, 202, 140, 176, 91, 207, 51, 187, - 55, 18, 45, 222, 180, 119, 54, 243, 97, 173, 150, 161, 169, 230, + 2, 205, 114, 218, 156, 16, 235, 172, 106, 37, 18, 153, 202, 140, 176, 91, 207, 51, 187, 55, 18, 45, 222, + 180, 119, 54, 243, 97, 173, 150, 161, 169, 230, ]) } - async fn default_provider_client(key: AccountKeyring) -> (JsonRpseeClient, TempDir) { - let tmp = TempDir::new("btc-parachain-").expect("failed to create tempdir"); - let config = SubxtClientConfig { - impl_name: "btc-parachain-full-client", - impl_version: "0.0.1", - author: "Interlay Ltd", - copyright_start_year: 2020, - db: DatabaseConfig::ParityDb { - path: tmp.path().join("db"), - }, - keystore: KeystoreConfig::Path { - path: tmp.path().join("keystore"), - password: None, - }, - chain_spec: btc_parachain::chain_spec::development_config(), - role: Role::Authority(key.clone()), - telemetry: None, - }; - - let client = SubxtClient::from_config(config, btc_parachain_service::new_full) - .expect("Error creating subxt client") - .into(); - return (client, tmp); - } - - async fn setup_provider(client: JsonRpseeClient, key: AccountKeyring) -> PolkaBtcProvider { - let signer = PairSigner::::new(key.pair()); - PolkaBtcProvider::new(client, signer) - .await - .expect("Error creating provider") - } - fn dot_to_planck(dot: u128) -> u128 { dot.checked_mul(PLANCK_PER_DOT).unwrap() } @@ -363,15 +325,11 @@ mod tests { let mut allowances: HashMap = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance_dot); allowances.insert(FundingRequestAccountType::Vault, vault_allowance_dot); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance_dot, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance_dot); let expected_amount_planck: u128 = dot_to_planck(user_allowance_dot); - let store = - Store::new(Config::new(tmp_dir.path().join("kv1"))).expect("Unable to open kv store"); + let store = Store::new(Config::new(tmp_dir.path().join("kv1"))).expect("Unable to open kv store"); let kv = open_kv_store(store.clone()).unwrap(); kv.clear().unwrap(); @@ -407,14 +365,10 @@ mod tests { let mut allowances: HashMap = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance_dot); allowances.insert(FundingRequestAccountType::Vault, vault_allowance_dot); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance_dot, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance_dot); let expected_amount_planck: u128 = dot_to_planck(vault_allowance_dot); - let store = - Store::new(Config::new(tmp_dir.path().join("kv3"))).expect("Unable to open kv store"); + let store = Store::new(Config::new(tmp_dir.path().join("kv3"))).expect("Unable to open kv store"); let kv = open_kv_store(store.clone()).unwrap(); kv.clear().unwrap(); @@ -434,10 +388,7 @@ mod tests { .expect("Funding the account failed"); let bob_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; - bob_provider - .register_vault(100, dummy_public_key()) - .await - .unwrap(); + bob_provider.register_vault(100, dummy_public_key()).await.unwrap(); let bob_funds_before = alice_provider .get_free_dot_balance_for_id(bob_account_id.clone()) @@ -466,14 +417,10 @@ mod tests { let mut allowances: HashMap = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance_dot); allowances.insert(FundingRequestAccountType::Vault, vault_allowance_dot); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance_dot, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance_dot); let expected_amount_planck: u128 = dot_to_planck(staked_relayer_allowance_dot); - let store = - Store::new(Config::new(tmp_dir.path().join("kv3"))).expect("Unable to open kv store"); + let store = Store::new(Config::new(tmp_dir.path().join("kv3"))).expect("Unable to open kv store"); let kv = open_kv_store(store.clone()).unwrap(); kv.clear().unwrap(); @@ -522,14 +469,10 @@ mod tests { let mut allowances: HashMap = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance_dot); allowances.insert(FundingRequestAccountType::Vault, vault_allowance_dot); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance_dot, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance_dot); let expected_amount_planck: u128 = dot_to_planck(user_allowance_dot); - let store = - Store::new(Config::new(tmp_dir.path().join("kv3"))).expect("Unable to open kv store"); + let store = Store::new(Config::new(tmp_dir.path().join("kv3"))).expect("Unable to open kv store"); let kv = open_kv_store(store.clone()).unwrap(); kv.clear().unwrap(); @@ -574,17 +517,11 @@ mod tests { let mut allowances: HashMap = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance_dot); allowances.insert(FundingRequestAccountType::Vault, vault_allowance_dot); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance_dot, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance_dot); let expected_amount_planck: u128 = dot_to_planck(vault_allowance_dot); let bob_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; - bob_provider - .register_vault(100, dummy_public_key()) - .await - .unwrap(); + bob_provider.register_vault(100, dummy_public_key()).await.unwrap(); let alice_provider = setup_provider(client.clone(), AccountKeyring::Alice).await; let bob_funds_before = alice_provider @@ -595,8 +532,7 @@ mod tests { account_id: bob_account_id.clone(), }; - let store = - Store::new(Config::new(tmp_dir.path().join("kv4"))).expect("Unable to open kv store"); + let store = Store::new(Config::new(tmp_dir.path().join("kv4"))).expect("Unable to open kv store"); let kv = open_kv_store(store.clone()).unwrap(); kv.clear().unwrap(); fund_account(&Arc::from(alice_provider.clone()), req, store, allowances) @@ -622,17 +558,11 @@ mod tests { let mut allowances: HashMap = HashMap::new(); allowances.insert(FundingRequestAccountType::User, user_allowance_dot); allowances.insert(FundingRequestAccountType::Vault, vault_allowance_dot); - allowances.insert( - FundingRequestAccountType::StakedRelayer, - staked_relayer_allowance_dot, - ); + allowances.insert(FundingRequestAccountType::StakedRelayer, staked_relayer_allowance_dot); let expected_amount_planck: u128 = dot_to_planck(vault_allowance_dot); let bob_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; - bob_provider - .register_vault(100, dummy_public_key()) - .await - .unwrap(); + bob_provider.register_vault(100, dummy_public_key()).await.unwrap(); let alice_provider = setup_provider(client.clone(), AccountKeyring::Alice).await; let bob_funds_before = alice_provider @@ -643,8 +573,7 @@ mod tests { account_id: bob_account_id.clone(), }; - let store = - Store::new(Config::new(tmp_dir.path().join("kv5"))).expect("Unable to open kv store"); + let store = Store::new(Config::new(tmp_dir.path().join("kv5"))).expect("Unable to open kv store"); let kv = open_kv_store(store.clone()).unwrap(); kv.clear().unwrap(); fund_account( diff --git a/faucet/src/main.rs b/faucet/src/main.rs index 1b53e1c02..582a99ca4 100644 --- a/faucet/src/main.rs +++ b/faucet/src/main.rs @@ -1,28 +1,28 @@ mod error; mod http; +mod system; use clap::Clap; use error::Error; -use runtime::substrate_subxt::PairSigner; -use runtime::{PolkaBtcProvider, PolkaBtcRuntime}; -use std::sync::Arc; +use runtime::{substrate_subxt::PairSigner, ConnectionManager, PolkaBtcRuntime}; +use system::{FaucetService, FaucetServiceConfig}; /// DOT faucet for enabling users to test PolkaBTC #[derive(Clap)] -#[clap(version = "0.1", author = "Interlay ")] +#[clap(version = "0.2", author = "Interlay ")] struct Opts { - /// Parachain URL, can be over WebSockets or HTTP. - #[clap(long, default_value = "ws://127.0.0.1:9944")] - polka_btc_url: String, + /// Keyring / keyfile options. + #[clap(flatten)] + account_info: runtime::cli::ProviderUserOpts, + + /// Connection settings for the BTC-Parachain. + #[clap(flatten)] + parachain: runtime::cli::ConnectionOpts, /// Address to listen on for JSON-RPC requests. #[clap(long, default_value = "[::0]:3033")] http_addr: String, - /// keyring / keyfile options. - #[clap(flatten)] - account_info: runtime::cli::ProviderUserOpts, - /// Comma separated list of allowed origins. #[clap(long, default_value = "*")] rpc_cors_domain: String, @@ -42,23 +42,29 @@ struct Opts { #[tokio::main] async fn main() -> Result<(), Error> { - env_logger::init(); + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, log::LevelFilter::Info.as_str()), + ); let opts: Opts = Opts::parse(); let (key_pair, _) = opts.account_info.get_key_pair()?; let signer = PairSigner::::new(key_pair); - let provider = Arc::new(PolkaBtcProvider::from_url(opts.polka_btc_url, signer).await?); - let http_addr = opts.http_addr.parse()?; - http::start( - provider.clone(), - http_addr, - opts.rpc_cors_domain, - opts.user_allowance, - opts.vault_allowance, - opts.staked_relayer_allowance, + ConnectionManager::<_, _, FaucetService>::new( + opts.parachain.polka_btc_url.clone(), + signer.clone(), + FaucetServiceConfig { + http_addr: opts.http_addr.parse()?, + rpc_cors_domain: opts.rpc_cors_domain, + user_allowance: opts.user_allowance, + vault_allowance: opts.vault_allowance, + staked_relayer_allowance: opts.staked_relayer_allowance, + }, + opts.parachain.into(), + tokio::runtime::Handle::current(), ) - .await; + .start() + .await?; Ok(()) } diff --git a/faucet/src/system.rs b/faucet/src/system.rs new file mode 100644 index 000000000..f1a954655 --- /dev/null +++ b/faucet/src/system.rs @@ -0,0 +1,71 @@ +use crate::{http, Error}; +use async_trait::async_trait; +use runtime::{on_shutdown, Error as RuntimeError, PolkaBtcProvider, Service, ShutdownReceiver}; +use std::net::SocketAddr; + +#[derive(Clone)] +pub struct FaucetServiceConfig { + pub http_addr: SocketAddr, + pub rpc_cors_domain: String, + pub user_allowance: u128, + pub vault_allowance: u128, + pub staked_relayer_allowance: u128, +} + +pub struct FaucetService { + btc_parachain: PolkaBtcProvider, + config: FaucetServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, +} + +#[async_trait] +impl Service for FaucetService { + async fn start( + btc_parachain: PolkaBtcProvider, + config: FaucetServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, + ) -> Result<(), RuntimeError> { + FaucetService::new(btc_parachain, config, handle, shutdown) + .run_service() + .await + .map_err(|_| RuntimeError::ChannelClosed) + } +} + +impl FaucetService { + fn new( + btc_parachain: PolkaBtcProvider, + config: FaucetServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, + ) -> Self { + Self { + btc_parachain, + config, + handle, + shutdown, + } + } + + async fn run_service(&self) -> Result<(), Error> { + let close_handle = http::start_http( + self.btc_parachain.clone(), + self.config.http_addr, + self.config.rpc_cors_domain.clone(), + self.config.user_allowance, + self.config.vault_allowance, + self.config.staked_relayer_allowance, + self.handle.clone(), + ) + .await; + + on_shutdown(self.shutdown.clone(), async move { + close_handle.close(); + }) + .await; + + Ok(()) + } +} diff --git a/oracle/Cargo.toml b/oracle/Cargo.toml index 4939d5cba..6491486b9 100644 --- a/oracle/Cargo.toml +++ b/oracle/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oracle" -version = "0.2.2" +version = "0.5.0" authors = ["Interlay "] edition = "2018" @@ -9,10 +9,9 @@ log = "0.4.0" env_logger = "0.7.1" clap = "3.0.0-beta.2" tokio = { version = "0.2.22", features = ["full"] } -runtime = { path = "../runtime" } chrono = "0.4" thiserror = "1.0" reqwest = { version = "0.10.9", features = ["json"] } -# Substrate dependencies -sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } \ No newline at end of file +# Workspace dependencies +runtime = { path = "../runtime" } diff --git a/oracle/src/main.rs b/oracle/src/main.rs index a681f318f..8ff4c651a 100644 --- a/oracle/src/main.rs +++ b/oracle/src/main.rs @@ -3,24 +3,21 @@ mod error; use clap::Clap; use error::Error; use log::{error, info}; -use runtime::substrate_subxt::PairSigner; use runtime::{ - ExchangeRateOraclePallet, FixedPointNumber, FixedU128, PolkaBtcProvider, PolkaBtcRuntime, + substrate_subxt::PairSigner, ExchangeRateOraclePallet, FixedPointNumber, FixedU128, PolkaBtcProvider, + PolkaBtcRuntime, }; -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; +use std::{collections::HashMap, time::Duration}; use tokio::time::delay_for; const ERR_RETRY_WAIT: Duration = Duration::from_secs(10); async fn get_exchange_rate_from_coingecko() -> Result { // https://www.coingecko.com/api/documentations/v3 - let resp = - reqwest::get("https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=dot") - .await? - .json::>>() - .await?; + let resp = reqwest::get("https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=dot") + .await? + .json::>>() + .await?; Ok(*resp .get("bitcoin") @@ -44,8 +41,8 @@ struct Opts { #[clap(long, default_value = "385523187")] exchange_rate: u128, - /// Timeout for exchange rate setter, default 30 minutes. - #[clap(long, default_value = "1800000")] + /// Timeout for exchange rate setter, default 25 minutes. + #[clap(long, default_value = "1500000")] timeout_ms: u64, /// keyring / keyfile options. @@ -55,20 +52,25 @@ struct Opts { /// Fetch the exchange rate from CoinGecko. #[clap(long, conflicts_with("exchange-rate"))] coingecko: bool, + + /// Timeout in milliseconds to wait for connection to btc-parachain. + #[clap(long, default_value = "60000")] + connection_timeout_ms: u64, } #[tokio::main] async fn main() -> Result<(), Error> { - env_logger::init(); + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, log::LevelFilter::Info.as_str()), + ); let opts: Opts = Opts::parse(); let (key_pair, _) = opts.account_info.get_key_pair()?; let signer = PairSigner::::new(key_pair); - let provider = Arc::new(PolkaBtcProvider::from_url(opts.polka_btc_url, signer).await?); let timeout = Duration::from_millis(opts.timeout_ms); - let exchange_rate = FixedU128::checked_from_rational(opts.exchange_rate, 100_000) - .ok_or(Error::InvalidExchangeRate)?; + let exchange_rate = + FixedU128::checked_from_rational(opts.exchange_rate, 100_000).ok_or(Error::InvalidExchangeRate)?; loop { let exchange_rate = if opts.coingecko { @@ -93,10 +95,19 @@ async fn main() -> Result<(), Error> { chrono::offset::Local::now() ); - match provider.set_exchange_rate_info(exchange_rate).await { - Err(e) => error!("Error: {}", e.to_string()), - _ => (), - }; + let result = PolkaBtcProvider::from_url_with_retry( + &opts.polka_btc_url.clone(), + signer.clone(), + Duration::from_millis(opts.connection_timeout_ms), + ) + .await? + .set_exchange_rate_info(exchange_rate) + .await; + + if let Err(e) = result { + error!("Error: {}", e.to_string()); + } + delay_for(timeout).await; } } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index af7574a34..7c836436f 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -1,12 +1,20 @@ [package] name = "runtime" -version = "0.3.0" +version = "0.5.0" authors = ["Interlay "] edition = "2018" [features] default = [] -testing-utils = ["substrate-subxt-client", "tempdir", "btc-parachain", "btc-parachain-service", "bitcoin", "rand"] +testing-utils = [ + "substrate-subxt/client", + "substrate-subxt-client", + "tempdir", + "btc-parachain", + "btc-parachain-service", + "bitcoin", + "rand", +] [dependencies] parity-scale-codec = "2.0.0" @@ -15,10 +23,10 @@ thiserror = "1.0" serde_json = "1.0.57" serde = "1.0.116" tokio = { version = "0.2.22", features = ["full"] } -jsonrpsee = "0.1.0" futures = "0.3.5" clap = "3.0.0-beta.2" log = "0.4.0" +url = "2" # Substrate dependencies sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } @@ -30,85 +38,92 @@ frame-support = { git = "https://github.com/paritytech/substrate", branch = "roc frame-system = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } # Subxt dependencies -substrate-subxt-proc-macro = { git = "https://github.com/interlay/substrate-subxt", rev = "9ef6ed9" } -substrate-subxt = { git = "https://github.com/interlay/substrate-subxt", rev = "9ef6ed9" } +substrate-subxt-proc-macro = { git = "https://github.com/interlay/substrate-subxt", rev = "0283aa0" } +substrate-subxt = { git = "https://github.com/interlay/substrate-subxt", rev = "0283aa0" } + +jsonrpsee-types = { git = "https://github.com/interlay/jsonrpsee", rev = "1c2ba33" } +jsonrpsee-ws-client = { git = "https://github.com/interlay/jsonrpsee", rev = "1c2ba33" } + +# Polkadot dependencies +xcm = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1" } +parachain = { package = "polkadot-parachain", git = "https://github.com/paritytech/polkadot", branch = "rococo-v1" } # Dependencies for the testing utils for integration tests -substrate-subxt-client = { git = "https://github.com/interlay/substrate-subxt", rev = "9ef6ed9", optional = true } +substrate-subxt-client = { git = "https://github.com/interlay/substrate-subxt", rev = "0283aa0", optional = true } tempdir = {version = "0.3.7", optional = true } -btc-parachain = { git = "https://gitlab.com/interlay/btc-parachain", branch = "dev", version = "0.5.0", features = ["aura-grandpa"], optional = true } -btc-parachain-service = { git = "https://gitlab.com/interlay/btc-parachain", branch = "dev", version = "0.5.1", features = ["aura-grandpa"], optional = true } +btc-parachain = { git = "https://github.com/interlay/btc-parachain", branch = "master", version = "0.5.0", features = ["aura-grandpa"], optional = true } +btc-parachain-service = { git = "https://github.com/interlay/btc-parachain", branch = "master", version = "0.5.1", features = ["aura-grandpa"], optional = true } bitcoin = { path = "../bitcoin", optional = true } rand = { version = "0.7", optional = true } [dependencies.module-bitcoin] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "bitcoin" [dependencies.module-refund] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "refund" [dependencies.module-btc-relay] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "btc-relay" [dependencies.module-security] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "security" [dependencies.module-staked-relayers] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "staked-relayers" [dependencies.module-vault-registry] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "vault-registry" [dependencies.module-exchange-rate-oracle-rpc-runtime-api] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "module-exchange-rate-oracle-rpc-runtime-api" [dependencies.module-issue] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "issue" [dependencies.module-redeem] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "redeem" [dependencies.module-replace] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "replace" [dependencies.module-exchange-rate-oracle] -git = "https://gitlab.com/interlay/btc-parachain" -branch = "dev" +git = "https://github.com/interlay/btc-parachain" +branch = "master" version = "0.5.0" package = "exchange-rate-oracle" [dev-dependencies] -substrate-subxt-client = { git = "https://github.com/interlay/substrate-subxt", rev = "9ef6ed9" } +substrate-subxt-client = { git = "https://github.com/interlay/substrate-subxt", rev = "0283aa0" } +btc-parachain = { git = "https://github.com/interlay/btc-parachain", branch = "master", version = "0.5.0", features = ["aura-grandpa"] } +btc-parachain-service = { git = "https://github.com/interlay/btc-parachain", branch = "master", version = "0.5.0", features = ["aura-grandpa"] } tempdir = "0.3.7" -btc-parachain = { git = "https://gitlab.com/interlay/btc-parachain", branch = "dev", version = "0.5.0", features = ["aura-grandpa"] } -btc-parachain-service = { git = "https://gitlab.com/interlay/btc-parachain", branch = "dev", version = "0.5.0", features = ["aura-grandpa"] } diff --git a/runtime/src/cli.rs b/runtime/src/cli.rs index b0b150032..e627a4f1d 100644 --- a/runtime/src/cli.rs +++ b/runtime/src/cli.rs @@ -1,10 +1,12 @@ -use crate::error::{Error, KeyLoadingError}; -use clap::Clap; +use crate::{ + error::{Error, KeyLoadingError}, + ConnectionManagerConfig, RestartPolicy, +}; -use sp_core::sr25519::Pair; -use sp_core::Pair as _; +use clap::Clap; +use sp_core::{sr25519::Pair, Pair as _}; use sp_keyring::AccountKeyring; -use std::collections::HashMap; +use std::{collections::HashMap, time::Duration}; #[derive(Clap, Debug, Clone)] pub struct ProviderUserOpts { @@ -27,12 +29,10 @@ impl ProviderUserOpts { /// Get the key pair and the username, the latter of which is used for wallet selection. pub fn get_key_pair(&self) -> Result<(Pair, String), Error> { // load parachain credentials - let (pair, user_name) = match (self.keyfile.as_ref(), self.keyname.as_ref(), &self.keyring) - { - (Some(file_path), Some(keyname), None) => ( - get_credentials_from_file(&file_path, &keyname)?, - keyname.to_string(), - ), + let (pair, user_name) = match (self.keyfile.as_ref(), self.keyname.as_ref(), &self.keyring) { + (Some(file_path), Some(keyname), None) => { + (get_credentials_from_file(&file_path, &keyname)?, keyname.to_string()) + } (None, None, Some(keyring)) => (keyring.pair(), format!("{}", keyring)), _ => panic!("Invalid arguments"), // should never occur, due to clap constraints }; @@ -51,7 +51,40 @@ fn get_credentials_from_file(file_path: &str, keyname: &str) -> Result = serde_json::from_reader(reader)?; let pair_str = map.get(keyname).ok_or(KeyLoadingError::KeyNotFound)?; - let pair = - Pair::from_string(pair_str, None).map_err(|e| KeyLoadingError::SecretStringError(e))?; + let pair = Pair::from_string(pair_str, None).map_err(|e| KeyLoadingError::SecretStringError(e))?; Ok(pair) } + +#[derive(Clap, Debug, Clone)] +pub struct ConnectionOpts { + /// Parachain websocket URL. + #[clap(long, default_value = "ws://127.0.0.1:9944")] + pub polka_btc_url: String, + + /// Timeout in milliseconds to wait for connection to btc-parachain. + #[clap(long, default_value = "60000")] + pub polka_btc_connection_timeout_ms: u64, + + /// What to do if the connection to the btc-parachain drops. + #[clap(long, default_value = "always")] + pub restart_policy: RestartPolicy, + + /// Maximum number of concurrent requests + #[clap(long)] + pub max_concurrent_requests: Option, + + /// Maximum notification capacity for each subscription + #[clap(long)] + pub max_notifs_per_subscription: Option, +} + +impl Into for ConnectionOpts { + fn into(self) -> ConnectionManagerConfig { + ConnectionManagerConfig { + connection_timeout: Duration::from_millis(self.polka_btc_connection_timeout_ms), + restart_policy: self.restart_policy, + max_concurrent_requests: self.max_concurrent_requests, + max_notifs_per_subscription: self.max_notifs_per_subscription, + } + } +} diff --git a/runtime/src/conn.rs b/runtime/src/conn.rs new file mode 100644 index 000000000..2e6bbedbb --- /dev/null +++ b/runtime/src/conn.rs @@ -0,0 +1,201 @@ +use crate::{error::JsonRpseeError, Error, PolkaBtcSigner}; +use async_trait::async_trait; +use futures::{Future, FutureExt}; +use jsonrpsee_ws_client::{WsClient, WsConfig}; +use log::{info, trace}; +use std::{marker::PhantomData, str::FromStr, sync::Arc, time::Duration}; +use substrate_subxt::RpcClient; +use tokio::{ + runtime::Handle, + time::{delay_for, timeout}, +}; + +const RETRY_TIMEOUT: Duration = Duration::from_millis(1000); +const CONNECTION_TIMEOUT: Duration = Duration::from_secs(10); + +pub type ShutdownReceiver = tokio::sync::watch::Receiver>; + +#[async_trait] +pub trait Provider { + async fn connect(rpc_client: T, signer: PolkaBtcSigner) -> Result + where + Self: Sized, + T: Into + Send; +} + +#[async_trait] +pub trait Service { + async fn start(provider: P, config: C, handle: Handle, shutdown: ShutdownReceiver) -> Result<(), Error>; +} + +pub(crate) async fn new_websocket_client( + url: &String, + max_concurrent_requests: Option, + max_notifs_per_subscription: Option, +) -> Result { + let parsed_url = url::Url::parse(&url)?; + let path = parsed_url.path(); + let config = WsConfig { + url, + max_request_body_size: 10 * 1024 * 1024, + request_timeout: None, + connection_timeout: CONNECTION_TIMEOUT, + origin: None, + handshake_url: path.into(), + max_concurrent_requests: max_concurrent_requests.unwrap_or(256), + max_notifs_per_subscription: max_notifs_per_subscription.unwrap_or(128), + }; + Ok(WsClient::new(config).await?) +} + +pub(crate) async fn new_websocket_client_with_retry( + url: &String, + max_concurrent_requests: Option, + max_notifs_per_subscription: Option, + connection_timeout: Duration, +) -> Result { + info!("Connecting to the btc-parachain..."); + timeout(connection_timeout, async move { + loop { + match new_websocket_client(url, max_concurrent_requests, max_notifs_per_subscription).await { + Err(Error::JsonRpseeError(JsonRpseeError::TransportError(err))) => { + trace!("could not connect to parachain: {}", err); + delay_for(RETRY_TIMEOUT).await; + continue; + } + Ok(rpc) => { + info!("Connected!"); + return Ok(rpc); + } + Err(err) => return Err(err), + } + } + }) + .await? +} + +#[derive(Clone, Debug)] +pub enum RestartPolicy { + Never, + Always, +} + +impl FromStr for RestartPolicy { + type Err = String; + fn from_str(code: &str) -> Result { + match code { + "never" => Ok(RestartPolicy::Never), + "always" => Ok(RestartPolicy::Always), + _ => Err("Could not parse input as RestartPolicy".to_string()), + } + } +} + +/// Connection settings for the service +pub struct ManagerConfig { + /// Fail to connect to server if elapsed + pub connection_timeout: Duration, + /// Whether to restart the client + pub restart_policy: RestartPolicy, + /// Maximum number of concurrent requests + pub max_concurrent_requests: Option, + /// Maximum notification capacity for each subscription + pub max_notifs_per_subscription: Option, +} + +pub struct Manager> { + url: String, + signer: PolkaBtcSigner, + service_config: C, + manager_config: ManagerConfig, + handle: Handle, + _marker: PhantomData<(P, S)>, +} + +impl> Manager { + pub fn new( + url: String, + signer: PolkaBtcSigner, + service_config: C, + manager_config: ManagerConfig, + handle: Handle, + ) -> Self { + Self { + url, + signer, + service_config, + manager_config, + handle, + _marker: PhantomData::default(), + } + } + + pub async fn start(&self) -> Result<(), Error> { + loop { + let ws_client = new_websocket_client_with_retry( + &self.url, + self.manager_config.max_concurrent_requests, + self.manager_config.max_notifs_per_subscription, + self.manager_config.connection_timeout, + ) + .await?; + let ws_client = Arc::new(ws_client); + + let signer = self.signer.clone(); + let config = self.service_config.clone(); + let handle = self.handle.clone(); + + let (shutdown_sender, shutdown_receiver) = tokio::sync::watch::channel(None); + let wait_for_shutdown = is_connected(ws_client.clone()); + + // run service and shutdown listener to terminate child + // processes if the websocket client disconnects + let _ = tokio::join! { + async move { + // TODO: propogate shutdown signal from children + wait_for_shutdown.await; + // signal shutdown to child processes + let _ = shutdown_sender.broadcast(Some(())); + }, + async move { + let provider = P::connect(ws_client, signer).await?; + let _ = S::start(provider, config, handle, shutdown_receiver).await; + Ok::<(), Error>(()) + } + }; + + info!("Disconnected"); + + match self.manager_config.restart_policy { + RestartPolicy::Never => return Err(Error::ChannelClosed), + RestartPolicy::Always => continue, + }; + } + } +} + +async fn is_connected(client: Arc) { + while client.is_connected() { + delay_for(Duration::from_millis(500)).await; + } +} + +pub async fn wait_or_shutdown(mut shutdown: ShutdownReceiver, future2: impl Future) { + let future1 = async move { while let Some(None) = shutdown.recv().await {} }.fuse(); + let future2 = future2.fuse(); + + futures::pin_mut!(future1); + futures::pin_mut!(future2); + + let _ = futures::select! { + _ = future1 => (), + _ = future2 => (), + }; +} + +pub async fn on_shutdown(mut shutdown: ShutdownReceiver, future2: impl Future) { + let future1 = async move { while let Some(None) = shutdown.recv().await {} }.fuse(); + + future1.await; + future2.await; +} diff --git a/runtime/src/error.rs b/runtime/src/error.rs index fe23e2740..60b2751c6 100644 --- a/runtime/src/error.rs +++ b/runtime/src/error.rs @@ -1,12 +1,14 @@ -use jsonrpsee::{client::RequestError as JsonRPSeeError, transport::ws::WsNewDnsError}; +pub use jsonrpsee_types::error::Error as JsonRpseeError; +pub use substrate_subxt::Error as XtError; + +use jsonrpsee_ws_client::transport::WsConnectError; use parity_scale_codec::Error as CodecError; use serde_json::Error as SerdeJsonError; use sp_core::crypto::SecretStringError; -use std::array::TryFromSliceError; -use std::io::Error as IoError; -use std::num::TryFromIntError; -pub use substrate_subxt::Error as XtError; +use std::{array::TryFromSliceError, io::Error as IoError, num::TryFromIntError}; use thiserror::Error; +use tokio::time::Elapsed; +use url::ParseError as UrlParseError; #[derive(Error, Debug)] pub enum Error { @@ -22,13 +24,17 @@ pub enum Error { BlockNotFound, #[error("Could not get vault")] VaultNotFound, + #[error("Vault has been liquidated")] + VaultLiquidated, + #[error("Vault has stolen BTC")] + VaultCommittedTheft, + #[error("Channel closed unexpectedly")] + ChannelClosed, + #[error("Callback error: {0}")] CallbackError(Box), - #[error("Failed to load credentials from file: {0}")] KeyLoadingFailure(#[from] KeyLoadingError), - #[error("Channel unexpectedly closed")] - ChannelClosed, #[error("Error serializing: {0}")] Serialize(#[from] TryFromSliceError), #[error("Error converting: {0}")] @@ -40,10 +46,14 @@ pub enum Error { #[error("Error encoding json data: {0}")] SerdeJsonError(#[from] SerdeJsonError), #[error("Error getting json-rpsee data: {0}")] - JsonRPSeeError(#[from] JsonRPSeeError), + JsonRpseeError(#[from] JsonRpseeError), /// Occurs during websocket handshake #[error("Rpc error: {0}")] - WsHandshake(#[from] WsNewDnsError), + WsConnectError(#[from] WsConnectError), + #[error("Timeout: {0}")] + TimeElapsed(#[from] Elapsed), + #[error("UrlParseError: {0}")] + UrlParseError(#[from] UrlParseError), } #[derive(Error, Debug)] diff --git a/runtime/src/integration/bitcoin_simulator.rs b/runtime/src/integration/bitcoin_simulator.rs index c9194ab2a..a1c5b1cac 100644 --- a/runtime/src/integration/bitcoin_simulator.rs +++ b/runtime/src/integration/bitcoin_simulator.rs @@ -6,37 +6,38 @@ use crate::{BtcAddress, BtcRelayPallet, PolkaBtcProvider}; use async_trait::async_trait; use bitcoin::{ secp256k1::{rand::rngs::OsRng, PublicKey, Secp256k1, SecretKey}, - serialize, BitcoinCoreApi, Block, BlockHash, BlockHeader, Error as BitcoinError, - GetBlockResult, Hash, LockedTransaction, Network, OutPoint, PartialAddress, PartialMerkleTree, - Script, Transaction, TransactionMetadata, TxIn, TxOut, Txid, Uint256, PUBLIC_KEY_SIZE, + serialize, BitcoinCoreApi, Block, BlockHash, BlockHeader, Error as BitcoinError, GetBlockResult, Hash, + LockedTransaction, Network, OutPoint, PartialAddress, PartialMerkleTree, Script, Transaction, TransactionMetadata, + TxIn, TxOut, Txid, Uint256, PUBLIC_KEY_SIZE, }; use rand::{thread_rng, Rng}; use sp_core::{H160, H256, U256}; -use std::convert::TryInto; -use std::sync::Arc; -use std::time::Duration; -use tokio::sync::{Mutex, RwLock}; -use tokio::time::delay_for; +use std::{convert::TryInto, sync::Arc, time::Duration}; +use tokio::{ + sync::{Mutex, RwLock}, + time::delay_for, +}; /// A simulated bitcoin-core interface. It combines the roles of bitcoin-core and the /// staked relayer: it automatically relays the generated transactions to the parachain. /// It does the minimum amount of work it can get away with, and the relayed data may /// be technically invalid. For example, all generated transactions share the same dummy /// input uxto. +#[derive(Clone)] pub struct MockBitcoinCore { - provider: Arc, - blocks: RwLock>, - mempool: RwLock>, + provider: PolkaBtcProvider, + blocks: Arc>>, + mempool: Arc>>, transaction_creation_lock: Arc>, } impl MockBitcoinCore { /// Creates a new instance, and initializes parachain's btc-relay - pub async fn new(provider: Arc) -> Self { + pub async fn new(provider: PolkaBtcProvider) -> Self { let ret = Self { provider, - blocks: RwLock::new(vec![]), - mempool: RwLock::new(vec![]), + blocks: Arc::new(RwLock::new(vec![])), + mempool: Arc::new(RwLock::new(vec![])), transaction_creation_lock: Arc::new(Mutex::new(())), }; @@ -54,11 +55,11 @@ impl MockBitcoinCore { } /// Creates a new instance, but does not initializes parachain's btc-relay - pub async fn new_uninitialized(provider: Arc) -> Self { + pub async fn new_uninitialized(provider: PolkaBtcProvider) -> Self { Self { provider, - blocks: RwLock::new(vec![]), - mempool: RwLock::new(vec![]), + blocks: Arc::new(RwLock::new(vec![])), + mempool: Arc::new(RwLock::new(vec![])), transaction_creation_lock: Arc::new(Mutex::new(())), } } @@ -117,12 +118,8 @@ impl MockBitcoinCore { block } - fn generate_normal_transaction( - address: &A, - reward: u64, - ) -> Transaction { - let address: BtcAddress = - BtcAddress::decode_str(&address.encode_str(Network::Regtest).unwrap()).unwrap(); + fn generate_normal_transaction(address: &A, reward: u64) -> Transaction { + let address: BtcAddress = BtcAddress::decode_str(&address.encode_str(Network::Regtest).unwrap()).unwrap(); let address = Script::from(address.to_script().as_bytes().to_vec()); Transaction { @@ -138,15 +135,13 @@ impl MockBitcoinCore { // actual contents of don't script_sig don't really matter as long as it contains // a parsable script script_sig: Script::from(vec![ - 0, 71, 48, 68, 2, 32, 91, 128, 41, 150, 96, 53, 187, 63, 230, 129, 53, 234, - 210, 186, 21, 187, 98, 38, 255, 112, 30, 27, 228, 29, 132, 140, 155, 62, 123, - 216, 232, 168, 2, 32, 72, 126, 179, 207, 142, 8, 99, 8, 32, 78, 244, 166, 106, - 160, 207, 227, 61, 210, 172, 234, 234, 93, 59, 159, 79, 12, 194, 240, 212, 3, - 120, 50, 1, 71, 81, 33, 3, 113, 209, 131, 177, 9, 29, 242, 229, 15, 217, 247, - 165, 78, 111, 80, 79, 50, 200, 117, 80, 30, 233, 210, 167, 133, 175, 62, 253, - 134, 127, 212, 51, 33, 2, 128, 200, 184, 235, 148, 25, 43, 34, 28, 173, 55, 54, - 189, 164, 187, 243, 243, 152, 7, 84, 210, 85, 156, 238, 77, 97, 188, 240, 162, - 197, 105, 62, 82, 174, + 0, 71, 48, 68, 2, 32, 91, 128, 41, 150, 96, 53, 187, 63, 230, 129, 53, 234, 210, 186, 21, 187, 98, + 38, 255, 112, 30, 27, 228, 29, 132, 140, 155, 62, 123, 216, 232, 168, 2, 32, 72, 126, 179, 207, + 142, 8, 99, 8, 32, 78, 244, 166, 106, 160, 207, 227, 61, 210, 172, 234, 234, 93, 59, 159, 79, 12, + 194, 240, 212, 3, 120, 50, 1, 71, 81, 33, 3, 113, 209, 131, 177, 9, 29, 242, 229, 15, 217, 247, + 165, 78, 111, 80, 79, 50, 200, 117, 80, 30, 233, 210, 167, 133, 175, 62, 253, 134, 127, 212, 51, + 33, 2, 128, 200, 184, 235, 148, 25, 43, 34, 28, 173, 55, 54, 189, 164, 187, 243, 243, 152, 7, 84, + 210, 85, 156, 238, 77, 97, 188, 240, 162, 197, 105, 62, 82, 174, ]), // not checked sequence: 0, @@ -160,11 +155,7 @@ impl MockBitcoinCore { } } - fn generate_coinbase_transaction( - address: &BtcAddress, - reward: u64, - height: u32, - ) -> Transaction { + fn generate_coinbase_transaction(address: &BtcAddress, reward: u64, height: u32) -> Transaction { let address = Script::from(address.to_script().as_bytes().to_vec()); // note that we set lock_time to height, otherwise we might generate blocks with @@ -219,11 +210,7 @@ impl BitcoinCoreApi for MockBitcoinCore { async fn get_block_count(&self) -> Result { Ok((self.blocks.read().await.len() - 1).try_into().unwrap()) } - async fn get_raw_tx_for( - &self, - txid: &Txid, - _block_hash: &BlockHash, - ) -> Result, BitcoinError> { + async fn get_raw_tx_for(&self, txid: &Txid, _block_hash: &BlockHash) -> Result, BitcoinError> { let blocks = self.blocks.read().await; let transaction = blocks @@ -233,11 +220,7 @@ impl BitcoinCoreApi for MockBitcoinCore { Ok(serialize(transaction)) } - async fn get_proof_for( - &self, - txid: Txid, - _block_hash: &BlockHash, - ) -> Result, BitcoinError> { + async fn get_proof_for(&self, txid: Txid, _block_hash: &BlockHash) -> Result, BitcoinError> { let mut proof = Vec::new(); let blocks = self.blocks.read().await; @@ -256,20 +239,13 @@ impl BitcoinCoreApi for MockBitcoinCore { Ok(proof) } - async fn get_block_hash_for(&self, height: u32) -> Result { + async fn get_block_hash(&self, height: u32) -> Result { let blocks = self.blocks.read().await; - let block = blocks - .get(height as usize) - .ok_or(BitcoinError::InvalidBitcoinHeight)?; + let block = blocks.get(height as usize).ok_or(BitcoinError::InvalidBitcoinHeight)?; Ok(block.header.block_hash()) } async fn is_block_known(&self, block_hash: BlockHash) -> Result { - Ok(self - .blocks - .read() - .await - .iter() - .any(|x| x.block_hash() == block_hash)) + Ok(self.blocks.read().await.iter().any(|x| x.block_hash() == block_hash)) } async fn get_new_address(&self) -> Result { let bytes: [u8; 20] = (0..20) @@ -281,9 +257,7 @@ impl BitcoinCoreApi for MockBitcoinCore { let address = BtcAddress::P2PKH(H160::from(bytes)); Ok(A::decode_str(&address.encode_str(Network::Regtest)?)?) } - async fn get_new_public_key + 'static>( - &self, - ) -> Result { + async fn get_new_public_key + 'static>(&self) -> Result { let secp = Secp256k1::new(); let mut rng = OsRng::new().unwrap(); let secret_key = SecretKey::new(&mut rng); @@ -309,6 +283,14 @@ impl BitcoinCoreApi for MockBitcoinCore { .ok_or(BitcoinError::InvalidBitcoinHeight)?; Ok(block.clone()) } + async fn get_block_header(&self, hash: &BlockHash) -> Result { + let blocks = self.blocks.read().await; + let block = blocks + .iter() + .find(|x| &x.block_hash() == hash) + .ok_or(BitcoinError::InvalidBitcoinHeight)?; + Ok(block.header.clone()) + } async fn get_block_info(&self, hash: &BlockHash) -> Result { let blocks = self.blocks.read().await; @@ -340,9 +322,8 @@ impl BitcoinCoreApi for MockBitcoinCore { }) } async fn get_mempool_transactions<'a>( - self: Arc, - ) -> Result> + Send + 'a>, BitcoinError> - { + self: &'a Self, + ) -> Result> + Send + 'a>, BitcoinError> { let transactions = (*self.mempool.read().await).clone(); Ok(Box::new(transactions.into_iter().map(|x| Ok(x)))) } @@ -356,11 +337,7 @@ impl BitcoinCoreApi for MockBitcoinCore { // we have to be careful not to deadlock, so limit the scope of the lock let blocks = (*self.blocks.read().await).clone(); - if let Some(x) = blocks - .iter() - .enumerate() - .find(|x| x.1.txdata[1].txid() == txid) - { + if let Some(x) = blocks.iter().enumerate().find(|x| x.1.txdata[1].txid() == txid) { break (x.0, x.1.clone()); } tokio::time::delay_for(Duration::from_secs(1)).await; @@ -398,13 +375,11 @@ impl BitcoinCoreApi for MockBitcoinCore { Ok(LockedTransaction::new( transaction, - self.transaction_creation_lock.clone().lock_owned().await, + Some(self.transaction_creation_lock.clone().lock_owned().await), )) } async fn send_transaction(&self, transaction: LockedTransaction) -> Result { - let block = self - .generate_block_with_transaction(&transaction.transaction) - .await; + let block = self.generate_block_with_transaction(&transaction.transaction).await; self.send_block(block.clone()).await; Ok(transaction.transaction.txid()) } @@ -441,13 +416,7 @@ impl BitcoinCoreApi for MockBitcoinCore { } async fn wallet_has_public_key

(&self, _public_key: P) -> Result where - P: Into<[u8; PUBLIC_KEY_SIZE]> - + From<[u8; PUBLIC_KEY_SIZE]> - + Clone - + PartialEq - + Send - + Sync - + 'static, + P: Into<[u8; PUBLIC_KEY_SIZE]> + From<[u8; PUBLIC_KEY_SIZE]> + Clone + PartialEq + Send + Sync + 'static, { Ok(true) } diff --git a/runtime/src/integration/mod.rs b/runtime/src/integration/mod.rs index 26ebf28ff..d657b1032 100644 --- a/runtime/src/integration/mod.rs +++ b/runtime/src/integration/mod.rs @@ -1,25 +1,19 @@ +#![cfg(feature = "testing-utils")] + mod bitcoin_simulator; -use crate::rpc::FeePallet; -use crate::rpc::IssuePallet; -use crate::rpc::VaultRegistryPallet; -use crate::AccountId; -use crate::H256Le; -use crate::PolkaBtcProvider; -use crate::PolkaBtcRuntime; -use bitcoin::BitcoinCoreApi; -use bitcoin::BlockHash; -use bitcoin::Txid; +use crate::{ + rpc::{FeePallet, IssuePallet, VaultRegistryPallet}, + AccountId, H256Le, PolkaBtcProvider, PolkaBtcRuntime, +}; +use bitcoin::{BitcoinCoreApi, BlockHash, Txid}; use futures::{future::Either, pin_mut, Future, FutureExt, SinkExt, StreamExt}; -use jsonrpsee::Client as JsonRpseeClient; use sp_keyring::AccountKeyring; use sp_runtime::FixedPointNumber; -use std::sync::Arc; use std::time::Duration; -use substrate_subxt::Event; -use substrate_subxt::PairSigner; +use substrate_subxt::{Event, PairSigner}; use substrate_subxt_client::{ - DatabaseConfig, KeystoreConfig, Role, SubxtClient, SubxtClientConfig, + DatabaseConfig, KeystoreConfig, Role, SubxtClient, SubxtClientConfig, WasmExecutionMethod, }; use tempdir::TempDir; use tokio::time::timeout; @@ -50,7 +44,7 @@ impl Translate for BlockHash { /// Start a new instance of the parachain. The second item in the returned tuple must remain in /// scope as long as the parachain is active, since dropping it will remove the temporary directory /// that the parachain uses -pub async fn default_provider_client(key: AccountKeyring) -> (JsonRpseeClient, TempDir) { +pub async fn default_provider_client(key: AccountKeyring) -> (SubxtClient, TempDir) { let tmp = TempDir::new("btc-parachain-").expect("failed to create tempdir"); let config = SubxtClientConfig { impl_name: "btc-parachain-full-client", @@ -67,6 +61,7 @@ pub async fn default_provider_client(key: AccountKeyring) -> (JsonRpseeClient, T chain_spec: btc_parachain::chain_spec::development_config(), role: Role::Authority(key.clone()), telemetry: None, + wasm_method: WasmExecutionMethod::Compiled, }; let client = SubxtClient::from_config(config, btc_parachain_service::new_full) @@ -76,25 +71,16 @@ pub async fn default_provider_client(key: AccountKeyring) -> (JsonRpseeClient, T } /// Create a new provider with the given keyring -pub async fn setup_provider(client: JsonRpseeClient, key: AccountKeyring) -> Arc { +pub async fn setup_provider(client: SubxtClient, key: AccountKeyring) -> PolkaBtcProvider { let signer = PairSigner::::new(key.pair()); - let ret = PolkaBtcProvider::new(client, signer) + PolkaBtcProvider::new(client, signer) .await - .expect("Error creating provider"); - Arc::new(ret) + .expect("Error creating provider") } /// request, pay and execute an issue -pub async fn assert_issue( - provider: &PolkaBtcProvider, - btc_rpc: &MockBitcoinCore, - vault_id: &AccountId, - amount: u128, -) { - let issue = provider - .request_issue(amount, vault_id.clone(), 10000) - .await - .unwrap(); +pub async fn assert_issue(provider: &PolkaBtcProvider, btc_rpc: &MockBitcoinCore, vault_id: &AccountId, amount: u128) { + let issue = provider.request_issue(amount, vault_id.clone(), 10000).await.unwrap(); let metadata = btc_rpc .send_to_address( @@ -119,10 +105,7 @@ pub async fn assert_issue( } /// calculate how much collateral the vault requires to accept an issue of the given size -pub async fn get_required_vault_collateral_for_issue( - provider: &PolkaBtcProvider, - amount: u128, -) -> u128 { +pub async fn get_required_vault_collateral_for_issue(provider: &PolkaBtcProvider, amount: u128) -> u128 { let fee = provider.get_issue_fee().await.unwrap(); let amount_btc_including_fee = amount + fee.checked_mul_int(amount).unwrap(); provider @@ -132,7 +115,7 @@ pub async fn get_required_vault_collateral_for_issue( } /// wait for an event to occur. After the specified error, this will panic. This returns the event. -pub async fn assert_event(duration: Duration, provider: Arc, f: F) -> T +pub async fn assert_event(duration: Duration, provider: PolkaBtcProvider, f: F) -> T where T: Event + Clone + std::fmt::Debug, F: Fn(T) -> bool, diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 25601137c..0e4fad18d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1,7 +1,10 @@ pub mod cli; -mod error; pub mod pallets; + +mod conn; +mod error; mod rpc; +mod types; #[cfg(test)] mod tests; @@ -10,39 +13,52 @@ mod tests; pub mod integration; pub use btc_relay::{ - BitcoinBlockHeight, BlockBuilder, BtcAddress, BtcPublicKey, Formattable, H256Le, - RawBlockHeader, RichBlockHeader, + BitcoinBlockHeight, BlockBuilder, BtcAddress, BtcPublicKey, Formattable, H256Le, RawBlockHeader, RichBlockHeader, +}; +pub use conn::{ + on_shutdown, wait_or_shutdown, Manager as ConnectionManager, ManagerConfig as ConnectionManagerConfig, Provider, + RestartPolicy, Service, ShutdownReceiver, }; pub use error::{Error, XtError}; -use pallets::*; pub use rpc::{ - AccountId, BtcRelayPallet, BtcTxFeesPerByte, DotBalancesPallet, ExchangeRateOraclePallet, - FeePallet, IssuePallet, PolkaBtcHeader, PolkaBtcIssueRequest, PolkaBtcProvider, - PolkaBtcRedeemRequest, PolkaBtcRefundRequest, PolkaBtcReplaceRequest, - PolkaBtcRequestIssueEvent, PolkaBtcStatusUpdate, PolkaBtcVault, RedeemPallet, RefundPallet, - ReplacePallet, SecurityPallet, StakedRelayerPallet, TimestampPallet, UtilFuncs, - VaultRegistryPallet, + BtcRelayPallet, BtcTxFeesPerByte, DotBalancesPallet, ExchangeRateOraclePallet, FeePallet, IssuePallet, + PolkaBtcProvider, RedeemPallet, RefundPallet, ReplacePallet, SecurityPallet, StakedRelayerPallet, TimestampPallet, + UtilFuncs, VaultRegistryPallet, }; pub use security::{ErrorCode, StatusCode}; pub use sp_arithmetic::{traits as FixedPointTraits, FixedI128, FixedPointNumber, FixedU128}; -use sp_core::{H160, H256}; pub use sp_runtime; +pub use substrate_subxt; +pub use types::*; +pub use vault_registry::VaultStatus; + +use pallets::*; +use sp_core::{H160, H256}; use sp_runtime::{ generic::Header, traits::{BlakeTwo256, IdentifyAccount, Verify}, MultiSignature, OpaqueExtrinsic, }; use std::collections::BTreeSet; -pub use substrate_subxt; -use substrate_subxt::register_default_type_sizes; -use substrate_subxt::system::SystemEventTypeRegistry; -use substrate_subxt::EventTypeRegistry; -use substrate_subxt::{balances, extrinsic::DefaultExtra, sudo, system, Runtime}; +use substrate_subxt::{ + balances, extrinsic::DefaultExtra, register_default_type_sizes, sudo, system, system::SystemEventTypeRegistry, + EventTypeRegistry, Runtime, +}; + +// cumulus / polkadot types +use parachain::primitives::{Id as ParaId, RelayChainBlockNumber}; +use xcm::v0::{Error as XcmError, NetworkId}; pub const MINIMUM_STAKE: u128 = 100; pub const TX_FEES: u128 = 2000000000; pub const PLANCK_PER_DOT: u128 = 10000000000; +pub const MILLISECS_PER_BLOCK: u64 = 6000; + +// These time units are defined in number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; + pub type Balance = u128; #[derive(Debug, Clone, Eq, PartialEq)] @@ -59,13 +75,19 @@ impl Runtime for PolkaBtcRuntime { } } +/// An index to a block. +pub type BlockNumber = u32; + +/// Some way of identifying an account on the chain. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + // TODO: use types from actual runtime impl system::System for PolkaBtcRuntime { type Index = u32; - type BlockNumber = u32; - type Hash = sp_core::H256; + type BlockNumber = BlockNumber; + type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = <::Signer as IdentifyAccount>::AccountId; + type AccountId = AccountId; type Address = Self::AccountId; type Header = Header; type Extrinsic = OpaqueExtrinsic; @@ -77,7 +99,7 @@ impl pallets::Core for PolkaBtcRuntime { type DOT = Balance; type PolkaBTC = Balance; type BTCBalance = Balance; - type RichBlockHeader = RichBlockHeader; + type RichBlockHeader = RichBlockHeader; type H256Le = H256Le; type H160 = H160; type H256 = H256; @@ -89,6 +111,13 @@ impl pallets::Core for PolkaBtcRuntime { type StatusUpdateId = u64; type SignedFixedPoint = FixedI128; type UnsignedFixedPoint = FixedU128; + type VaultStatus = VaultStatus; + + // cumulus / polkadot types + type XcmError = XcmError; + type NetworkId = NetworkId; + type RelayChainBlockNumber = RelayChainBlockNumber; + type ParaId = ParaId; } impl balances::Balances for PolkaBtcRuntime { @@ -132,3 +161,9 @@ impl fee::Fee for PolkaBtcRuntime {} impl sla::Sla for PolkaBtcRuntime {} impl treasury::Treasury for PolkaBtcRuntime {} + +pub const BTC_RELAY_MODULE: &str = "BTCRelay"; +pub const ISSUE_MODULE: &str = "Issue"; + +pub const DUPLICATE_BLOCK_ERROR: &str = "DuplicateBlock"; +pub const ISSUE_COMPLETED_ERROR: &str = "IssueCompleted"; diff --git a/runtime/src/pallets/balances_dot.rs b/runtime/src/pallets/balances_dot.rs index a1c963d0f..55d271627 100644 --- a/runtime/src/pallets/balances_dot.rs +++ b/runtime/src/pallets/balances_dot.rs @@ -3,8 +3,7 @@ use frame_support::Parameter; use parity_scale_codec::{Codec, Decode, Encode}; use sp_runtime::traits::{AtLeast32Bit, MaybeSerialize, Member}; use std::fmt::Debug; -use substrate_subxt::balances::AccountData; -use substrate_subxt::system::System; +use substrate_subxt::{balances::AccountData, system::System}; use substrate_subxt_proc_macro::{module, Call, Event, Store}; #[module] diff --git a/runtime/src/pallets/btc_relay.rs b/runtime/src/pallets/btc_relay.rs index 7d42e8899..78746a28b 100644 --- a/runtime/src/pallets/btc_relay.rs +++ b/runtime/src/pallets/btc_relay.rs @@ -1,7 +1,7 @@ use super::Core; use core::marker::PhantomData; pub use module_bitcoin::{formatter::Formattable, types::*}; -pub use module_btc_relay::{BtcAddress, BtcPublicKey}; +pub use module_btc_relay::{BtcAddress, BtcPublicKey, RichBlockHeader}; use parity_scale_codec::{Decode, Encode}; use std::fmt::Debug; use substrate_subxt_proc_macro::{module, Call, Event, Store}; @@ -61,6 +61,7 @@ pub struct InitializedEvent { pub _runtime: PhantomData, pub block_height: BitcoinBlockHeight, pub block_header_hash: T::H256Le, + pub account_id: T::AccountId, } #[derive(Clone, Debug, Eq, PartialEq, Event, Decode)] @@ -68,6 +69,7 @@ pub struct StoreMainChainHeaderEvent { pub _runtime: PhantomData, pub block_height: BitcoinBlockHeight, pub block_header_hash: T::H256Le, + pub account_id: T::AccountId, } #[derive(Clone, Debug, Eq, PartialEq, Store, Encode)] diff --git a/runtime/src/pallets/mod.rs b/runtime/src/pallets/mod.rs index ab45e106b..cd9cb5f81 100644 --- a/runtime/src/pallets/mod.rs +++ b/runtime/src/pallets/mod.rs @@ -15,10 +15,14 @@ pub mod timestamp; pub mod treasury; pub mod vault_registry; -pub use btc_relay::{ - BitcoinBlockHeight, BtcAddress, BtcPublicKey, H256Le, RawBlockHeader, RichBlockHeader, -}; +pub use btc_relay::{BitcoinBlockHeight, BtcAddress, BtcPublicKey, H256Le, RawBlockHeader, RichBlockHeader}; +pub use issue::{IssueRequest, RequestIssueEvent}; +pub use redeem::RedeemRequest; +pub use refund::RefundRequest; +pub use replace::ReplaceRequest; pub use security::{ErrorCode, StatusCode}; +pub use staked_relayers::StatusUpdate; +pub use vault_registry::{Vault, VaultStatus}; use parity_scale_codec::{Codec, EncodeLike}; use sp_arithmetic::traits::Saturating; @@ -44,4 +48,11 @@ pub trait Core: System { type StatusUpdateId: Codec + EncodeLike + Member + Default; type SignedFixedPoint: Codec + EncodeLike + Member + Default; type UnsignedFixedPoint: Codec + EncodeLike + Member + Default; + type VaultStatus: Codec + EncodeLike + Default + Send + Sync; + + // cumulus / polkadot types + type XcmError: Codec + EncodeLike + Member; + type NetworkId: Codec + EncodeLike + Member; + type RelayChainBlockNumber: Codec + EncodeLike + Member + Default; + type ParaId: Codec + EncodeLike + Member + Default; } diff --git a/runtime/src/pallets/redeem.rs b/runtime/src/pallets/redeem.rs index 120907184..aefa925db 100644 --- a/runtime/src/pallets/redeem.rs +++ b/runtime/src/pallets/redeem.rs @@ -68,8 +68,14 @@ pub struct RedeemRequestsStore { pub redeem_id: T::H256, } +#[derive(Clone, Debug, Eq, PartialEq, Store, Encode)] +pub struct RedeemPeriodStore { + #[store(returns = T::BlockNumber)] + pub _runtime: PhantomData, +} + #[derive(Clone, Debug, PartialEq, Call, Encode)] pub struct SetRedeemPeriodCall { - pub period: u32, + pub period: T::BlockNumber, pub _runtime: PhantomData, } diff --git a/runtime/src/pallets/replace.rs b/runtime/src/pallets/replace.rs index f5c0d6f12..1cb14692f 100644 --- a/runtime/src/pallets/replace.rs +++ b/runtime/src/pallets/replace.rs @@ -103,7 +103,7 @@ pub struct CancelReplaceEvent { #[derive(Clone, Debug, Eq, PartialEq, Store, Encode)] pub struct ReplacePeriodStore { - #[store(returns = u32)] + #[store(returns = T::BlockNumber)] pub _runtime: PhantomData, } @@ -116,6 +116,6 @@ pub struct ReplaceRequestsStore { #[derive(Clone, Debug, PartialEq, Call, Encode)] pub struct SetReplacePeriodCall { - pub period: u32, + pub period: T::BlockNumber, pub _runtime: PhantomData, } diff --git a/runtime/src/pallets/sla.rs b/runtime/src/pallets/sla.rs index a786b02ad..191860126 100644 --- a/runtime/src/pallets/sla.rs +++ b/runtime/src/pallets/sla.rs @@ -11,10 +11,12 @@ pub trait Sla: Core {} pub struct UpdateVaultSLAEvent { pub vault_id: T::AccountId, pub new_sla: T::SignedFixedPoint, + pub delta_sla: T::SignedFixedPoint, } #[derive(Clone, Debug, Eq, PartialEq, Event, Decode, Serialize)] pub struct UpdateRelayerSLAEvent { pub relayer_id: T::AccountId, pub new_sla: T::SignedFixedPoint, + pub delta_sla: T::SignedFixedPoint, } diff --git a/runtime/src/pallets/staked_relayers.rs b/runtime/src/pallets/staked_relayers.rs index cfc84d375..31368cee4 100644 --- a/runtime/src/pallets/staked_relayers.rs +++ b/runtime/src/pallets/staked_relayers.rs @@ -1,7 +1,9 @@ use super::Core; use core::marker::PhantomData; -pub use module_staked_relayers::types::{StakedRelayer, StatusUpdate}; -pub use module_staked_relayers::Error as StakedRelayersError; +pub use module_staked_relayers::{ + types::{StakedRelayer, StatusUpdate}, + Error as StakedRelayersError, +}; use parity_scale_codec::{Decode, Encode}; use std::fmt::Debug; use substrate_subxt::balances::Balances; diff --git a/runtime/src/pallets/vault_registry.rs b/runtime/src/pallets/vault_registry.rs index f207e67a8..14290d87d 100644 --- a/runtime/src/pallets/vault_registry.rs +++ b/runtime/src/pallets/vault_registry.rs @@ -47,7 +47,7 @@ pub struct WithdrawCollateralEvent { #[derive(Clone, Debug, Eq, PartialEq, Store, Encode)] pub struct VaultsStore { - #[store(returns = Vault)] + #[store(returns = Vault)] pub _runtime: PhantomData, pub account_id: T::AccountId, } diff --git a/runtime/src/rpc.rs b/runtime/src/rpc.rs index 2d5554002..6821a323e 100644 --- a/runtime/src/rpc.rs +++ b/runtime/src/rpc.rs @@ -2,104 +2,50 @@ pub use module_exchange_rate_oracle::BtcTxFeesPerByte; use async_trait::async_trait; use core::marker::PhantomData; -use jsonrpsee::{ - common::{to_value as to_json_value, Params}, - Client as RpcClient, -}; +use futures::{stream::StreamExt, FutureExt, SinkExt}; +use jsonrpsee_types::jsonrpc::{to_value as to_json_value, Params}; use log::trace; use module_exchange_rate_oracle_rpc_runtime_api::BalanceWrapper; use sp_arithmetic::FixedU128; -use sp_core::sr25519::Pair as KeyPair; use sp_core::H256; -use std::collections::BTreeSet; -use std::future::Future; -use std::sync::Arc; -use std::time::Duration; -use substrate_subxt::Error as XtError; +use std::{collections::BTreeSet, future::Future, sync::Arc, time::Duration}; use substrate_subxt::{ - sudo::*, system::System, Call, Client, ClientBuilder, Event, EventSubscription, EventsDecoder, - PairSigner, Signer, + sudo::*, Call, Client as SubxtClient, ClientBuilder as SubxtClientBuilder, Error as XtError, Event, + EventSubscription, EventTypeRegistry, EventsDecoder, RpcClient, Signer, +}; +use tokio::{sync::RwLock, time::delay_for}; + +use crate::{ + balances_dot::*, btc_relay::*, conn::*, exchange_rate_oracle::*, fee::*, issue::*, pallets::Core, redeem::*, + refund::*, replace::*, security::*, staked_relayers::*, timestamp::*, types::*, vault_registry::*, BlockNumber, + Error, PolkaBtcRuntime, }; -use tokio::sync::RwLock; -use tokio::time::delay_for; - -use crate::balances_dot::*; -use crate::btc_relay::*; -use crate::exchange_rate_oracle::*; -use crate::fee::*; -use crate::issue::*; -use crate::pallets::Core; -use crate::redeem::*; -use crate::refund::*; -use crate::replace::*; -use crate::security::*; -use crate::staked_relayers::*; -use crate::timestamp::*; -use crate::vault_registry::*; -use crate::Error; -use crate::PolkaBtcRuntime; -use futures::{stream::StreamExt, SinkExt}; -use substrate_subxt::EventTypeRegistry; - -pub type PolkaBtcHeader = ::Header; - -pub type AccountId = ::AccountId; - -pub type PolkaBtcVault = - Vault::BlockNumber, ::PolkaBTC>; - -pub type PolkaBtcIssueRequest = IssueRequest< - AccountId, - ::BlockNumber, - ::PolkaBTC, - ::DOT, ->; -pub type PolkaBtcRequestIssueEvent = RequestIssueEvent; - -pub type PolkaBtcRedeemRequest = RedeemRequest< - AccountId, - ::BlockNumber, - ::PolkaBTC, - ::DOT, ->; - -pub type PolkaBtcRefundRequest = RefundRequest::PolkaBTC>; - -pub type PolkaBtcReplaceRequest = ReplaceRequest< - AccountId, - ::BlockNumber, - ::PolkaBTC, - ::DOT, ->; - -pub type PolkaBtcStatusUpdate = StatusUpdate< - AccountId, - ::BlockNumber, - ::DOT, ->; #[derive(Clone)] pub struct PolkaBtcProvider { rpc_client: RpcClient, - ext_client: Client, - signer: Arc>>, + ext_client: SubxtClient, + signer: Arc>, account_id: AccountId, } impl PolkaBtcProvider { - pub async fn new>( - rpc_client: P, - signer: PairSigner, - ) -> Result { + pub async fn new>(rpc_client: P, mut signer: PolkaBtcSigner) -> Result { let account_id = signer.account_id().clone(); let rpc_client = rpc_client.into(); - let ext_client = ClientBuilder::::new() + let ext_client = SubxtClientBuilder::::new() .set_client(rpc_client.clone()) .build() .await?; - // there is a race condition on signing - // since we run the relayer in the background + // For getting the nonce, use latest, possibly non-finalized block. + // TODO: we might want to wait until the latest block is actually finalized + // query account info in order to get the nonce value used for communication + let account_info = + crate::frame_system::AccountStoreExt::account(&ext_client, account_id.clone(), Option::::None) + .await?; + signer.set_nonce(account_info.nonce); + Ok(Self { rpc_client, ext_client, @@ -108,27 +54,37 @@ impl PolkaBtcProvider { }) } - pub async fn from_url( - url: String, - signer: PairSigner, + pub async fn from_url(url: &String, signer: PolkaBtcSigner) -> Result { + let ws_client = new_websocket_client(url, None, None).await?; + Self::new(ws_client, signer).await + } + + pub async fn from_url_with_retry( + url: &String, + signer: PolkaBtcSigner, + connection_timeout: Duration, ) -> Result { - let rpc_client = if url.starts_with("ws://") || url.starts_with("wss://") { - jsonrpsee::ws_client(&url).await? - } else { - jsonrpsee::http_client(&url) - }; + let ws_client = new_websocket_client_with_retry(url, None, None, connection_timeout).await?; + Self::new(ws_client, signer).await + } - Self::new(rpc_client, signer).await + /// Gets a copy of the signer with a unique nonce + async fn get_unique_signer(&self) -> PolkaBtcSigner { + // TODO: refresh from account store + let mut signer = self.signer.write().await; + // return the current value, increment afterwards + let ret = signer.clone(); + signer.increment_nonce(); + ret } - /// Fetch all active vaults. - pub async fn get_all_vaults(&self) -> Result, Error> { - let mut vaults = Vec::new(); - let mut iter = self.ext_client.vaults_iter(None).await?; - while let Some((_, account)) = iter.next().await? { - vaults.push(account); - } - Ok(vaults) + pub async fn get_latest_block_hash(&self) -> Result, Error> { + Ok(Some(self.ext_client.finalized_head().await?)) + } + + pub async fn get_latest_block(&self) -> Result, Error> { + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.block::(head).await?) } /// Subscribe to new parachain blocks. @@ -139,7 +95,7 @@ impl PolkaBtcProvider { { let mut sub = self.ext_client.subscribe_finalized_blocks().await?; loop { - on_block(sub.next().await).await?; + on_block(sub.next().await.ok_or(Error::ChannelClosed)?).await?; } } @@ -150,11 +106,9 @@ impl PolkaBtcProvider { /// # Arguments /// * `on_error` - callback for decoding errors, is not allowed to take too long pub async fn on_event_error(&self, on_error: E) -> Result<(), Error> { - let sub = self.ext_client.subscribe_events().await?; - let decoder = EventsDecoder::::new( - self.ext_client.metadata().clone(), - EventTypeRegistry::new(), - ); + let sub = self.ext_client.subscribe_finalized_events().await?; + let decoder = + EventsDecoder::::new(self.ext_client.metadata().clone(), EventTypeRegistry::new()); let mut sub = EventSubscription::::new(sub, &decoder); loop { @@ -184,11 +138,9 @@ impl PolkaBtcProvider { R: Future, E: Fn(XtError), { - let sub = self.ext_client.subscribe_events().await?; - let decoder = EventsDecoder::::new( - self.ext_client.metadata().clone(), - EventTypeRegistry::new(), - ); + let sub = self.ext_client.subscribe_finalized_events().await?; + let decoder = + EventsDecoder::::new(self.ext_client.metadata().clone(), EventTypeRegistry::new()); let mut sub = EventSubscription::::new(sub, &decoder); sub.filter_event::(); @@ -199,7 +151,7 @@ impl PolkaBtcProvider { futures::future::try_join( async move { let tx = &tx; - while let Some(result) = sub.next().await { + while let Some(result) = sub.next().fuse().await { if let Ok(raw_event) = result { trace!("raw event: {:?}", raw_event); let decoded = T::decode(&mut &raw_event.data[..]); @@ -222,7 +174,7 @@ impl PolkaBtcProvider { async move { loop { // block until we receive an event from the other task - match rx.next().await { + match rx.next().fuse().await { Some(event) => { on_event(event).await; } @@ -241,12 +193,23 @@ impl PolkaBtcProvider { async fn sudo>(&self, call: C) -> Result<(), Error> { let encoded = self.ext_client.encode(call)?; self.ext_client - .sudo_and_watch(&*self.signer.write().await, &encoded) + .sudo_and_watch(&self.get_unique_signer().await, &encoded) .await?; Ok(()) } } +#[async_trait] +impl Provider for PolkaBtcProvider { + async fn connect(rpc_client: T, signer: PolkaBtcSigner) -> Result + where + Self: Sized, + T: Into + Send, + { + Self::new(rpc_client, signer).await + } +} + #[async_trait] pub trait UtilFuncs { /// Gets the current height of the parachain @@ -261,7 +224,8 @@ pub trait UtilFuncs { #[async_trait] impl UtilFuncs for PolkaBtcProvider { async fn get_current_chain_height(&self) -> Result { - let query_result = self.ext_client.block(Option::::None).await?; + let head = self.get_latest_block_hash().await?; + let query_result = self.ext_client.block(head).await?; match query_result { Some(x) => Ok(x.block.header.number), None => Err(Error::BlockNotFound), @@ -269,10 +233,7 @@ impl UtilFuncs for PolkaBtcProvider { } async fn get_blockchain_height_at(&self, parachain_height: u32) -> Result { - let hash = self - .ext_client - .block_hash(Some(parachain_height.into())) - .await?; + let hash = self.ext_client.block_hash(Some(parachain_height.into())).await?; Ok(self.ext_client.best_block_height(hash).await?) } @@ -285,10 +246,7 @@ impl UtilFuncs for PolkaBtcProvider { pub trait DotBalancesPallet { async fn get_free_dot_balance(&self) -> Result<::Balance, Error>; - async fn get_free_dot_balance_for_id( - &self, - id: AccountId, - ) -> Result<::Balance, Error>; + async fn get_free_dot_balance_for_id(&self, id: AccountId) -> Result<::Balance, Error>; async fn get_reserved_dot_balance(&self) -> Result<::Balance, Error>; @@ -301,24 +259,19 @@ impl DotBalancesPallet for PolkaBtcProvider { Ok(Self::get_free_dot_balance_for_id(&self, self.account_id.clone()).await?) } - async fn get_free_dot_balance_for_id( - &self, - id: AccountId, - ) -> Result<::Balance, Error> { - Ok(self.ext_client.account(id.clone(), None).await?.free) + async fn get_free_dot_balance_for_id(&self, id: AccountId) -> Result<::Balance, Error> { + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.account(id.clone(), head).await?.free) } async fn get_reserved_dot_balance(&self) -> Result<::Balance, Error> { - Ok(self - .ext_client - .account(self.account_id.clone(), None) - .await? - .reserved) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.account(self.account_id.clone(), head).await?.reserved) } async fn transfer_to(&self, destination: AccountId, amount: u128) -> Result<(), Error> { self.ext_client - .transfer_and_watch(&*self.signer.write().await, &destination, amount) + .transfer_and_watch(&self.get_unique_signer().await, &destination, amount) .await?; Ok(()) } @@ -333,8 +286,7 @@ pub trait ReplacePallet { /// * `&self` - sender of the transaction /// * `amount` - amount of PolkaBTC /// * `griefing_collateral` - amount of DOT - async fn request_replace(&self, amount: u128, griefing_collateral: u128) - -> Result; + async fn request_replace(&self, amount: u128, griefing_collateral: u128) -> Result; /// Withdraw a request of vault replacement /// @@ -352,12 +304,7 @@ pub trait ReplacePallet { /// * `replace_id` - the unique identifier for the specific request /// * `collateral` - the collateral for replacement /// * `btc_address` - the address to send funds to - async fn accept_replace( - &self, - replace_id: H256, - collateral: u128, - btc_address: BtcAddress, - ) -> Result<(), Error>; + async fn accept_replace(&self, replace_id: H256, collateral: u128, btc_address: BtcAddress) -> Result<(), Error>; /// Auction forces vault replacement /// @@ -427,14 +374,10 @@ pub trait ReplacePallet { #[async_trait] impl ReplacePallet for PolkaBtcProvider { - async fn request_replace( - &self, - amount: u128, - griefing_collateral: u128, - ) -> Result { + async fn request_replace(&self, amount: u128, griefing_collateral: u128) -> Result { let result = self .ext_client - .request_replace_and_watch(&*self.signer.write().await, amount, griefing_collateral) + .request_replace_and_watch(&self.get_unique_signer().await, amount, griefing_collateral) .await?; if let Some(event) = result.request_replace()? { @@ -446,24 +389,14 @@ impl ReplacePallet for PolkaBtcProvider { async fn withdraw_replace(&self, replace_id: H256) -> Result<(), Error> { self.ext_client - .withdraw_replace_and_watch(&*self.signer.write().await, replace_id) + .withdraw_replace_and_watch(&self.get_unique_signer().await, replace_id) .await?; Ok(()) } - async fn accept_replace( - &self, - replace_id: H256, - collateral: u128, - btc_address: BtcAddress, - ) -> Result<(), Error> { + async fn accept_replace(&self, replace_id: H256, collateral: u128, btc_address: BtcAddress) -> Result<(), Error> { self.ext_client - .accept_replace_and_watch( - &*self.signer.write().await, - replace_id, - collateral, - btc_address, - ) + .accept_replace_and_watch(&self.get_unique_signer().await, replace_id, collateral, btc_address) .await?; Ok(()) } @@ -477,7 +410,7 @@ impl ReplacePallet for PolkaBtcProvider { ) -> Result<(), Error> { self.ext_client .auction_replace_and_watch( - &*self.signer.write().await, + &self.get_unique_signer().await, old_vault, btc_amount, collateral, @@ -495,20 +428,14 @@ impl ReplacePallet for PolkaBtcProvider { raw_tx: Vec, ) -> Result<(), Error> { self.ext_client - .execute_replace_and_watch( - &*self.signer.write().await, - replace_id, - tx_id, - merkle_proof, - raw_tx, - ) + .execute_replace_and_watch(&self.get_unique_signer().await, replace_id, tx_id, merkle_proof, raw_tx) .await?; Ok(()) } async fn cancel_replace(&self, replace_id: H256) -> Result<(), Error> { self.ext_client - .cancel_replace_and_watch(&*self.signer.write().await, replace_id) + .cancel_replace_and_watch(&self.get_unique_signer().await, replace_id) .await?; Ok(()) } @@ -546,7 +473,8 @@ impl ReplacePallet for PolkaBtcProvider { } async fn get_replace_period(&self) -> Result { - Ok(self.ext_client.replace_period(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.replace_period(head).await?) } async fn set_replace_period(&self, period: u32) -> Result<(), Error> { @@ -559,7 +487,8 @@ impl ReplacePallet for PolkaBtcProvider { } async fn get_replace_request(&self, replace_id: H256) -> Result { - Ok(self.ext_client.replace_requests(replace_id, None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.replace_requests(replace_id, head).await?) } } @@ -572,7 +501,8 @@ pub trait TimestampPallet { impl TimestampPallet for PolkaBtcProvider { /// Get the current time as defined by the `timestamp` pallet. async fn get_time_now(&self) -> Result { - Ok(self.ext_client.now(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.now(head).await?) } } @@ -596,9 +526,10 @@ impl ExchangeRateOraclePallet for PolkaBtcProvider { /// Returns the last exchange rate in planck per satoshis, the time at which it was set /// and the configured max delay. async fn get_exchange_rate_info(&self) -> Result<(FixedU128, u64, u64), Error> { - let get_rate = self.ext_client.exchange_rate(None); - let get_time = self.ext_client.last_exchange_rate_time(None); - let get_delay = self.ext_client.max_delay(None); + let head = self.get_latest_block_hash().await?; + let get_rate = self.ext_client.exchange_rate(head); + let get_time = self.ext_client.last_exchange_rate_time(head); + let get_delay = self.ext_client.max_delay(head); match tokio::try_join!(get_rate, get_time, get_delay) { Ok((rate, time, delay)) => Ok((rate, time, delay)), @@ -612,7 +543,7 @@ impl ExchangeRateOraclePallet for PolkaBtcProvider { /// * `dot_per_btc` - the current dot per btc exchange rate async fn set_exchange_rate_info(&self, dot_per_btc: FixedU128) -> Result<(), Error> { self.ext_client - .set_exchange_rate_and_watch(&*self.signer.write().await, dot_per_btc) + .set_exchange_rate_and_watch(&self.get_unique_signer().await, dot_per_btc) .await?; Ok(()) } @@ -626,7 +557,7 @@ impl ExchangeRateOraclePallet for PolkaBtcProvider { /// * `hour` - The estimated Satoshis per bytes to get included in the next 6 blocks (~hour) async fn set_btc_tx_fees_per_byte(&self, fast: u32, half: u32, hour: u32) -> Result<(), Error> { self.ext_client - .set_btc_tx_fees_per_byte_and_watch(&*self.signer.write().await, fast, half, hour) + .set_btc_tx_fees_per_byte_and_watch(&self.get_unique_signer().await, fast, half, hour) .await?; Ok(()) } @@ -634,7 +565,8 @@ impl ExchangeRateOraclePallet for PolkaBtcProvider { /// Gets the estimated Satoshis per bytes required to get a Bitcoin transaction included in /// in the next x blocks async fn get_btc_tx_fees_per_byte(&self) -> Result { - Ok(self.ext_client.satoshi_per_bytes(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.satoshi_per_bytes(head).await?) } /// Converts the amount in btc to dot, based on the current set exchange rate. @@ -666,9 +598,9 @@ impl ExchangeRateOraclePallet for PolkaBtcProvider { #[async_trait] pub trait StakedRelayerPallet { - async fn get_stake(&self) -> Result; + async fn get_active_stake(&self) -> Result; - async fn get_stake_by_id(&self, account_id: AccountId) -> Result; + async fn get_active_stake_by_id(&self, account_id: AccountId) -> Result; async fn get_inactive_stake_by_id(&self, account_id: AccountId) -> Result; @@ -686,11 +618,7 @@ pub trait StakedRelayerPallet { message: String, ) -> Result<(), Error>; - async fn vote_on_status_update( - &self, - status_update_id: u64, - approve: bool, - ) -> Result<(), Error>; + async fn vote_on_status_update(&self, status_update_id: u64, approve: bool) -> Result<(), Error>; async fn get_status_update(&self, id: u64) -> Result; @@ -704,11 +632,7 @@ pub trait StakedRelayerPallet { raw_tx: Vec, ) -> Result<(), Error>; - async fn is_transaction_invalid( - &self, - vault_id: AccountId, - raw_tx: Vec, - ) -> Result; + async fn is_transaction_invalid(&self, vault_id: AccountId, raw_tx: Vec) -> Result; async fn set_maturity_period(&self, period: u32) -> Result<(), Error>; @@ -718,26 +642,20 @@ pub trait StakedRelayerPallet { #[async_trait] impl StakedRelayerPallet for PolkaBtcProvider { /// Get the stake registered for this staked relayer. - async fn get_stake(&self) -> Result { - Ok(self.get_stake_by_id(self.account_id.clone()).await?) + async fn get_active_stake(&self) -> Result { + Ok(self.get_active_stake_by_id(self.account_id.clone()).await?) } /// Get the stake registered for this staked relayer. - async fn get_stake_by_id(&self, account_id: AccountId) -> Result { - Ok(self - .ext_client - .active_staked_relayers(&account_id, None) - .await? - .stake) + async fn get_active_stake_by_id(&self, account_id: AccountId) -> Result { + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.active_staked_relayers(&account_id, head).await?.stake) } /// Get the stake registered for this inactive staked relayer. async fn get_inactive_stake_by_id(&self, account_id: AccountId) -> Result { - Ok(self - .ext_client - .inactive_staked_relayers(&account_id, None) - .await? - .stake) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.inactive_staked_relayers(&account_id, head).await?.stake) } /// Submit extrinsic to register the staked relayer. @@ -746,7 +664,7 @@ impl StakedRelayerPallet for PolkaBtcProvider { /// * `stake` - deposit async fn register_staked_relayer(&self, stake: u128) -> Result<(), Error> { self.ext_client - .register_staked_relayer_and_watch(&*self.signer.write().await, stake) + .register_staked_relayer_and_watch(&self.get_unique_signer().await, stake) .await?; Ok(()) } @@ -754,7 +672,7 @@ impl StakedRelayerPallet for PolkaBtcProvider { /// Submit extrinsic to deregister the staked relayer. async fn deregister_staked_relayer(&self) -> Result<(), Error> { self.ext_client - .deregister_staked_relayer_and_watch(&*self.signer.write().await) + .deregister_staked_relayer_and_watch(&self.get_unique_signer().await) .await?; Ok(()) } @@ -786,7 +704,7 @@ impl StakedRelayerPallet for PolkaBtcProvider { ) -> Result<(), Error> { self.ext_client .suggest_status_update_and_watch( - &*self.signer.write().await, + &self.get_unique_signer().await, deposit, status_code, add_error, @@ -803,13 +721,9 @@ impl StakedRelayerPallet for PolkaBtcProvider { /// # Arguments /// * `status_update_id` - ID of the status update /// * `approve` - whether to approve or reject the proposal - async fn vote_on_status_update( - &self, - status_update_id: u64, - approve: bool, - ) -> Result<(), Error> { + async fn vote_on_status_update(&self, status_update_id: u64, approve: bool) -> Result<(), Error> { self.ext_client - .vote_on_status_update_and_watch(&*self.signer.write().await, status_update_id, approve) + .vote_on_status_update_and_watch(&self.get_unique_signer().await, status_update_id, approve) .await?; Ok(()) } @@ -818,20 +732,15 @@ impl StakedRelayerPallet for PolkaBtcProvider { /// /// # Arguments /// * `status_update_id` - ID of the status update - async fn get_status_update( - &self, - status_update_id: u64, - ) -> Result { - Ok(self - .ext_client - .active_status_updates(status_update_id, None) - .await?) + async fn get_status_update(&self, status_update_id: u64) -> Result { + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.active_status_updates(status_update_id, head).await?) } /// Submit extrinsic to report that the oracle is offline. async fn report_oracle_offline(&self) -> Result<(), Error> { self.ext_client - .report_oracle_offline_and_watch(&*self.signer.write().await) + .report_oracle_offline_and_watch(&self.get_unique_signer().await) .await?; Ok(()) } @@ -854,13 +763,7 @@ impl StakedRelayerPallet for PolkaBtcProvider { raw_tx: Vec, ) -> Result<(), Error> { self.ext_client - .report_vault_theft_and_watch( - &*self.signer.write().await, - vault_id, - tx_id, - merkle_proof, - raw_tx, - ) + .report_vault_theft_and_watch(&self.get_unique_signer().await, vault_id, tx_id, merkle_proof, raw_tx) .await?; Ok(()) } @@ -875,11 +778,7 @@ impl StakedRelayerPallet for PolkaBtcProvider { /// # Arguments /// * `vault_id` - vault account which features in vin /// * `raw_tx` - raw Bitcoin transaction - async fn is_transaction_invalid( - &self, - vault_id: AccountId, - raw_tx: Vec, - ) -> Result { + async fn is_transaction_invalid(&self, vault_id: AccountId, raw_tx: Vec) -> Result { Ok( match self .rpc_client @@ -927,11 +826,13 @@ impl SecurityPallet for PolkaBtcProvider { /// Get the current security status of the parachain. /// Should be one of; `Running`, `Error` or `Shutdown`. async fn get_parachain_status(&self) -> Result { - Ok(self.ext_client.parachain_status(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.parachain_status(head).await?) } /// Return any `ErrorCode`s set in the security module. async fn get_error_codes(&self) -> Result, Error> { - Ok(self.ext_client.errors(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.errors(head).await?) } } @@ -959,10 +860,8 @@ pub trait IssuePallet { async fn get_issue_request(&self, issue_id: H256) -> Result; - async fn get_vault_issue_requests( - &self, - account_id: AccountId, - ) -> Result, Error>; + async fn get_vault_issue_requests(&self, account_id: AccountId) + -> Result, Error>; async fn get_issue_period(&self) -> Result; @@ -981,12 +880,7 @@ impl IssuePallet for PolkaBtcProvider { ) -> Result { let result = self .ext_client - .request_issue_and_watch( - &*self.signer.write().await, - amount, - vault_id, - griefing_collateral, - ) + .request_issue_and_watch(&self.get_unique_signer().await, amount, vault_id, griefing_collateral) .await?; result.request_issue()?.ok_or(Error::RequestIssueIDNotFound) @@ -1000,26 +894,21 @@ impl IssuePallet for PolkaBtcProvider { raw_tx: Vec, ) -> Result<(), Error> { self.ext_client - .execute_issue_and_watch( - &*self.signer.write().await, - issue_id, - tx_id, - merkle_proof, - raw_tx, - ) + .execute_issue_and_watch(&self.get_unique_signer().await, issue_id, tx_id, merkle_proof, raw_tx) .await?; Ok(()) } async fn cancel_issue(&self, issue_id: H256) -> Result<(), Error> { self.ext_client - .cancel_issue_and_watch(&*self.signer.write().await, issue_id) + .cancel_issue_and_watch(&self.get_unique_signer().await, issue_id) .await?; Ok(()) } async fn get_issue_request(&self, issue_id: H256) -> Result { - Ok(self.ext_client.issue_requests(issue_id, None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.issue_requests(issue_id, head).await?) } async fn get_vault_issue_requests( @@ -1038,7 +927,8 @@ impl IssuePallet for PolkaBtcProvider { } async fn get_issue_period(&self) -> Result { - Ok(self.ext_client.issue_period(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.issue_period(head).await?) } async fn set_issue_period(&self, period: u32) -> Result<(), Error> { @@ -1055,12 +945,10 @@ impl IssuePallet for PolkaBtcProvider { let issue_period = self.get_issue_period().await?; let mut issue_requests = Vec::new(); - let mut iter = self.ext_client.issue_requests_iter(None).await?; + let head = self.get_latest_block_hash().await?; + let mut iter = self.ext_client.issue_requests_iter(head).await?; while let Some((issue_id, request)) = iter.next().await? { - if !request.completed - && !request.cancelled - && request.opentime + issue_period > current_height - { + if !request.completed && !request.cancelled && request.opentime + issue_period > current_height { let key_hash = issue_id.0.as_slice(); // last bytes are the raw key let key = &key_hash[key_hash.len() - 32..]; @@ -1101,6 +989,8 @@ pub trait RedeemPallet { account_id: AccountId, ) -> Result, Error>; + async fn get_redeem_period(&self) -> Result; + async fn set_redeem_period(&self, period: u32) -> Result<(), Error>; } @@ -1114,12 +1004,7 @@ impl RedeemPallet for PolkaBtcProvider { ) -> Result { let result = self .ext_client - .request_redeem_and_watch( - &*self.signer.write().await, - amount_polka_btc, - btc_address, - vault_id, - ) + .request_redeem_and_watch(&self.get_unique_signer().await, amount_polka_btc, btc_address, vault_id) .await?; if let Some(event) = result.request_redeem()? { @@ -1137,33 +1022,28 @@ impl RedeemPallet for PolkaBtcProvider { raw_tx: Vec, ) -> Result<(), Error> { self.ext_client - .execute_redeem_and_watch( - &*self.signer.write().await, - redeem_id, - tx_id, - merkle_proof, - raw_tx, - ) + .execute_redeem_and_watch(&self.get_unique_signer().await, redeem_id, tx_id, merkle_proof, raw_tx) .await?; Ok(()) } async fn cancel_redeem(&self, redeem_id: H256, reimburse: bool) -> Result<(), Error> { self.ext_client - .cancel_redeem_and_watch(&*self.signer.write().await, redeem_id, reimburse) + .cancel_redeem_and_watch(&self.get_unique_signer().await, redeem_id, reimburse) .await?; Ok(()) } async fn get_redeem_request(&self, redeem_id: H256) -> Result { - Ok(self.ext_client.redeem_requests(redeem_id, None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.redeem_requests(redeem_id, head).await?) } async fn get_vault_redeem_requests( &self, account_id: AccountId, ) -> Result, Error> { - let result: Vec<(H256, PolkaBtcRedeemRequest)> = self + let requests: Vec<(H256, PolkaBtcRedeemRequest)> = self .rpc_client .request( "redeem_getVaultRedeemRequests", @@ -1171,10 +1051,15 @@ impl RedeemPallet for PolkaBtcProvider { ) .await?; - Ok(result) + Ok(requests) + } + + async fn get_redeem_period(&self) -> Result { + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.redeem_period(head).await?) } - async fn set_redeem_period(&self, period: u32) -> Result<(), Error> { + async fn set_redeem_period(&self, period: BlockNumber) -> Result<(), Error> { Ok(self .sudo(SetRedeemPeriodCall { period, @@ -1212,13 +1097,7 @@ impl RefundPallet for PolkaBtcProvider { raw_tx: Vec, ) -> Result<(), Error> { self.ext_client - .execute_refund_and_watch( - &*self.signer.write().await, - refund_id, - tx_id, - merkle_proof, - raw_tx, - ) + .execute_refund_and_watch(&self.get_unique_signer().await, refund_id, tx_id, merkle_proof, raw_tx) .await?; Ok(()) } @@ -1249,13 +1128,9 @@ pub trait BtcRelayPallet { async fn get_block_hash(&self, height: u32) -> Result; - async fn get_block_header(&self, hash: H256Le) -> Result; + async fn get_block_header(&self, hash: H256Le) -> Result; - async fn initialize_btc_relay( - &self, - header: RawBlockHeader, - height: BitcoinBlockHeight, - ) -> Result<(), Error>; + async fn initialize_btc_relay(&self, header: RawBlockHeader, height: BitcoinBlockHeight) -> Result<(), Error>; async fn store_block_header(&self, header: RawBlockHeader) -> Result<(), Error>; @@ -1263,23 +1138,21 @@ pub trait BtcRelayPallet { async fn get_bitcoin_confirmations(&self) -> Result; - async fn wait_for_block_in_relay( - &self, - block_hash: H256Le, - num_confirmations: u32, - ) -> Result<(), Error>; + async fn wait_for_block_in_relay(&self, block_hash: H256Le, num_confirmations: u32) -> Result<(), Error>; } #[async_trait] impl BtcRelayPallet for PolkaBtcProvider { /// Get the hash of the current best tip. async fn get_best_block(&self) -> Result { - Ok(self.ext_client.best_block(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.best_block(head).await?) } /// Get the current best known height. async fn get_best_block_height(&self) -> Result { - Ok(self.ext_client.best_block_height(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.best_block_height(head).await?) } /// Get the block hash for the main chain at the specified height. @@ -1287,33 +1160,31 @@ impl BtcRelayPallet for PolkaBtcProvider { /// # Arguments /// * `height` - chain height async fn get_block_hash(&self, height: u32) -> Result { - Ok(self.ext_client.chains_hashes(0, height, None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.chains_hashes(0, height, head).await?) } /// Get the corresponding block header for the given hash. /// /// # Arguments /// * `hash` - little endian block hash - async fn get_block_header(&self, hash: H256Le) -> Result { - Ok(self.ext_client.block_headers(hash, None).await?) + async fn get_block_header(&self, hash: H256Le) -> Result { + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.block_headers(hash, head).await?) } /// Initializes the relay with the provided block header and height, - /// should be called automatically by `relayer_core` subject to the + /// should be called automatically by relayer subject to the /// result of `is_initialized`. /// /// # Arguments /// * `header` - raw block header /// * `height` - starting height - async fn initialize_btc_relay( - &self, - header: RawBlockHeader, - height: BitcoinBlockHeight, - ) -> Result<(), Error> { + async fn initialize_btc_relay(&self, header: RawBlockHeader, height: BitcoinBlockHeight) -> Result<(), Error> { // TODO: can we initialize the relay through the chain-spec? // we would also need to consider re-initialization per governance self.ext_client - .initialize_and_watch(&*self.signer.write().await, header, height) + .initialize_and_watch(&self.get_unique_signer().await, header, height) .await?; Ok(()) } @@ -1324,7 +1195,7 @@ impl BtcRelayPallet for PolkaBtcProvider { /// * `header` - raw block header async fn store_block_header(&self, header: RawBlockHeader) -> Result<(), Error> { self.ext_client - .store_block_header_and_watch(&*self.signer.write().await, header) + .store_block_header_and_watch(&self.get_unique_signer().await, header) .await?; Ok(()) } @@ -1335,30 +1206,26 @@ impl BtcRelayPallet for PolkaBtcProvider { /// * `headers` - raw block headers async fn store_block_headers(&self, headers: Vec) -> Result<(), Error> { self.ext_client - .store_block_headers_and_watch(&*self.signer.write().await, headers) + .store_block_headers_and_watch(&self.get_unique_signer().await, headers) .await?; Ok(()) } /// Get the global security parameter k for stable Bitcoin transactions async fn get_bitcoin_confirmations(&self) -> Result { - Ok(self.ext_client.stable_bitcoin_confirmations(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.stable_bitcoin_confirmations(head).await?) } /// Wait until Bitcoin block is submitted to the relay - async fn wait_for_block_in_relay( - &self, - block_hash: H256Le, - num_confirmations: u32, - ) -> Result<(), Error> { + async fn wait_for_block_in_relay(&self, block_hash: H256Le, num_confirmations: u32) -> Result<(), Error> { loop { match self.get_block_header(block_hash).await { // rpc returns zero-initialized storage items if not set, therefore // a block header only exists if the height is non-zero Ok(block_header) if block_header.block_height > 0 - && block_header.block_height + num_confirmations - <= self.get_best_block_height().await? => + && block_header.block_height + num_confirmations <= self.get_best_block_height().await? => { return Ok(()); } @@ -1382,8 +1249,7 @@ pub trait VaultRegistryPallet { async fn get_all_vaults(&self) -> Result, Error>; - async fn register_vault(&self, collateral: u128, public_key: BtcPublicKey) - -> Result<(), Error>; + async fn register_vault(&self, collateral: u128, public_key: BtcPublicKey) -> Result<(), Error>; async fn lock_additional_collateral(&self, amount: u128) -> Result<(), Error>; @@ -1409,21 +1275,34 @@ impl VaultRegistryPallet for PolkaBtcProvider { /// /// # Errors /// * `VaultNotFound` - if the rpc returned a default value rather than the vault we want + /// * `VaultLiquidated` - if the vault is liquidated + /// * `VaultCommittedTheft` - if the vault is stole BTC async fn get_vault(&self, vault_id: AccountId) -> Result { - let vault: PolkaBtcVault = self.ext_client.vaults(vault_id.clone(), None).await?; - if vault.id == vault_id { - Ok(vault) - } else { - Err(Error::VaultNotFound) + let head = self.get_latest_block_hash().await?; + match self.ext_client.vaults(vault_id.clone(), head).await { + Ok(PolkaBtcVault { + status: VaultStatus::Liquidated, + .. + }) => Err(Error::VaultLiquidated), + Ok(PolkaBtcVault { + status: VaultStatus::CommittedTheft, + .. + }) => Err(Error::VaultCommittedTheft), + Ok(vault) if vault.id == vault_id => Ok(vault), + Ok(_) => Err(Error::VaultNotFound), + Err(err) => Err(err.into()), } } /// Fetch all active vaults. async fn get_all_vaults(&self) -> Result, Error> { let mut vaults = Vec::new(); - let mut iter = self.ext_client.vaults_iter(None).await?; + let head = self.get_latest_block_hash().await?; + let mut iter = self.ext_client.vaults_iter(head).await?; while let Some((_, account)) = iter.next().await? { - vaults.push(account); + if let VaultStatus::Active = account.status { + vaults.push(account); + } } Ok(vaults) } @@ -1433,13 +1312,9 @@ impl VaultRegistryPallet for PolkaBtcProvider { /// # Arguments /// * `collateral` - deposit /// * `public_key` - Bitcoin public key - async fn register_vault( - &self, - collateral: u128, - public_key: BtcPublicKey, - ) -> Result<(), Error> { + async fn register_vault(&self, collateral: u128, public_key: BtcPublicKey) -> Result<(), Error> { self.ext_client - .register_vault_and_watch(&*self.signer.write().await, collateral, public_key) + .register_vault_and_watch(&self.get_unique_signer().await, collateral, public_key) .await?; Ok(()) } @@ -1451,7 +1326,7 @@ impl VaultRegistryPallet for PolkaBtcProvider { /// * `amount` - the amount of extra collateral to lock async fn lock_additional_collateral(&self, amount: u128) -> Result<(), Error> { self.ext_client - .lock_additional_collateral_and_watch(&*self.signer.write().await, amount) + .lock_additional_collateral_and_watch(&self.get_unique_signer().await, amount) .await?; Ok(()) } @@ -1468,7 +1343,7 @@ impl VaultRegistryPallet for PolkaBtcProvider { /// * `amount` - the amount of collateral to withdraw async fn withdraw_collateral(&self, amount: u128) -> Result<(), Error> { self.ext_client - .withdraw_collateral_and_watch(&*self.signer.write().await, amount) + .withdraw_collateral_and_watch(&self.get_unique_signer().await, amount) .await?; Ok(()) } @@ -1479,7 +1354,7 @@ impl VaultRegistryPallet for PolkaBtcProvider { /// * `public_key` - the new public key of the vault async fn update_public_key(&self, public_key: BtcPublicKey) -> Result<(), Error> { self.ext_client - .update_public_key_and_watch(&*self.signer.write().await, public_key) + .update_public_key_and_watch(&self.get_unique_signer().await, public_key) .await?; Ok(()) } @@ -1490,7 +1365,7 @@ impl VaultRegistryPallet for PolkaBtcProvider { /// * `btc_address` - the new btc address of the vault async fn register_address(&self, btc_address: BtcAddress) -> Result<(), Error> { self.ext_client - .register_address_and_watch(&*self.signer.write().await, btc_address) + .register_address_and_watch(&self.get_unique_signer().await, btc_address) .await?; Ok(()) } @@ -1550,14 +1425,17 @@ pub trait FeePallet { #[async_trait] impl FeePallet for PolkaBtcProvider { async fn get_issue_griefing_collateral(&self) -> Result { - Ok(self.ext_client.issue_griefing_collateral(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.issue_griefing_collateral(head).await?) } async fn get_issue_fee(&self) -> Result { - Ok(self.ext_client.issue_fee(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.issue_fee(head).await?) } async fn get_replace_griefing_collateral(&self) -> Result { - Ok(self.ext_client.replace_griefing_collateral(None).await?) + let head = self.get_latest_block_hash().await?; + Ok(self.ext_client.replace_griefing_collateral(head).await?) } } diff --git a/runtime/src/tests.rs b/runtime/src/tests.rs index a8150f9ad..104f637ef 100644 --- a/runtime/src/tests.rs +++ b/runtime/src/tests.rs @@ -1,59 +1,29 @@ +#![cfg(test)] + +use crate::integration::*; + use super::{ - BtcAddress, BtcPublicKey, BtcRelayPallet, DotBalancesPallet, PolkaBtcProvider, PolkaBtcRuntime, - SecurityPallet, StatusCode, VaultRegistryPallet, + BtcAddress, BtcPublicKey, BtcRelayPallet, DotBalancesPallet, SecurityPallet, StakedRelayerPallet, StatusCode, + VaultRegistryPallet, MINIMUM_STAKE, }; use module_bitcoin::{ - formatter::Formattable, + formatter::TryFormattable, types::{BlockBuilder, RawBlockHeader}, }; use sp_core::{H160, U256}; use sp_keyring::AccountKeyring; -use substrate_subxt::PairSigner; -use substrate_subxt_client::{ - DatabaseConfig, KeystoreConfig, Role, SubxtClient, SubxtClientConfig, -}; -use tempdir::TempDir; fn dummy_public_key() -> BtcPublicKey { BtcPublicKey([ - 2, 205, 114, 218, 156, 16, 235, 172, 106, 37, 18, 153, 202, 140, 176, 91, 207, 51, 187, 55, - 18, 45, 222, 180, 119, 54, 243, 97, 173, 150, 161, 169, 230, + 2, 205, 114, 218, 156, 16, 235, 172, 106, 37, 18, 153, 202, 140, 176, 91, 207, 51, 187, 55, 18, 45, 222, 180, + 119, 54, 243, 97, 173, 150, 161, 169, 230, ]) } -async fn test_client_with(key: AccountKeyring) -> PolkaBtcProvider { - let tmp = TempDir::new("btc-parachain-").expect("failed to create tempdir"); - let config = SubxtClientConfig { - impl_name: "btc-parachain-full-client", - impl_version: "0.0.1", - author: "Interlay Ltd", - copyright_start_year: 2020, - db: DatabaseConfig::ParityDb { - path: tmp.path().join("db"), - }, - keystore: KeystoreConfig::Path { - path: tmp.path().join("keystore"), - password: None, - }, - chain_spec: btc_parachain::chain_spec::development_config(), - role: Role::Authority(key.clone()), - telemetry: None, - }; - - let signer = PairSigner::::new(key.pair()); - - PolkaBtcProvider::new( - SubxtClient::from_config(config, btc_parachain_service::new_full) - .expect("Error creating subxt client"), - signer, - ) - .await - .expect("Error creating client") -} - #[tokio::test] async fn test_get_free_dot_balance() { - let provider = test_client_with(AccountKeyring::Alice).await; + let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; + let provider = setup_provider(client.clone(), AccountKeyring::Alice).await; let balance = provider.get_free_dot_balance().await.unwrap(); assert_eq!(balance, 1 << 60); @@ -61,7 +31,8 @@ async fn test_get_free_dot_balance() { #[tokio::test] async fn test_parachain_status() { - let provider = test_client_with(AccountKeyring::Alice).await; + let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; + let provider = setup_provider(client.clone(), AccountKeyring::Alice).await; let status = provider.get_parachain_status().await.unwrap(); assert_eq!(status, StatusCode::Running); @@ -69,21 +40,21 @@ async fn test_parachain_status() { #[tokio::test] async fn test_register_vault() { - let provider = test_client_with(AccountKeyring::Alice).await; - provider - .register_vault(100, dummy_public_key()) - .await - .unwrap(); - let vault = provider - .get_vault(AccountKeyring::Alice.to_account_id()) - .await - .unwrap(); + let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; + let provider = setup_provider(client.clone(), AccountKeyring::Alice).await; + + provider.register_vault(100, dummy_public_key()).await.unwrap(); + let vault = provider.get_vault(AccountKeyring::Alice.to_account_id()).await.unwrap(); assert_eq!(vault.wallet.public_key, dummy_public_key()); } #[tokio::test] async fn test_btc_relay() { - let provider = test_client_with(AccountKeyring::Alice).await; + let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; + let provider = setup_provider(client.clone(), AccountKeyring::Alice).await; + + // must be authorized to submit blocks + provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); let address = BtcAddress::P2PKH(H160::zero()); let mut height = 0; @@ -92,16 +63,14 @@ async fn test_btc_relay() { .with_version(2) .with_coinbase(&address, 50, 3) .with_timestamp(1588813835) - .mine(U256::from(2).pow(254.into())); + .mine(U256::from(2).pow(254.into())) + .unwrap(); - let mut block_hash = block.header.hash(); - let block_header = RawBlockHeader::from_bytes(&block.header.format()) - .expect("could not serialize block header"); + let mut block_hash = block.header.hash().unwrap(); + let block_header = + RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).expect("could not serialize block header"); - provider - .initialize_btc_relay(block_header, height) - .await - .unwrap(); + provider.initialize_btc_relay(block_header, height).await.unwrap(); assert_eq!(provider.get_best_block().await.unwrap(), block_hash); assert_eq!(provider.get_best_block_height().await.unwrap(), height); @@ -115,11 +84,12 @@ async fn test_btc_relay() { .with_version(2) .with_coinbase(&address, 50, height - 1) .with_timestamp(1588813835) - .mine(U256::from(2).pow(254.into())); + .mine(U256::from(2).pow(254.into())) + .unwrap(); - block_hash = block.header.hash(); - let block_header = RawBlockHeader::from_bytes(&block.header.format()) - .expect("could not serialize block header"); + block_hash = block.header.hash().unwrap(); + let block_header = + RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).expect("could not serialize block header"); provider.store_block_header(block_header).await.unwrap(); diff --git a/runtime/src/types.rs b/runtime/src/types.rs new file mode 100644 index 000000000..aa2623fb3 --- /dev/null +++ b/runtime/src/types.rs @@ -0,0 +1,56 @@ +use sp_core::sr25519::Pair as KeyPair; +use sp_runtime::generic::{Block, SignedBlock}; +use substrate_subxt::{system::System, PairSigner}; + +use crate::{ + pallets::{ + Core, IssueRequest, RedeemRequest, RefundRequest, ReplaceRequest, RequestIssueEvent, RichBlockHeader, + StatusUpdate, Vault, + }, + PolkaBtcRuntime, +}; + +pub type AccountId = ::AccountId; + +pub type PolkaBtcHeader = ::Header; + +pub type PolkaBtcBlock = SignedBlock::Extrinsic>>; + +pub type PolkaBtcVault = Vault< + AccountId, + ::BlockNumber, + ::PolkaBTC, + ::DOT, +>; + +pub type PolkaBtcIssueRequest = IssueRequest< + AccountId, + ::BlockNumber, + ::PolkaBTC, + ::DOT, +>; + +pub type PolkaBtcRequestIssueEvent = RequestIssueEvent; + +pub type PolkaBtcRedeemRequest = RedeemRequest< + AccountId, + ::BlockNumber, + ::PolkaBTC, + ::DOT, +>; + +pub type PolkaBtcRefundRequest = RefundRequest::PolkaBTC>; + +pub type PolkaBtcReplaceRequest = ReplaceRequest< + AccountId, + ::BlockNumber, + ::PolkaBTC, + ::DOT, +>; + +pub type PolkaBtcStatusUpdate = + StatusUpdate::BlockNumber, ::DOT>; + +pub type PolkaBtcRichBlockHeader = RichBlockHeader; + +pub type PolkaBtcSigner = PairSigner; diff --git a/staked-relayer/Cargo.toml b/staked-relayer/Cargo.toml index 2222efdbd..3ef413c2f 100644 --- a/staked-relayer/Cargo.toml +++ b/staked-relayer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "staked-relayer" -version = "0.2.0" +version = "0.5.0" authors = ["Interlay "] edition = "2018" @@ -9,28 +9,27 @@ log = "0.4.0" env_logger = "0.7.1" parity-scale-codec = "2.0.0" tokio = { version = "0.2.22", features = ["full"] } +backoff = { version = "0.2.1", features = ["tokio"] } hex = "0.4.2" thiserror = "1.0" futures = "0.3.5" clap = "3.0.0-beta.2" async-trait = "0.1.40" serde = "1.0.116" -relayer-core = { git = "https://gitlab.com/interlay/relayer-core", rev = "7a99a32e" } -runtime = { path = "../runtime" } + +jsonrpc-http-server = "17.0.0" +jsonrpc-core-client = { version = "17.0.0", features = ["http", "tls"] } + +# Workspace dependencies bitcoin = { path = "../bitcoin", features = ["cli"] } -jsonrpc-http-server = "16.0.0" -backoff = { version = "0.2.1", features = ["tokio"] } -jsonrpc-core-client = { version = "16.0.0", features = ["http"] } +runtime = { path = "../runtime" } # Substrate dependencies sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } - [dev-dependencies] mockall = "0.8.1" -rand = "0.7" -schnorrkel = "0.9.1" -jsonrpsee = "0.1.0" + +# Workspace dependencies runtime = { path = "../runtime", features = ["testing-utils"] } diff --git a/staked-relayer/README.md b/staked-relayer/README.md index 943fb7826..24b9bafa0 100644 --- a/staked-relayer/README.md +++ b/staked-relayer/README.md @@ -17,7 +17,7 @@ Download and start [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/): bitcoind -regtest -server ``` -Build and run the [PolkaBTC Parachain](https://gitlab.com/interlay/btc-parachain): +Build and run the [PolkaBTC Parachain](https://github.com/interlay/btc-parachain): ``` git clone git@gitlab.com:interlay/btc-parachain.git @@ -46,7 +46,7 @@ For convenience, a copy of this output is included below. Note that the bitcoin ``` USAGE: - cargo run -- [OPTIONS] --bitcoin-rpc-url --bitcoin-rpc-user --bitcoin-rpc-pass + staked-relayer [OPTIONS] --bitcoin-rpc-url --bitcoin-rpc-user --bitcoin-rpc-pass FLAGS: -h, --help Prints help information @@ -60,9 +60,26 @@ OPTIONS: --auto-register-with-stake Automatically register the relayer with the given stake (in Planck) - --bitcoin-rpc-pass [env: BITCOIN_RPC_PASS=] - --bitcoin-rpc-url [env: BITCOIN_RPC_URL=] - --bitcoin-rpc-user [env: BITCOIN_RPC_USER=] + --bitcoin-relay-start-height + Starting height to relay block headers, if not defined use the best height as reported + by the relay module + + --bitcoin-rpc-pass + [env: BITCOIN_RPC_PASS=rpcpassword] + + --bitcoin-rpc-url + [env: BITCOIN_RPC_URL=http://localhost:18443] + + --bitcoin-rpc-user + [env: BITCOIN_RPC_USER=rpcuser] + + --bitcoin-theft-start-height + Starting height for vault theft checks, if not defined automatically start from the + chain tip + + --bitcoin-timeout-ms + Timeout in milliseconds to poll Bitcoin [default: 6000] + --http-addr Address to listen on for JSON-RPC requests [default: [::0]:3030] @@ -74,11 +91,10 @@ OPTIONS: The name of the account from the keyfile to use --keyring - Keyring to use, mutually exclusive with keyfile [valid values: alice, bob, charlie, - dave, eve, ferdie] + Keyring to use, mutually exclusive with keyfile --max-batch-size - Max batch size for combined block header submission. [default: 16] + Max batch size for combined block header submission [default: 16] --oracle-timeout-ms Timeout in milliseconds to repeat oracle liveness check [default: 5000] @@ -86,22 +102,14 @@ OPTIONS: --polka-btc-url Parachain URL, can be over WebSockets or HTTP [default: ws://127.0.0.1:9944] - --relay-start-height - Starting height to relay block headers, if not defined use the best height as reported - by the relay module - --rpc-cors-domain Comma separated list of allowed origins [default: *] - --scan-block-delay - Delay for checking Bitcoin for new blocks (in seconds) [default: 60] - - --scan-start-height - Starting height for vault theft checks, if not defined automatically start from the - chain tip - --status-update-deposit Default deposit for all automated status proposals [default: 100] + + --required-btc-confirmations: + Number of confirmations a block needs to have before it is submitted [default: 0] ``` ## Example diff --git a/staked-relayer/docker-compose.yml b/staked-relayer/docker-compose.yml deleted file mode 100644 index 8ffe97c95..000000000 --- a/staked-relayer/docker-compose.yml +++ /dev/null @@ -1,31 +0,0 @@ -version: "3.8" -services: - bitcoind: - image: "ruimarinho/bitcoin-core:0.20" - command: - - -testnet - - -server - - -maxuploadtarget=200 - - -blocksonly - - -rpcbind=0.0.0.0 - - -rpcallowip=0.0.0.0/0 - - -rpcuser=rpcuser - - -rpcpassword=rpcpassword - - -fallbackfee=0.0002 - ports: - - "18332:18332" - volumes: - - ./cache:/home/bitcoin/.bitcoin/testnet3 - staked_relayer: - image: "registry.gitlab.com/interlay/polkabtc-clients/staked-relayer:0-4-0" - command: - - /bin/sh - - -c - - | - echo "Sleeping..." - sleep 1 - staked-relayer --http-addr '[::0]:3030' --bitcoin-rpc-url http://bitcoind:18332 --bitcoin-rpc-user rpcuser --bitcoin-rpc-pass rpcpassword --keyfile /keyring/keyfile.json --keyname polkabtcrelayer --auto-register-with-faucet-url 'http://beta.polkabtc.io/api/faucet' --polka-btc-url 'wss://beta.polkabtc.io/api/parachain' - ports: - - "3030:3030" - volumes: - - ./:/keyring diff --git a/staked-relayer/src/core/error.rs b/staked-relayer/src/core/error.rs new file mode 100644 index 000000000..664517883 --- /dev/null +++ b/staked-relayer/src/core/error.rs @@ -0,0 +1,21 @@ +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum Error { + #[error("Client already initialized")] + AlreadyInitialized, + #[error("Client has not been initialized")] + NotInitialized, + #[error("Block already submitted")] + BlockExists, + #[error("Cannot read the best height")] + CannotFetchBestHeight, + #[error("Block hash not found for the given height")] + BlockHashNotFound, + #[error("Call failed after {0} retries")] + CallFailed(u32), + #[error("Backing error: {0}")] + Backing(E), + #[error("Issuing error: {0}")] + Issuing(E), +} diff --git a/staked-relayer/src/core/mod.rs b/staked-relayer/src/core/mod.rs new file mode 100644 index 000000000..7e8154401 --- /dev/null +++ b/staked-relayer/src/core/mod.rs @@ -0,0 +1,542 @@ +use log::{info, trace}; +use std::{error::Error as StdError, marker::PhantomData, time::Duration}; +use tokio::time::delay_for; + +mod error; +mod types; + +pub use error::Error; +pub use types::{Backing, Issuing}; + +// 10 minutes = 600 seconds +const SLEEP_TIME: u64 = 600; + +/// Retrieves `batch` blocks starting at block `height` from the backing blockchain +async fn collect_headers( + height: u32, + batch: u32, + cli: &impl Backing, +) -> Result>, Error> { + let mut headers = Vec::new(); + for h in height..height + batch { + headers.push(cli.get_block_header(h).await.map(|header| header.unwrap())?); + } + Ok(headers) +} + +/// Computes the height at which the relayer should start to submit blocks. +/// In most cases it should be from the next block after the highest block +/// stored by the issuing blockchain +async fn compute_start_height( + backing: &impl Backing, + issuing: &impl Issuing, +) -> Result> { + let mut start_height = issuing.get_best_height().await?; + + // check backing for discrepancy + let mut relay_hash = issuing.get_block_hash(start_height).await?; + let mut btc_hash = backing.get_block_hash(start_height).await?; + + // backwards pass + while relay_hash != btc_hash { + start_height = start_height.checked_sub(1).ok_or(Error::NotInitialized)?; + relay_hash = issuing.get_block_hash(start_height).await?; + btc_hash = backing.get_block_hash(start_height).await?; + } + + // forward pass (possible forks) + loop { + match backing.get_block_hash(start_height).await { + Ok(h) if issuing.is_block_stored(h.clone()).await? => { + start_height = start_height.saturating_add(1); + } + _ => break, + } + } + + // found matching parent start on next + Ok(start_height) +} + +#[derive(Default)] +pub struct Config { + // initialization height, if unset will use `get_block_count` + pub start_height: Option, + // maximum number of headers to collect on catchup + pub max_batch_size: u32, + // thread sleep duration + pub timeout: Option, + ///Number of confirmations a block needs to have before it is submitted. + pub required_btc_confirmations: u32, +} + +/// Runner implements the main loop for the relayer +pub struct Runner, I: Issuing> { + _marker: PhantomData, + backing: B, + issuing: I, + start_height: Option, + max_batch_size: u32, + timeout: Duration, + required_btc_confirmations: u32, +} + +impl, I: Issuing> Runner { + pub fn new(backing: B, issuing: I, conf: Config) -> Runner { + Runner { + _marker: PhantomData {}, + backing, + issuing, + start_height: conf.start_height, + max_batch_size: conf.max_batch_size, + timeout: conf.timeout.unwrap_or(Duration::from_secs(SLEEP_TIME)), + required_btc_confirmations: conf.required_btc_confirmations, + } + } + + /// Returns the block header at `height` + async fn get_block_header(&self, height: u32) -> Result, Error> { + loop { + match self.backing.get_block_header(height).await? { + Some(header) => return Ok(header), + None => { + trace!("No block found at height {}, sleeping for {:?}", height, self.timeout); + delay_for(self.timeout).await + } + }; + } + } + + async fn get_num_confirmed_blocks(&self) -> Result> { + Ok(self + .backing + .get_block_count() + .await? + .saturating_sub(self.required_btc_confirmations)) + } + + /// Submit the next block(s) or initialize the relay, + /// may submit up to `max_batch_size` blocks at a time + pub async fn submit_next(&self) -> Result<(), Error> { + if !self.issuing.is_initialized().await? { + let start_height = self.start_height.unwrap_or(self.get_num_confirmed_blocks().await?); + info!("Initializing at height {}", start_height); + self.issuing + .initialize( + self.backing.get_block_header(start_height).await?.unwrap(), + start_height, + ) + .await?; + } + + let max_height = self.get_num_confirmed_blocks().await?; + trace!("Backing height: {}", max_height); + let current_height = compute_start_height(&self.backing, &self.issuing).await?; + trace!("Issuing height: {}", current_height); + + let batch_size = if current_height.saturating_add(self.max_batch_size) > max_height { + max_height.saturating_add(1).saturating_sub(current_height) + } else { + self.max_batch_size + }; + + match batch_size { + 0 => { + // nothing to submit right now. Wait a little while + trace!("Waiting for the next Bitcoin block..."); + delay_for(self.timeout).await; + } + 1 => { + // submit a single block header + info!("Processing block at height {}", current_height); + let header = self.get_block_header(current_height).await?; + // TODO: check if block already stored + self.issuing.submit_block_header(header).await?; + info!("Submitted block at height {}", current_height); + } + _ => { + info!( + "Processing blocks {} -> {} [{}]", + current_height, + current_height + batch_size, + batch_size + ); + let headers = collect_headers(current_height, batch_size, &self.backing).await?; + self.issuing.submit_block_header_batch(headers).await?; + info!( + "Submitted blocks {} -> {} [{}]", + current_height, + current_height + batch_size, + batch_size + ); + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use async_trait::async_trait; + use std::{ + cell::{Ref, RefCell, RefMut}, + collections::HashMap, + rc::Rc, + }; + + #[derive(Debug, PartialEq)] + struct DummyError(); + + impl StdError for DummyError {} + + impl std::fmt::Display for DummyError { + fn fmt(&self, _f: &mut std::fmt::Formatter) -> std::fmt::Result { + Ok(()) + } + } + + struct DummyIssuing { + headers: Rc>>>, + } + + unsafe impl Sync for DummyIssuing {} + + impl DummyIssuing { + fn new(headers: HashMap>) -> DummyIssuing { + DummyIssuing { + headers: Rc::new(RefCell::new(headers)), + } + } + + fn get_headers(&self) -> Ref>> { + self.headers.borrow() + } + + fn get_headers_mut(&self) -> RefMut>> { + self.headers.borrow_mut() + } + } + + #[async_trait] + impl Issuing for DummyIssuing { + async fn is_initialized(&self) -> Result> { + Ok(!self.get_headers().is_empty()) + } + + async fn initialize(&self, header: Vec, height: u32) -> Result<(), Error> { + if self.get_headers().is_empty() { + self.get_headers_mut().insert(height, header); + Ok(()) + } else { + Err(Error::AlreadyInitialized) + } + } + + async fn submit_block_header(&self, header: Vec) -> Result<(), Error> { + let is_stored = self.is_block_stored(header.clone()).await?; + if is_stored { + Err(Error::BlockExists) + } else { + let height = self.get_best_height().await? + 1; + // NOTE: assume hash(header) == header + self.get_headers_mut().insert(height, header); + Ok(()) + } + } + + async fn submit_block_header_batch(&self, headers: Vec>) -> Result<(), Error> { + for header in headers { + self.submit_block_header(header.to_vec()).await?; + } + Ok(()) + } + + async fn get_best_height(&self) -> Result> { + self.get_headers() + .keys() + .max() + .map(|v| *v) + .ok_or(Error::CannotFetchBestHeight) + } + + async fn get_block_hash(&self, height: u32) -> Result, Error> { + self.get_headers() + .get(&height) + .map(|v| v.clone()) + .ok_or(Error::BlockHashNotFound) + } + + async fn is_block_stored(&self, hash: Vec) -> Result> { + Ok(self.get_headers().iter().find(|&(_, h)| &h[..] == &hash[..]).is_some()) + } + } + + struct DummyBacking { + hashes: HashMap>, + } + + impl DummyBacking { + fn new(hashes: HashMap>) -> DummyBacking { + DummyBacking { hashes } + } + } + + #[async_trait] + impl Backing for DummyBacking { + async fn get_block_count(&self) -> Result> { + self.hashes.keys().max().map(|v| *v).ok_or(Error::CannotFetchBestHeight) + } + + async fn get_block_header(&self, height: u32) -> Result>, Error> { + Ok(self.hashes.get(&height).map(|v| v.clone())) + } + + async fn get_block_hash(&self, height: u32) -> Result, Error> { + self.hashes + .get(&height) + .map(|v| v.clone()) + .ok_or(Error::BlockHashNotFound) + } + } + + fn make_hash(hash_hex: &str) -> Vec { + hash_hex.as_bytes().to_vec() + } + + fn make_hashes(hashes: Vec<(u32, &str)>) -> HashMap> { + hashes.iter().map(|(k, v)| (*k, make_hash(v))).collect() + } + + #[tokio::test] + async fn test_dummy_issuing() { + let hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c")]); + let issuing = DummyIssuing::new(hashes); + + assert_eq!( + issuing.initialize(make_hash("x"), 1).await, + Err(Error::::AlreadyInitialized) + ); + assert_eq!(issuing.get_best_height().await, Ok(4)); + assert_eq!(issuing.get_block_hash(2).await, Ok(make_hash("a"))); + assert_eq!(issuing.get_block_hash(5).await, Err(Error::BlockHashNotFound)); + assert_eq!(issuing.is_block_stored(make_hash("a")).await, Ok(true)); + assert_eq!(issuing.is_block_stored(make_hash("x")).await, Ok(false)); + assert_eq!( + issuing.submit_block_header(make_hash("a")).await, + Err(Error::BlockExists) + ); + assert_eq!(issuing.submit_block_header(make_hash("d")).await, Ok(())); + assert_eq!(issuing.get_best_height().await, Ok(5)); + } + + #[tokio::test] + async fn compute_start_height_simple() { + let hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c")]); + let backing = DummyBacking::new(hashes.clone()); + let issuing = DummyIssuing::new(hashes); + assert_eq!(Ok(5), compute_start_height(&backing, &issuing).await); + } + + #[tokio::test] + async fn compute_start_height_missing_blocks() { + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c")]); + let issuing_hashes = make_hashes(vec![(2, "a"), (3, "b")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + assert_eq!(Ok(4), compute_start_height(&backing, &issuing).await); + } + + #[tokio::test] + async fn compute_start_height_with_fork() { + // height of c should also be 4 but we cannot model fork with this dummy implementation + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c")]); + let issuing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "d"), (0, "c")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + assert_eq!(Ok(5), compute_start_height(&backing, &issuing).await); + } + + #[tokio::test] + async fn new_runner_with_best() -> Result<(), Error> { + let hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c")]); + let backing = DummyBacking::new(hashes.clone()); + let issuing = DummyIssuing::new(hashes); + let runner = Runner::new( + backing, + issuing, + Config { + start_height: None, + max_batch_size: 1, + timeout: None, + required_btc_confirmations: 0, + }, + ); + + assert_eq!(runner.issuing.get_best_height().await.unwrap(), 4); + Ok(()) + } + + #[tokio::test] + async fn catchup_when_out_of_sync() -> Result<(), Error> { + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c"), (5, "d"), (6, "e")]); + let issuing_hashes = make_hashes(vec![(2, "a"), (3, "b")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + let runner = Runner::new( + backing, + issuing, + Config { + start_height: Some(0), + max_batch_size: 16, + timeout: None, + required_btc_confirmations: 0, + }, + ); + + let height_before = runner.issuing.get_best_height().await?; + assert_eq!(height_before, 3); + + runner.submit_next().await?; + let height_after = runner.issuing.get_best_height().await?; + assert_eq!(height_after, 6); + + let best_height = runner.backing.get_block_count().await?; + assert_eq!(height_after, best_height); + + assert!(runner.issuing.is_block_stored(make_hash("c")).await?); + assert!(runner.issuing.is_block_stored(make_hash("d")).await?); + assert!(runner.issuing.is_block_stored(make_hash("e")).await?); + Ok(()) + } + + #[tokio::test] + async fn submit_next_success() -> Result<(), Error> { + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c"), (5, "d")]); + let issuing_hashes = make_hashes(vec![(2, "a"), (3, "b")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + let runner = Runner::new( + backing, + issuing, + Config { + start_height: None, + max_batch_size: 1, + timeout: None, + required_btc_confirmations: 0, + }, + ); + + let height_before = runner.issuing.get_best_height().await?; + assert_eq!(height_before, 3); + + runner.submit_next().await?; + let height_after = runner.issuing.get_best_height().await?; + assert_eq!(height_after, 4); + + assert!(runner.issuing.is_block_stored(make_hash("c")).await?); + assert!(!runner.issuing.is_block_stored(make_hash("d")).await?); + Ok(()) + } + + #[tokio::test] + async fn submit_next_with_1_confirmation_batch_submission_succeeds() -> Result<(), Error> { + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c"), (5, "d")]); + let issuing_hashes = make_hashes(vec![(2, "a")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + let runner = Runner::new( + backing, + issuing, + Config { + start_height: None, + timeout: Some(Duration::from_secs(0)), + max_batch_size: 16, + required_btc_confirmations: 1, + }, + ); + + let height_before = runner.issuing.get_best_height().await?; + assert_eq!(height_before, 2); + + runner.submit_next().await?; + runner.submit_next().await?; + + let height_after = runner.issuing.get_best_height().await?; + assert_eq!(height_after, 4); + + assert!(runner.issuing.is_block_stored(make_hash("c")).await?); + // this block has not been confirmed yet, so we should not have submitted it + assert!(!runner.issuing.is_block_stored(make_hash("d")).await?); + Ok(()) + } + + #[tokio::test] + async fn submit_next_with_1_confirmation_single_submission_succeeds() -> Result<(), Error> { + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c"), (5, "d")]); + let issuing_hashes = make_hashes(vec![(2, "a")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + let runner = Runner::new( + backing, + issuing, + Config { + start_height: None, + max_batch_size: 1, + timeout: Some(Duration::from_secs(0)), + required_btc_confirmations: 1, + }, + ); + + let height_before = runner.issuing.get_best_height().await?; + assert_eq!(height_before, 2); + + for _ in 0..10 { + runner.submit_next().await?; + } + + let height_after = runner.issuing.get_best_height().await?; + assert_eq!(height_after, 4); + + assert!(runner.issuing.is_block_stored(make_hash("c")).await?); + // this block has not been confirmed yet, so we should not have submitted it + assert!(!runner.issuing.is_block_stored(make_hash("d")).await?); + Ok(()) + } + + #[tokio::test] + async fn submit_next_with_2_confirmation_succeeds() -> Result<(), Error> { + let backing_hashes = make_hashes(vec![(2, "a"), (3, "b"), (4, "c"), (5, "d")]); + let issuing_hashes = make_hashes(vec![(2, "a")]); + let backing = DummyBacking::new(backing_hashes); + let issuing = DummyIssuing::new(issuing_hashes); + let runner = Runner::new( + backing, + issuing, + Config { + start_height: None, + max_batch_size: 1, + timeout: Some(Duration::from_secs(0)), + required_btc_confirmations: 2, + }, + ); + + let height_before = runner.issuing.get_best_height().await?; + assert_eq!(height_before, 2); + + for _ in 0..10 { + runner.submit_next().await?; + } + + let height_after = runner.issuing.get_best_height().await?; + assert_eq!(height_after, 3); + + assert!(runner.issuing.is_block_stored(make_hash("b")).await?); + + // these blocks have not been confirmed yet, so we should not have submitted it + assert!(!runner.issuing.is_block_stored(make_hash("c")).await?); + assert!(!runner.issuing.is_block_stored(make_hash("d")).await?); + Ok(()) + } +} diff --git a/staked-relayer/src/core/types.rs b/staked-relayer/src/core/types.rs new file mode 100644 index 000000000..aed9fe5b6 --- /dev/null +++ b/staked-relayer/src/core/types.rs @@ -0,0 +1,70 @@ +use super::Error; +use async_trait::async_trait; +use std::error::Error as StdError; + +#[async_trait] +pub trait Backing { + /// Returns the height of the longest chain + async fn get_block_count(&self) -> Result>; + + /// Returns the raw header of a block in storage + /// + /// # Arguments + /// + /// * `height` - The height of the block to fetch + async fn get_block_header(&self, height: u32) -> Result>, Error>; + + /// Returns the (little endian) hash of a block + /// + /// # Arguments + /// + /// * `height` - The height of the block to fetch + async fn get_block_hash(&self, height: u32) -> Result, Error>; +} + +#[async_trait] +pub trait Issuing { + /// Returns true if the light client is initialized + async fn is_initialized(&self) -> Result>; + + /// Initialize the light client + /// + /// # Arguments + /// + /// * `header` - Raw block header + /// * `height` - Starting height + async fn initialize(&self, header: Vec, height: u32) -> Result<(), Error>; + + /// Submit a block header and wait for inclusion + /// + /// # Arguments + /// + /// * `header` - Raw block header + async fn submit_block_header(&self, header: Vec) -> Result<(), Error>; + + /// Submit a batch of block headers and wait for inclusion + /// + /// # Arguments + /// + /// * `headers` - Raw block headers (multiple of 80 bytes) + async fn submit_block_header_batch(&self, headers: Vec>) -> Result<(), Error>; + + /// Returns the light client's chain tip + async fn get_best_height(&self) -> Result>; + + /// Returns the block hash stored at a given height, + /// this is assumed to be in little-endian format + /// + /// # Arguments + /// + /// * `height` - Height of the block to fetch + async fn get_block_hash(&self, height: u32) -> Result, Error>; + + /// Returns true if the block described by the hash + /// has been stored in the light client + /// + /// # Arguments + /// + /// * `hash_le` - Hash (little-endian) of the block + async fn is_block_stored(&self, hash_le: Vec) -> Result>; +} diff --git a/staked-relayer/src/error.rs b/staked-relayer/src/error.rs index 3db926934..cc8c7d63c 100644 --- a/staked-relayer/src/error.rs +++ b/staked-relayer/src/error.rs @@ -1,19 +1,17 @@ -use crate::relay::Error as RelayError; +use crate::{core::Error as CoreError, relay::Error as RelayError}; use backoff::ExponentialBackoff; -use bitcoin::BitcoinError as BitcoinCoreError; -use bitcoin::Error as BitcoinError; +use bitcoin::{BitcoinError as BitcoinCoreError, Error as BitcoinError}; use jsonrpc_core_client::RpcError; use jsonrpc_http_server::jsonrpc_core::Error as JsonRpcError; use parity_scale_codec::Error as CodecError; -use relayer_core::Error as CoreError; -use runtime::substrate_subxt::Error as XtError; -use runtime::Error as RuntimeError; -use std::net::AddrParseError; -use std::time::Duration; +use runtime::{substrate_subxt::Error as XtError, Error as RuntimeError}; +use std::{net::AddrParseError, time::Duration}; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { + #[error("Internal error")] + InternalError, #[error("Could not verify that the oracle is offline")] CheckOracleOffline, #[error("Suggested status update does not contain block hash")] diff --git a/staked-relayer/src/faucet.rs b/staked-relayer/src/faucet.rs index 2b7111880..d86b5355c 100644 --- a/staked-relayer/src/faucet.rs +++ b/staked-relayer/src/faucet.rs @@ -1,19 +1,15 @@ -use crate::error::Error; -use crate::http::RawBytes; -use jsonrpc_core_client::TypedClient; +use crate::{error::Error, http::RawBytes}; +use jsonrpc_core_client::{transports::http as jsonrpc_http, TypedClient}; use jsonrpc_http_server::jsonrpc_core::Value; use parity_scale_codec::{Decode, Encode}; -use runtime::AccountId; +use runtime::{AccountId, PolkaBtcProvider, StakedRelayerPallet, UtilFuncs, PLANCK_PER_DOT, TX_FEES}; #[derive(Encode, Decode, Debug, Clone, serde::Serialize)] struct FundAccountJsonRpcRequest { pub account_id: AccountId, } -pub async fn get_funding( - faucet_connection: TypedClient, - staked_relayer_id: AccountId, -) -> Result<(), Error> { +async fn get_funding(faucet_connection: TypedClient, staked_relayer_id: AccountId) -> Result<(), Error> { let funding_request = FundAccountJsonRpcRequest { account_id: staked_relayer_id, }; @@ -24,12 +20,29 @@ pub async fn get_funding( Ok(()) } -pub async fn get_faucet_allowance( - faucet_connection: TypedClient, - allowance_type: &str, -) -> Result { +async fn get_faucet_allowance(faucet_connection: TypedClient, allowance_type: &str) -> Result { let raw_allowance = faucet_connection .call_method::<(), RawBytes>(&allowance_type, "", ()) .await?; Ok(Decode::decode(&mut &raw_allowance.0[..])?) } + +pub async fn fund_and_register(provider: &PolkaBtcProvider, faucet_url: &String) -> Result<(), Error> { + let connection = jsonrpc_http::connect::(faucet_url).await?; + + // Receive user allowance from faucet + get_funding(connection.clone(), provider.get_account_id().clone()).await?; + + let user_allowance_in_dot: u128 = get_faucet_allowance(connection.clone(), "user_allowance").await?; + let registration_stake = user_allowance_in_dot + .checked_mul(PLANCK_PER_DOT) + .ok_or(Error::MathError)? + .checked_sub(TX_FEES) + .ok_or(Error::MathError)?; + provider.register_staked_relayer(registration_stake).await?; + + // Receive staked relayer allowance from faucet + get_funding(connection.clone(), provider.get_account_id().clone()).await?; + + Ok(()) +} diff --git a/staked-relayer/src/http.rs b/staked-relayer/src/http.rs index 51629b6cf..36569de82 100644 --- a/staked-relayer/src/http.rs +++ b/staked-relayer/src/http.rs @@ -1,18 +1,21 @@ use super::Error; -use futures::executor::block_on; use hex::FromHex; -use jsonrpc_http_server::jsonrpc_core::serde_json::Value; -use jsonrpc_http_server::jsonrpc_core::{Error as JsonRpcError, ErrorCode as JsonRpcErrorCode}; -use jsonrpc_http_server::jsonrpc_core::{IoHandler, Params}; -use jsonrpc_http_server::{DomainsValidation, ServerBuilder}; +use jsonrpc_http_server::{ + jsonrpc_core::{serde_json::Value, Error as JsonRpcError, ErrorCode as JsonRpcErrorCode, IoHandler, Params}, + DomainsValidation, ServerBuilder, +}; +use log::info; use parity_scale_codec::{Decode, Encode}; -use runtime::ErrorCode as PolkaBtcErrorCode; -use runtime::StatusCode as PolkaBtcStatusCode; -use runtime::{H256Le, PolkaBtcProvider, SecurityPallet, StakedRelayerPallet, UtilFuncs}; +use runtime::{ + Error as RuntimeError, ErrorCode as PolkaBtcErrorCode, H256Le, PolkaBtcProvider, StakedRelayerPallet, + StatusCode as PolkaBtcStatusCode, UtilFuncs, +}; use serde::{Deserialize, Deserializer}; use sp_core::crypto::Ss58Codec; -use std::net::SocketAddr; -use std::sync::Arc; +use std::{net::SocketAddr, time::Duration}; +use tokio::time::timeout; + +const HEALTH_DURATION: Duration = Duration::from_millis(5000); #[derive(Debug, Clone, Deserialize)] pub(crate) struct RawBytes(#[serde(deserialize_with = "hex_to_buffer")] pub(crate) Vec); @@ -22,9 +25,8 @@ where D: Deserializer<'de>, { use serde::de::Error; - String::deserialize(deserializer).and_then(|string| { - Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string())) - }) + String::deserialize(deserializer) + .and_then(|string| Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string()))) } fn parse_params(params: Params) -> Result { @@ -44,9 +46,11 @@ fn handle_resp(resp: Result) -> Result } } -fn _system_health(provider: &Arc) -> Result<(), Error> { - block_on(provider.get_parachain_status())?; - Ok(()) +async fn _system_health(provider: &PolkaBtcProvider) -> Result<(), Error> { + match timeout(HEALTH_DURATION, provider.get_latest_block_hash()).await { + Err(err) => Err(Error::RuntimeError(RuntimeError::from(err))), + _ => Ok(()), + } } #[derive(Encode, Decode, Debug)] @@ -54,7 +58,7 @@ struct AccountIdJsonRpcResponse { account_id: String, } -fn _account_id(provider: &Arc) -> Result { +fn _account_id(provider: &PolkaBtcProvider) -> Result { Ok(AccountIdJsonRpcResponse { account_id: provider.get_account_id().to_ss58check(), }) @@ -65,13 +69,13 @@ struct RegisterStakedRelayerJsonRpcRequest { stake: u128, } -fn _register_staked_relayer(provider: &Arc, params: Params) -> Result<(), Error> { +async fn _register_staked_relayer(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { let req: RegisterStakedRelayerJsonRpcRequest = parse_params(params)?; - Ok(block_on(provider.register_staked_relayer(req.stake))?) + Ok(provider.register_staked_relayer(req.stake).await?) } -fn _deregister_staked_relayer(provider: &Arc) -> Result<(), Error> { - Ok(block_on(provider.deregister_staked_relayer())?) +async fn _deregister_staked_relayer(provider: &PolkaBtcProvider) -> Result<(), Error> { + Ok(provider.deregister_staked_relayer().await?) } #[derive(Encode, Decode, Debug)] @@ -84,16 +88,18 @@ struct SuggestStatusUpdateJsonRpcRequest { message: String, } -fn _suggest_status_update(provider: &Arc, params: Params) -> Result<(), Error> { +async fn _suggest_status_update(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { let req: SuggestStatusUpdateJsonRpcRequest = parse_params(params)?; - Ok(block_on(provider.suggest_status_update( - req.deposit, - req.status_code, - req.add_error, - req.remove_error, - req.block_hash, - req.message, - ))?) + Ok(provider + .suggest_status_update( + req.deposit, + req.status_code, + req.add_error, + req.remove_error, + req.block_hash, + req.message, + ) + .await?) } #[derive(Encode, Decode, Debug)] @@ -102,60 +108,77 @@ struct VoteOnStatusUpdateJsonRpcRequest { pub approve: bool, } -fn _vote_on_status_update(provider: &Arc, params: Params) -> Result<(), Error> { +async fn _vote_on_status_update(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { let req: VoteOnStatusUpdateJsonRpcRequest = parse_params(params)?; - Ok(block_on( - provider.vote_on_status_update(req.status_update_id, req.approve), - )?) + Ok(provider + .vote_on_status_update(req.status_update_id, req.approve) + .await?) } -pub async fn start(provider: Arc, addr: SocketAddr, origin: String) { +pub fn start_http( + provider: PolkaBtcProvider, + addr: SocketAddr, + origin: String, + handle: tokio::runtime::Handle, +) -> jsonrpc_http_server::CloseHandle { let mut io = IoHandler::default(); { let provider = provider.clone(); - io.add_sync_method("system_health", move |_| { - handle_resp(_system_health(&provider)) + io.add_method("system_health", move |_| { + let provider = provider.clone(); + async move { handle_resp(_system_health(&provider).await) } }); } { let provider = provider.clone(); - io.add_sync_method("account_id", move |_| handle_resp(_account_id(&provider))); + io.add_method("account_id", move |_| { + let provider = provider.clone(); + async move { handle_resp(_account_id(&provider)) } + }); } { let provider = provider.clone(); - io.add_sync_method("register_staked_relayer", move |params| { - handle_resp(_register_staked_relayer(&provider, params)) + io.add_method("register_staked_relayer", move |params| { + let provider = provider.clone(); + async move { handle_resp(_register_staked_relayer(&provider, params).await) } }); } { let provider = provider.clone(); - io.add_sync_method("deregister_staked_relayer", move |_| { - handle_resp(_deregister_staked_relayer(&provider)) + io.add_method("deregister_staked_relayer", move |_| { + let provider = provider.clone(); + async move { handle_resp(_deregister_staked_relayer(&provider).await) } }); } { let provider = provider.clone(); - io.add_sync_method("suggest_status_update", move |params| { - handle_resp(_suggest_status_update(&provider, params)) + io.add_method("suggest_status_update", move |params| { + let provider = provider.clone(); + async move { handle_resp(_suggest_status_update(&provider, params).await) } }); } { let provider = provider.clone(); - io.add_sync_method("vote_on_status_update", move |params| { - handle_resp(_vote_on_status_update(&provider, params)) + io.add_method("vote_on_status_update", move |params| { + let provider = provider.clone(); + async move { handle_resp(_vote_on_status_update(&provider, params).await) } }); } let server = ServerBuilder::new(io) + .event_loop_executor(handle.clone()) .health_api(("/health", "system_health")) .rest_api(jsonrpc_http_server::RestApi::Unsecure) .cors(DomainsValidation::AllowOnly(vec![origin.into()])) .start_http(&addr) .expect("Unable to start RPC server"); - tokio::task::spawn_blocking(move || { + let close_handle = server.close_handle(); + + handle.spawn_blocking(move || { + info!("Starting http server..."); server.wait(); - }) - .await - .unwrap(); + }); + + close_handle } diff --git a/staked-relayer/src/lib.rs b/staked-relayer/src/lib.rs index d926965f8..6f5163061 100644 --- a/staked-relayer/src/lib.rs +++ b/staked-relayer/src/lib.rs @@ -1,23 +1,25 @@ +mod core; mod error; mod faucet; mod http; mod oracle; -pub mod relay; mod status; -mod utils; mod vault; +pub mod relay; +pub mod system; +pub mod utils; + pub use error::Error; pub use vault::Vaults; pub mod service { - pub use crate::faucet::get_faucet_allowance; - pub use crate::faucet::get_funding; - pub use crate::http::start as start_api; - pub use crate::oracle::report_offline_oracle; - pub use crate::status::listen_for_blocks_stored; - pub use crate::status::listen_for_status_updates; - pub use crate::vault::listen_for_vaults_registered; - pub use crate::vault::listen_for_wallet_updates; - pub use crate::vault::report_vault_thefts; + pub use crate::{ + core::{Config, Runner}, + faucet::fund_and_register, + http::start_http, + oracle::report_offline_oracle, + status::{listen_for_blocks_stored, listen_for_status_updates}, + vault::{listen_for_vaults_registered, listen_for_wallet_updates, report_vault_thefts}, + }; } diff --git a/staked-relayer/src/main.rs b/staked-relayer/src/main.rs index 3bceeb7cb..f419b6afa 100644 --- a/staked-relayer/src/main.rs +++ b/staked-relayer/src/main.rs @@ -1,27 +1,26 @@ -use staked_relayer::relay::{BitcoinClient, PolkaBtcClient}; -use staked_relayer::service::*; -use staked_relayer::Error; -use staked_relayer::Vaults; +use staked_relayer::{system::*, Error}; -use bitcoin::{BitcoinCore, BitcoinCoreApi as _}; +use bitcoin::BitcoinCore; use clap::Clap; -use jsonrpc_core_client::{transports::http as jsonrpc_http, TypedClient}; -use log::*; -use relayer_core::{Config, Runner}; -use runtime::pallets::sla::UpdateRelayerSLAEvent; -use runtime::{substrate_subxt::PairSigner, StakedRelayerPallet, UtilFuncs}; -use runtime::{PolkaBtcProvider, PolkaBtcRuntime, PLANCK_PER_DOT, TX_FEES}; -use std::sync::Arc; -use std::time::Duration; +use runtime::{substrate_subxt::PairSigner, ConnectionManager, PolkaBtcRuntime}; +use std::{sync::Arc, time::Duration}; /// The Staked Relayer client intermediates between Bitcoin Core /// and the PolkaBTC Parachain. #[derive(Clap)] -#[clap(version = "0.1", author = "Interlay ")] +#[clap(version = "0.2", author = "Interlay ")] struct Opts { - /// Parachain URL, can be over WebSockets or HTTP. - #[clap(long, default_value = "ws://127.0.0.1:9944")] - polka_btc_url: String, + /// Keyring / keyfile options. + #[clap(flatten)] + account_info: runtime::cli::ProviderUserOpts, + + /// Connection settings for the BTC-Parachain. + #[clap(flatten)] + parachain: runtime::cli::ConnectionOpts, + + /// Connection settings for Bitcoin Core. + #[clap(flatten)] + bitcoin: bitcoin::cli::BitcoinOpts, /// Address to listen on for JSON-RPC requests. #[clap(long, default_value = "[::0]:3030")] @@ -30,16 +29,16 @@ struct Opts { /// Starting height for vault theft checks, if not defined /// automatically start from the chain tip. #[clap(long)] - scan_start_height: Option, + bitcoin_theft_start_height: Option, - /// Delay for checking Bitcoin for new blocks (in seconds). - #[clap(long, default_value = "60")] - scan_block_delay: u64, + /// Timeout in milliseconds to poll Bitcoin. + #[clap(long, default_value = "6000")] + bitcoin_poll_timeout_ms: u64, /// Starting height to relay block headers, if not defined /// use the best height as reported by the relay module. #[clap(long)] - relay_start_height: Option, + bitcoin_relay_start_height: Option, /// Max batch size for combined block header submission. #[clap(long, default_value = "16")] @@ -57,197 +56,71 @@ struct Opts { #[clap(long, default_value = "*")] rpc_cors_domain: String, - /// keyring / keyfile options. - #[clap(flatten)] - account_info: runtime::cli::ProviderUserOpts, - - /// Connection settings for Bitcoin Core. - #[clap(flatten)] - bitcoin: bitcoin::cli::BitcoinOpts, - /// Automatically register the relayer with the given stake (in Planck). - #[clap(long, conflicts_with("auto-register-with-faucet-url"))] - pub auto_register_with_stake: Option, - - /// Automatically register the staked relayer with collateral received from the faucet and a newly generated address. - /// The parameter is the URL of the faucet #[clap(long)] + auto_register_with_stake: Option, + + /// Automatically register the staked relayer with collateral received from the faucet and a newly generated + /// address. The parameter is the URL of the faucet + #[clap(long, conflicts_with("auto-register-with-stake"))] auto_register_with_faucet_url: Option, -} -async fn is_registered(provider: &Arc) -> Result { - let account_id = provider.get_account_id(); - // get stake returns 0 if not registered, so check that either active or inactive stake is non-zero - match provider.get_stake_by_id(account_id.clone()).await { - Ok(x) if x > 0 => Ok(true), - _ => Ok(provider - .get_inactive_stake_by_id(account_id.clone()) - .await? - > 0), - } + /// Number of confirmations a block needs to have before it is submitted. + #[clap(long, default_value = "0")] + required_btc_confirmations: u32, } -#[tokio::main] -async fn main() -> Result<(), Error> { - env_logger::init(); +async fn start() -> Result<(), Error> { + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, log::LevelFilter::Info.as_str()), + ); let opts: Opts = Opts::parse(); - let http_addr = opts.http_addr.parse()?; - let oracle_timeout_ms = opts.oracle_timeout_ms; - - let (key_pair, _) = opts.account_info.get_key_pair()?; - let signer = PairSigner::::new(key_pair); - let provider = Arc::new(PolkaBtcProvider::from_url(opts.polka_btc_url, signer).await?); - - if let Some(stake) = opts.auto_register_with_stake { - if !is_registered(&provider).await? { - provider.register_staked_relayer(stake).await?; - info!("Automatically registered staked relayer"); - } else { - info!("Not registering staked relayer -- already registered"); - } - } let dummy_network = bitcoin::Network::Regtest; // we don't make any transaction so this is not used - let btc_rpc = Arc::new(BitcoinCore::new( - opts.bitcoin.new_client(None)?, + let bitcoin_core = BitcoinCore::new_with_retry( + Arc::new(opts.bitcoin.new_client(None)?), dummy_network, - )); + Duration::from_millis(opts.bitcoin.bitcoin_connection_timeout_ms), + ) + .await?; - let relayer = Runner::new( - PolkaBtcClient::new(provider.clone()), - BitcoinClient::new(opts.bitcoin.new_client(None)?), - Config { - start_height: opts.relay_start_height, + let (key_pair, _) = opts.account_info.get_key_pair()?; + let signer = PairSigner::::new(key_pair); + + // only open connection to parachain after bitcoind sync to prevent timeout + ConnectionManager::<_, _, RelayerService>::new( + opts.parachain.polka_btc_url.clone(), + signer.clone(), + RelayerServiceConfig { + bitcoin_core, + auto_register_with_stake: opts.auto_register_with_stake, + auto_register_with_faucet_url: opts.auto_register_with_faucet_url, + bitcoin_theft_start_height: opts.bitcoin_theft_start_height, + bitcoin_relay_start_height: opts.bitcoin_relay_start_height, max_batch_size: opts.max_batch_size, - timeout: Some(Duration::from_secs(opts.scan_block_delay)), + bitcoin_timeout: Duration::from_millis(opts.bitcoin_poll_timeout_ms), + oracle_timeout: Duration::from_millis(opts.oracle_timeout_ms), + required_btc_confirmations: opts.required_btc_confirmations, + status_update_deposit: opts.status_update_deposit, + http_addr: opts.http_addr.parse()?, + rpc_cors_domain: opts.rpc_cors_domain, }, - )?; - - let oracle_monitor = - report_offline_oracle(provider.clone(), Duration::from_millis(oracle_timeout_ms)); - - let vaults = provider - .get_all_vaults() - .await? - .into_iter() - .flat_map(|vault| { - vault - .wallet - .addresses - .iter() - .map(|addr| (addr.clone(), vault.id.clone())) - .collect::>() - }) - .collect(); - - // store vaults in Arc - let vaults = Arc::new(Vaults::from(vaults)); - // scan from custom height or the current tip - let scan_start_height = opts - .scan_start_height - .unwrap_or(btc_rpc.get_block_count().await? as u32 + 1); - let vaults_monitor = report_vault_thefts( - scan_start_height, - btc_rpc.clone(), - vaults.clone(), - provider.clone(), - Duration::from_secs(opts.scan_block_delay), - ); + opts.parachain.into(), + tokio::runtime::Handle::current(), + ) + .start() + .await?; - let wallet_update_listener = listen_for_wallet_updates(provider.clone(), vaults.clone()); - let vaults_listener = listen_for_vaults_registered(provider.clone(), vaults); - let status_update_listener = listen_for_status_updates(btc_rpc.clone(), provider.clone()); - let relay_listener = listen_for_blocks_stored( - btc_rpc.clone(), - provider.clone(), - opts.status_update_deposit, - ); + Ok(()) +} - let api = start_api(provider.clone(), http_addr, opts.rpc_cors_domain); - - if let Some(faucet_url) = opts.auto_register_with_faucet_url { - let connection = jsonrpc_http::connect::(&faucet_url).await?; - - // Receive user allowance from faucet - match get_funding( - connection.clone(), - provider.clone().get_account_id().clone(), - ) - .await - { - Ok(_) => { - let user_allowance_in_dot: u128 = - get_faucet_allowance(connection.clone(), "user_allowance").await?; - let registration_stake = user_allowance_in_dot - .checked_mul(PLANCK_PER_DOT) - .ok_or(Error::MathError)? - .checked_sub(TX_FEES) - .ok_or(Error::MathError)?; - if !is_registered(&provider).await? { - provider.register_staked_relayer(registration_stake).await?; - } - } - Err(e) => error!("Faucet error: {}", e.to_string()), - } - - // Receive staked relayer allowance from faucet - if let Err(e) = get_funding( - connection.clone(), - provider.clone().get_account_id().clone(), - ) - .await - { - error!("Faucet error: {}", e.to_string()) - }; - } - - let result = tokio::try_join!( - tokio::spawn(async move { - let relayer_id = provider.get_account_id(); - provider - .on_event::, _, _, _>( - |event| async move { - if &event.relayer_id == relayer_id { - info!("Received event: new total SLA score = {:?}", event.new_sla); - } - }, - |err| error!("Error (UpdateRelayerSLAEvent): {}", err.to_string()), - ) - .await - .unwrap(); - }), - // runs json-rpc server for incoming requests - tokio::spawn(async move { api.await }), - // keep track of all registered vaults (i.e. keep the `vaults` map up-to-date) - tokio::spawn(async move { vaults_listener.await.unwrap() }), - // runs vault theft checks - tokio::spawn(async move { - vaults_monitor.await.unwrap(); - }), - // keep vault wallets up-to-date - tokio::spawn(async move { - wallet_update_listener.await.unwrap(); - }), - // runs oracle liveness check - tokio::spawn(async move { oracle_monitor.await }), - // runs `NO_DATA` checks and submits status updates - tokio::spawn(async move { - relay_listener.await.unwrap(); - }), - // runs subscription service for status updates - tokio::spawn(async move { - status_update_listener.await.unwrap(); - }), - tokio::task::spawn_blocking(move || relayer.run().unwrap()) - ); - match result { - Ok(res) => { - println!("{:?}", res); - } - Err(err) => { - println!("Error: {}", err); - std::process::exit(1); - } +#[tokio::main] +async fn main() { + let exit_code = if let Err(err) = start().await { + eprintln!("Error: {}", err); + 1 + } else { + 0 }; - Ok(()) + std::process::exit(exit_code); } diff --git a/staked-relayer/src/oracle.rs b/staked-relayer/src/oracle.rs index 5238c8a6c..060470e21 100644 --- a/staked-relayer/src/oracle.rs +++ b/staked-relayer/src/oracle.rs @@ -1,36 +1,29 @@ use super::Error; use crate::utils; use log::info; -use runtime::{ - ErrorCode, ExchangeRateOraclePallet, SecurityPallet, StakedRelayerPallet, TimestampPallet, - MINIMUM_STAKE, -}; -use std::sync::Arc; +use runtime::{ErrorCode, ExchangeRateOraclePallet, SecurityPallet, StakedRelayerPallet, TimestampPallet}; use std::time::Duration; +use tokio::time::delay_for; pub async fn report_offline_oracle< P: TimestampPallet + ExchangeRateOraclePallet + StakedRelayerPallet + SecurityPallet, >( - rpc: Arc

, - checking_interval: Duration, -) { + rpc: P, + duration: Duration, +) -> Result<(), Error> { let monitor = OracleMonitor::new(rpc); - utils::check_every(checking_interval, || async { - monitor.report_offline().await - }) - .await + loop { + delay_for(duration).await; + monitor.report_offline().await?; + } } -pub struct OracleMonitor< - P: TimestampPallet + ExchangeRateOraclePallet + StakedRelayerPallet + SecurityPallet, -> { - rpc: Arc

, +pub struct OracleMonitor { + rpc: P, } -impl - OracleMonitor

-{ - pub fn new(rpc: Arc

) -> Self { +impl OracleMonitor

{ + pub fn new(rpc: P) -> Self { Self { rpc } } @@ -46,7 +39,8 @@ impl Result<(), Error> { - if self.rpc.get_stake().await? < MINIMUM_STAKE { + if !utils::is_active(&self.rpc).await? { + // not registered (active), ignore check return Ok(()); } @@ -69,13 +63,11 @@ impl Result; - async fn get_stake_by_id(&self, account_id: AccountId) -> Result; + async fn get_active_stake(&self) -> Result; + async fn get_active_stake_by_id(&self, account_id: AccountId) -> Result; async fn get_inactive_stake_by_id(&self, account_id: AccountId) -> Result; async fn register_staked_relayer(&self, stake: u128) -> Result<(), Error>; async fn deregister_staked_relayer(&self) -> Result<(), Error>; @@ -146,6 +138,13 @@ mod tests { } } + impl Clone for MockProvider { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + #[tokio::test] async fn test_is_oracle_offline_true() { let mut parachain = MockProvider::default(); @@ -154,13 +153,7 @@ mod tests { .returning(|| Ok((FixedU128::one(), 0, 0))); parachain.expect_get_time_now().returning(|| Ok(1)); - assert_eq!( - OracleMonitor::new(Arc::new(parachain)) - .is_offline() - .await - .unwrap(), - true - ); + assert_eq!(OracleMonitor::new(parachain).is_offline().await.unwrap(), true); } #[tokio::test] @@ -171,20 +164,14 @@ mod tests { .returning(|| Ok((FixedU128::one(), 1, 3))); parachain.expect_get_time_now().returning(|| Ok(2)); - assert_eq!( - OracleMonitor::new(Arc::new(parachain)) - .is_offline() - .await - .unwrap(), - false - ); + assert_eq!(OracleMonitor::new(parachain).is_offline().await.unwrap(), false); } #[tokio::test] async fn test_report_oracle_offline_not_reported() { let mut parachain = MockProvider::default(); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); @@ -199,22 +186,16 @@ mod tests { .expect_get_error_codes() .once() .returning(|| Ok(BTreeSet::new())); - parachain - .expect_report_oracle_offline() - .once() - .returning(|| Ok(())); + parachain.expect_report_oracle_offline().once().returning(|| Ok(())); - OracleMonitor::new(Arc::new(parachain)) - .report_offline() - .await - .unwrap(); + OracleMonitor::new(parachain).report_offline().await.unwrap(); } #[tokio::test] async fn test_report_oracle_offline_already_reported() { let mut parachain = MockProvider::default(); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); @@ -229,14 +210,8 @@ mod tests { .expect_get_error_codes() .once() .returning(|| Ok(BTreeSet::from_iter(vec![ErrorCode::OracleOffline]))); - parachain - .expect_report_oracle_offline() - .never() - .returning(|| Ok(())); - - OracleMonitor::new(Arc::new(parachain)) - .report_offline() - .await - .unwrap(); + parachain.expect_report_oracle_offline().never().returning(|| Ok(())); + + OracleMonitor::new(parachain).report_offline().await.unwrap(); } } diff --git a/staked-relayer/src/relay/backing.rs b/staked-relayer/src/relay/backing.rs index d30e739b6..b8a442604 100644 --- a/staked-relayer/src/relay/backing.rs +++ b/staked-relayer/src/relay/backing.rs @@ -1,28 +1,32 @@ use super::Error; -use bitcoin::{serialize, Client as RPC, RpcApi}; -use relayer_core::{Backing, Error as CoreError}; +use crate::core::{Backing, Error as CoreError}; +use async_trait::async_trait; +use bitcoin::serialize; +pub use bitcoin::{BitcoinCore, BitcoinCoreApi}; pub struct Client { - rpc: RPC, + bitcoin_core: BitcoinCore, } impl Client { - pub fn new(rpc: RPC) -> Self { - Client { rpc } + pub fn new(bitcoin_core: BitcoinCore) -> Self { + Client { bitcoin_core } } } +#[async_trait] impl Backing for Client { - fn get_block_count(&self) -> Result> { + async fn get_block_count(&self) -> Result> { let count = self - .rpc + .bitcoin_core .get_block_count() + .await .map_err(|e| CoreError::Backing(Error::BitcoinError(e)))?; return Ok(count as u32); } - fn get_block_header(&self, height: u32) -> Result>, CoreError> { - let block_hash = match self.rpc.get_block_hash(height as u64) { + async fn get_block_header(&self, height: u32) -> Result>, CoreError> { + let block_hash = match self.bitcoin_core.get_block_hash(height).await { Ok(h) => h, Err(_) => { // TODO: match error @@ -30,16 +34,18 @@ impl Backing for Client { } }; let block_header = self - .rpc + .bitcoin_core .get_block_header(&block_hash) + .await .map_err(|e| CoreError::Backing(Error::BitcoinError(e)))?; Ok(Some(serialize(&block_header))) } - fn get_block_hash(&self, height: u32) -> Result, CoreError> { + async fn get_block_hash(&self, height: u32) -> Result, CoreError> { let block_hash = self - .rpc - .get_block_hash(height as u64) + .bitcoin_core + .get_block_hash(height) + .await .map(|hash| serialize(&hash)) .map_err(|e| CoreError::Backing(Error::BitcoinError(e)))?; Ok(block_hash) diff --git a/staked-relayer/src/relay/error.rs b/staked-relayer/src/relay/error.rs index 9c94e9622..2dc375787 100644 --- a/staked-relayer/src/relay/error.rs +++ b/staked-relayer/src/relay/error.rs @@ -1,4 +1,4 @@ -use bitcoin::BitcoinError; +use bitcoin::Error as BitcoinError; use runtime::Error as PolkaBtcError; use thiserror::Error; diff --git a/staked-relayer/src/relay/issuing.rs b/staked-relayer/src/relay/issuing.rs index 62e580042..161b18d45 100644 --- a/staked-relayer/src/relay/issuing.rs +++ b/staked-relayer/src/relay/issuing.rs @@ -1,17 +1,14 @@ use super::Error; -use futures::executor::block_on; -use log::error; -use relayer_core::{Error as CoreError, Issuing}; -use runtime::PolkaBtcProvider; -use runtime::{BtcRelayPallet, H256Le, RawBlockHeader}; -use std::sync::Arc; +use crate::core::{Error as CoreError, Issuing}; +use async_trait::async_trait; +use runtime::{BtcRelayPallet, H256Le, PolkaBtcProvider, RawBlockHeader}; pub struct Client { - rpc: Arc, + rpc: PolkaBtcProvider, } impl Client { - pub fn new(rpc: Arc) -> Self { + pub fn new(rpc: PolkaBtcProvider) -> Self { Self { rpc } } } @@ -20,60 +17,71 @@ fn encode_raw_header(bytes: Vec) -> Result> RawBlockHeader::from_bytes(bytes).map_err(|_| CoreError::Issuing(Error::SerializeHeader)) } +#[async_trait] impl Issuing for Client { - fn is_initialized(&self) -> Result> { - let hash = block_on(self.rpc.get_best_block()) + async fn is_initialized(&self) -> Result> { + let hash = self + .rpc + .get_best_block() + .await .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e)))?; Ok(!hash.is_zero()) } - fn initialize(&self, header: Vec, height: u32) -> Result<(), CoreError> { - block_on( - self.rpc - .initialize_btc_relay(encode_raw_header(header)?, height), - ) - .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e))) + async fn initialize(&self, header: Vec, height: u32) -> Result<(), CoreError> { + self.rpc + .initialize_btc_relay(encode_raw_header(header)?, height) + .await + .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e))) } - fn submit_block_header(&self, header: Vec) -> Result<(), CoreError> { + async fn submit_block_header(&self, header: Vec) -> Result<(), CoreError> { let raw_block_header = encode_raw_header(header)?; - if self.is_block_stored(raw_block_header.hash().to_bytes_le().to_vec())? { + if self + .is_block_stored(raw_block_header.hash().to_bytes_le().to_vec()) + .await? + { return Ok(()); } - block_on(self.rpc.store_block_header(raw_block_header)).map_err(|e| { - error!("Failed to submit block: {}", e); - CoreError::Issuing(Error::PolkaBtcError(e)) - }) + self.rpc + .store_block_header(raw_block_header) + .await + .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e))) } - fn submit_block_header_batch(&self, headers: Vec>) -> Result<(), CoreError> { - block_on( - self.rpc.store_block_headers( + async fn submit_block_header_batch(&self, headers: Vec>) -> Result<(), CoreError> { + self.rpc + .store_block_headers( headers .iter() .map(|header| encode_raw_header(header.to_vec())) .collect::, _>>()?, - ), - ) - .map_err(|e| { - error!("Failed to submit blocks: {}", e); - CoreError::Issuing(Error::PolkaBtcError(e)) - }) + ) + .await + .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e))) } - fn get_best_height(&self) -> Result> { - block_on(self.rpc.get_best_block_height()) + async fn get_best_height(&self) -> Result> { + self.rpc + .get_best_block_height() + .await .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e))) } - fn get_block_hash(&self, height: u32) -> Result, CoreError> { - let hash = block_on(self.rpc.get_block_hash(height)) + async fn get_block_hash(&self, height: u32) -> Result, CoreError> { + let hash = self + .rpc + .get_block_hash(height) + .await .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e)))?; hex::decode(hash.to_hex_le()).map_err(|_| CoreError::Issuing(Error::DecodeHash)) } - fn is_block_stored(&self, hash_le: Vec) -> Result> { - let head = block_on(self.rpc.get_block_header(H256Le::from_bytes_le(&hash_le))) + async fn is_block_stored(&self, hash_le: Vec) -> Result> { + let head = self + .rpc + .get_block_header(H256Le::from_bytes_le(&hash_le)) + .await .map_err(|e| CoreError::Issuing(Error::PolkaBtcError(e)))?; Ok(head.block_height > 0) } diff --git a/staked-relayer/src/relay/mod.rs b/staked-relayer/src/relay/mod.rs index 3c8b284f0..526467e66 100644 --- a/staked-relayer/src/relay/mod.rs +++ b/staked-relayer/src/relay/mod.rs @@ -7,3 +7,34 @@ pub use error::Error; pub use backing::Client as BitcoinClient; pub use issuing::Client as PolkaBtcClient; + +use crate::core::{Error as CoreError, Runner}; +use log::{error, info}; +use runtime::{ + substrate_subxt::{Error as SubxtError, ModuleError as SubxtModuleError, RuntimeError as SubxtRuntimeError}, + Error as RuntimeError, PolkaBtcProvider, BTC_RELAY_MODULE, DUPLICATE_BLOCK_ERROR, +}; +use std::time::Duration; + +pub async fn run_relayer( + runner: Runner, + provider: PolkaBtcProvider, + timeout: Duration, +) { + loop { + super::utils::wait_until_registered(&provider, timeout).await; + match runner.submit_next().await { + Ok(_) => (), + Err(CoreError::Issuing(Error::PolkaBtcError(RuntimeError::XtError(SubxtError::Runtime( + SubxtRuntimeError::Module(SubxtModuleError { ref module, ref error }), + ))))) + if module == BTC_RELAY_MODULE && error == DUPLICATE_BLOCK_ERROR => + { + info!("Attempted to submit block that already exists") + } + Err(err) => { + error!("Failed to submit_next: {}", err); + } + } + } +} diff --git a/staked-relayer/src/status.rs b/staked-relayer/src/status.rs index 4b02ef0ab..43be8d98c 100644 --- a/staked-relayer/src/status.rs +++ b/staked-relayer/src/status.rs @@ -1,44 +1,35 @@ use super::Error; use crate::utils; -use bitcoin::{ - BitcoinCoreApi, BlockHash, ConversionError as BitcoinConversionError, Error as BitcoinError, - Hash, -}; +use bitcoin::{BitcoinCoreApi, BlockHash, ConversionError as BitcoinConversionError, Error as BitcoinError, Hash}; use log::{error, info, warn}; use runtime::{ pallets::{btc_relay::StoreMainChainHeaderEvent, staked_relayers::StatusUpdateSuggestedEvent}, - Error as RuntimeError, ErrorCode, H256Le, PolkaBtcProvider, PolkaBtcRuntime, - StakedRelayerPallet, StatusCode, UtilFuncs, + Error as RuntimeError, ErrorCode, H256Le, PolkaBtcProvider, PolkaBtcRuntime, StakedRelayerPallet, StatusCode, + UtilFuncs, }; -use std::sync::Arc; type PolkaBtcStatusUpdateSuggestedEvent = StatusUpdateSuggestedEvent; -pub struct StatusUpdateMonitor { - btc_rpc: Arc, - polka_rpc: Arc

, +pub struct StatusUpdateMonitor { + btc_rpc: B, + polka_rpc: P, } -impl StatusUpdateMonitor { - pub fn new(btc_rpc: Arc, polka_rpc: Arc

) -> Self { +impl StatusUpdateMonitor { + pub fn new(btc_rpc: B, polka_rpc: P) -> Self { Self { btc_rpc, polka_rpc } } - async fn on_status_update_suggested( - &self, - event: PolkaBtcStatusUpdateSuggestedEvent, - ) -> Result<(), Error> { - if !utils::is_registered(&self.polka_rpc).await { + async fn on_status_update_suggested(&self, event: PolkaBtcStatusUpdateSuggestedEvent) -> Result<(), Error> { + if !utils::is_active(&self.polka_rpc).await? { + // not registered (active), ignore event return Ok(()); } + // we can only automate NO_DATA checks, all other suggestible // status updates can only be voted upon manually if let Some(ErrorCode::NoDataBTCRelay) = event.add_error { - match self - .btc_rpc - .is_block_known(convert_block_hash(event.block_hash)?) - .await - { + match self.btc_rpc.is_block_known(convert_block_hash(event.block_hash)?).await { Ok(true) => { self.polka_rpc .vote_on_status_update(event.status_update_id, false) @@ -57,9 +48,9 @@ impl StatusUpdateMonitor { } } -pub async fn listen_for_status_updates( - btc_rpc: Arc, - polka_rpc: Arc, +pub async fn listen_for_status_updates( + btc_rpc: B, + polka_rpc: PolkaBtcProvider, ) -> Result<(), RuntimeError> { let monitor = &StatusUpdateMonitor::new(btc_rpc, polka_rpc.clone()); @@ -81,14 +72,14 @@ pub async fn listen_for_status_updates( .await } -pub struct RelayMonitor { - btc_rpc: Arc, - polka_rpc: Arc

, +pub struct RelayMonitor { + btc_rpc: B, + polka_rpc: P, status_update_deposit: u128, } async fn report_no_data_btc_relay( - rpc: &Arc

, + rpc: &P, deposit: u128, block_hash: H256Le, ) -> Result<(), Error> { @@ -104,8 +95,8 @@ async fn report_no_data_btc_relay( .await?) } -impl RelayMonitor { - pub fn new(btc_rpc: Arc, polka_rpc: Arc

, status_update_deposit: u128) -> Self { +impl RelayMonitor { + pub fn new(btc_rpc: B, polka_rpc: P, status_update_deposit: u128) -> Self { Self { btc_rpc, polka_rpc, @@ -113,48 +104,35 @@ impl RelayMonitor { } } - pub async fn on_store_block( - &self, - height: u32, - parachain_block_hash: H256Le, - ) -> Result<(), Error> { - if !utils::is_registered(&self.polka_rpc).await { + pub async fn on_store_block(&self, height: u32, parachain_block_hash: H256Le) -> Result<(), Error> { + if !utils::is_active(&self.polka_rpc).await? { + // not registered (active), ignore event return Ok(()); } - info!("Block submission: {}", parachain_block_hash); // TODO: check if user submitted - match self.btc_rpc.get_block_hash_for(height).await { + info!("Block submission: {}", parachain_block_hash); + match self.btc_rpc.get_block_hash(height).await { Ok(bitcoin_block_hash) => { if bitcoin_block_hash.into_inner() != parachain_block_hash.to_bytes_le() { warn!("Block does not match at height {}", height); - report_no_data_btc_relay( - &self.polka_rpc, - self.status_update_deposit, - parachain_block_hash, - ) - .await?; + report_no_data_btc_relay(&self.polka_rpc, self.status_update_deposit, parachain_block_hash).await?; } } Err(BitcoinError::InvalidBitcoinHeight) => { warn!("Block does not exist at height {}", height); - report_no_data_btc_relay( - &self.polka_rpc, - self.status_update_deposit, - parachain_block_hash, - ) - .await?; + report_no_data_btc_relay(&self.polka_rpc, self.status_update_deposit, parachain_block_hash).await?; } - Err(e) => error!("Got error on get_block_hash_for({}): {}", height, e), + Err(e) => error!("Got error on get_block_hash({}): {}", height, e), } Ok(()) } } -pub async fn listen_for_blocks_stored( - btc_rpc: Arc, - polka_rpc: Arc, +pub async fn listen_for_blocks_stored( + btc_rpc: B, + polka_rpc: PolkaBtcProvider, status_update_deposit: u128, ) -> Result<(), RuntimeError> { let monitor = &RelayMonitor::new(btc_rpc, polka_rpc.clone(), status_update_deposit); @@ -186,11 +164,12 @@ mod tests { use super::*; use async_trait::async_trait; use bitcoin::{ - Block, GetBlockResult, LockedTransaction, PartialAddress, Transaction, TransactionMetadata, - Txid, PUBLIC_KEY_SIZE, + Block, BlockHeader, GetBlockResult, LockedTransaction, PartialAddress, Transaction, TransactionMetadata, Txid, + PUBLIC_KEY_SIZE, + }; + use runtime::{ + AccountId, Error as RuntimeError, ErrorCode, H256Le, PolkaBtcStatusUpdate, StatusCode, MINIMUM_STAKE, }; - use runtime::PolkaBtcStatusUpdate; - use runtime::{AccountId, Error as RuntimeError, ErrorCode, H256Le, StatusCode, MINIMUM_STAKE}; use sp_core::H256; use sp_keyring::AccountKeyring; use std::time::Duration; @@ -229,10 +208,17 @@ mod tests { mockall::mock! { Provider {} + #[async_trait] + pub trait UtilFuncs { + async fn get_current_chain_height(&self) -> Result; + async fn get_blockchain_height_at(&self, parachain_height: u32) -> Result; + fn get_account_id(&self) -> &AccountId; + } + #[async_trait] trait StakedRelayerPallet { - async fn get_stake(&self) -> Result; - async fn get_stake_by_id(&self, account_id: AccountId) -> Result; + async fn get_active_stake(&self) -> Result; + async fn get_active_stake_by_id(&self, account_id: AccountId) -> Result; async fn get_inactive_stake_by_id(&self, account_id: AccountId) -> Result; async fn register_staked_relayer(&self, stake: u128) -> Result<(), RuntimeError>; async fn deregister_staked_relayer(&self) -> Result<(), RuntimeError>; @@ -269,6 +255,13 @@ mod tests { } } + impl Clone for MockProvider { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + mockall::mock! { Bitcoin {} @@ -278,7 +271,7 @@ mod tests { async fn get_block_count(&self) -> Result; async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, BitcoinError>; async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, BitcoinError>; - async fn get_block_hash_for(&self, height: u32) -> Result; + async fn get_block_hash(&self, height: u32) -> Result; async fn is_block_known(&self, block_hash: BlockHash) -> Result; async fn get_new_address(&self) -> Result; async fn get_new_public_key + 'static>(&self) -> Result; @@ -289,9 +282,10 @@ mod tests { ) -> Result<(), BitcoinError>; async fn get_best_block_hash(&self) -> Result; async fn get_block(&self, hash: &BlockHash) -> Result; + async fn get_block_header(&self, hash: &BlockHash) -> Result; async fn get_block_info(&self, hash: &BlockHash) -> Result; async fn get_mempool_transactions<'a>( - self: Arc, + self: &'a Self, ) -> Result> + Send + 'a>, BitcoinError>; async fn wait_for_transaction_metadata( &self, @@ -327,11 +321,18 @@ mod tests { } } + impl Clone for MockBitcoin { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + #[tokio::test] async fn test_on_store_block_exists() { let mut bitcoin = MockBitcoin::default(); bitcoin - .expect_get_block_hash_for() + .expect_get_block_hash() .returning(|_| Ok(BlockHash::from_slice(&[1; 32]).unwrap())); let mut parachain = MockProvider::default(); parachain @@ -339,23 +340,19 @@ mod tests { .never() .returning(|_, _, _, _, _, _| Ok(())); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); - let monitor = RelayMonitor::new(Arc::new(bitcoin), Arc::new(parachain), 100); - assert_ok!( - monitor - .on_store_block(123, H256Le::from_bytes_le(&[1; 32])) - .await - ); + let monitor = RelayMonitor::new(bitcoin, parachain, 100); + assert_ok!(monitor.on_store_block(123, H256Le::from_bytes_le(&[1; 32])).await); } #[tokio::test] async fn test_on_store_block_not_exists() { let mut bitcoin = MockBitcoin::default(); bitcoin - .expect_get_block_hash_for() + .expect_get_block_hash() .returning(|_| Err(BitcoinError::InvalidBitcoinHeight.into())); let mut parachain = MockProvider::default(); parachain @@ -363,16 +360,12 @@ mod tests { .once() .returning(|_, _, _, _, _, _| Ok(())); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); - let monitor = RelayMonitor::new(Arc::new(bitcoin), Arc::new(parachain), 100); - assert_ok!( - monitor - .on_store_block(123, H256Le::from_bytes_le(&[1; 32])) - .await - ); + let monitor = RelayMonitor::new(bitcoin, parachain, 100); + assert_ok!(monitor.on_store_block(123, H256Le::from_bytes_le(&[1; 32])).await); } #[tokio::test] @@ -380,11 +373,11 @@ mod tests { let bitcoin = MockBitcoin::default(); let mut parachain = MockProvider::default(); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE - 1)); - let monitor = RelayMonitor::new(Arc::new(bitcoin), Arc::new(parachain), 100); + let monitor = RelayMonitor::new(bitcoin, parachain, 100); assert_ok!(monitor.on_store_block(0, H256Le::zero()).await); } @@ -395,11 +388,11 @@ mod tests { let mut parachain = MockProvider::default(); parachain.expect_vote_on_status_update().never(); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); - let monitor = StatusUpdateMonitor::new(Arc::new(bitcoin), Arc::new(parachain)); + let monitor = StatusUpdateMonitor::new(bitcoin, parachain); assert_ok!( monitor .on_status_update_suggested(PolkaBtcStatusUpdateSuggestedEvent { @@ -421,11 +414,11 @@ mod tests { let mut parachain = MockProvider::default(); parachain.expect_vote_on_status_update().never(); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); - let monitor = StatusUpdateMonitor::new(Arc::new(bitcoin), Arc::new(parachain)); + let monitor = StatusUpdateMonitor::new(bitcoin, parachain); assert_err!( monitor .on_status_update_suggested(PolkaBtcStatusUpdateSuggestedEvent { @@ -444,10 +437,7 @@ mod tests { #[tokio::test] async fn test_on_status_update_suggested_add_error_block_unknown() { let mut bitcoin = MockBitcoin::default(); - bitcoin - .expect_is_block_known() - .once() - .returning(|_| Ok(false)); + bitcoin.expect_is_block_known().once().returning(|_| Ok(false)); let mut parachain = MockProvider::default(); parachain .expect_vote_on_status_update() @@ -455,11 +445,11 @@ mod tests { .once() .returning(|_, _| Ok(())); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); - let monitor = StatusUpdateMonitor::new(Arc::new(bitcoin), Arc::new(parachain)); + let monitor = StatusUpdateMonitor::new(bitcoin, parachain); assert_ok!( monitor .on_status_update_suggested(PolkaBtcStatusUpdateSuggestedEvent { @@ -477,10 +467,7 @@ mod tests { #[tokio::test] async fn test_on_status_update_suggested_add_error_block_known() { let mut bitcoin = MockBitcoin::default(); - bitcoin - .expect_is_block_known() - .once() - .returning(|_| Ok(true)); + bitcoin.expect_is_block_known().once().returning(|_| Ok(true)); let mut parachain = MockProvider::default(); parachain .expect_vote_on_status_update() @@ -488,11 +475,11 @@ mod tests { .once() .returning(|_, _| Ok(())); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE)); - let monitor = StatusUpdateMonitor::new(Arc::new(bitcoin), Arc::new(parachain)); + let monitor = StatusUpdateMonitor::new(bitcoin, parachain); assert_ok!( monitor .on_status_update_suggested(PolkaBtcStatusUpdateSuggestedEvent { @@ -512,11 +499,11 @@ mod tests { let bitcoin = MockBitcoin::default(); let mut parachain = MockProvider::default(); parachain - .expect_get_stake() + .expect_get_active_stake() .once() .returning(|| Ok(MINIMUM_STAKE - 1)); - let monitor = StatusUpdateMonitor::new(Arc::new(bitcoin), Arc::new(parachain)); + let monitor = StatusUpdateMonitor::new(bitcoin, parachain); assert_ok!( monitor .on_status_update_suggested(PolkaBtcStatusUpdateSuggestedEvent { diff --git a/staked-relayer/src/system.rs b/staked-relayer/src/system.rs new file mode 100644 index 000000000..0ba5f64e8 --- /dev/null +++ b/staked-relayer/src/system.rs @@ -0,0 +1,220 @@ +use crate::{relay::*, service::*, utils::*, Error, Vaults}; +use async_trait::async_trait; +use bitcoin::{BitcoinCore, BitcoinCoreApi}; +use futures::executor::block_on; +use log::*; +use runtime::{ + on_shutdown, pallets::sla::UpdateRelayerSLAEvent, wait_or_shutdown, Error as RuntimeError, PolkaBtcProvider, + PolkaBtcRuntime, Service, ShutdownReceiver, StakedRelayerPallet, UtilFuncs, VaultRegistryPallet, +}; +use std::{net::SocketAddr, sync::Arc, time::Duration}; + +#[derive(Clone)] +pub struct RelayerServiceConfig { + /// the bitcoin RPC handle + pub bitcoin_core: BitcoinCore, + pub auto_register_with_stake: Option, + pub auto_register_with_faucet_url: Option, + pub bitcoin_theft_start_height: Option, + pub bitcoin_relay_start_height: Option, + pub max_batch_size: u32, + pub bitcoin_timeout: Duration, + pub oracle_timeout: Duration, + pub required_btc_confirmations: u32, + pub status_update_deposit: u128, + pub http_addr: SocketAddr, + pub rpc_cors_domain: String, +} + +pub struct RelayerService { + btc_parachain: PolkaBtcProvider, + config: RelayerServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, +} + +#[async_trait] +impl Service for RelayerService { + async fn start( + btc_parachain: PolkaBtcProvider, + config: RelayerServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, + ) -> Result<(), RuntimeError> { + RelayerService::new(btc_parachain, config, handle, shutdown) + .run_service() + .await + .map_err(|_| RuntimeError::ChannelClosed) + } +} + +impl RelayerService { + fn new( + btc_parachain: PolkaBtcProvider, + config: RelayerServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, + ) -> Self { + Self { + btc_parachain, + config, + handle, + shutdown, + } + } + + async fn run_service(&self) -> Result<(), Error> { + let bitcoin_core = self.config.bitcoin_core.clone(); + + if let Some(stake) = self.config.auto_register_with_stake { + if !is_registered(&self.btc_parachain).await? { + self.btc_parachain.register_staked_relayer(stake).await?; + info!("Automatically registered staked relayer"); + } else { + info!("Not registering staked relayer -- already registered"); + } + } else if let Some(faucet_url) = &self.config.auto_register_with_faucet_url { + if !is_registered(&self.btc_parachain).await? { + fund_and_register(&self.btc_parachain, faucet_url).await?; + info!("Automatically registered staked relayer"); + } else { + info!("Not registering staked relayer -- already registered"); + } + } + + let close_handle = start_http( + self.btc_parachain.clone(), + self.config.http_addr, + self.config.rpc_cors_domain.clone(), + self.handle.clone(), + ); + + let http_server = on_shutdown(self.shutdown.clone(), async move { + close_handle.close(); + }); + + info!("Fetching all active vaults..."); + let vaults = self + .btc_parachain + .get_all_vaults() + .await? + .into_iter() + .flat_map(|vault| { + vault + .wallet + .addresses + .iter() + .map(|addr| (addr.clone(), vault.id.clone())) + .collect::>() + }) + .collect(); + + // store vaults in Arc + let vaults = Arc::new(Vaults::from(vaults)); + + // scan from custom height or the current tip + let bitcoin_theft_start_height = self + .config + .bitcoin_theft_start_height + .unwrap_or(bitcoin_core.get_block_count().await? as u32 + 1); + + let vaults_listener = wait_or_shutdown( + self.shutdown.clone(), + report_vault_thefts( + bitcoin_theft_start_height, + bitcoin_core.clone(), + vaults.clone(), + self.btc_parachain.clone(), + self.config.bitcoin_timeout, + ), + ); + + let vaults_registration_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_vaults_registered(self.btc_parachain.clone(), vaults.clone()), + ); + + let wallet_update_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_wallet_updates(self.btc_parachain.clone(), vaults.clone()), + ); + + let sla_provider = self.btc_parachain.clone(); + let sla_listener = wait_or_shutdown(self.shutdown.clone(), async move { + let relayer_id = sla_provider.get_account_id(); + sla_provider + .on_event::, _, _, _>( + |event| async move { + if &event.relayer_id == relayer_id { + info!("Received event: new total SLA score = {:?}", event.new_sla); + } + }, + |err| error!("Error (UpdateRelayerSLAEvent): {}", err.to_string()), + ) + .await + }); + + let status_update_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_status_updates(bitcoin_core.clone(), self.btc_parachain.clone()), + ); + + let relay_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_blocks_stored( + bitcoin_core.clone(), + self.btc_parachain.clone(), + self.config.status_update_deposit, + ), + ); + + let relayer = wait_or_shutdown( + self.shutdown.clone(), + run_relayer( + Runner::new( + BitcoinClient::new(bitcoin_core.clone()), + PolkaBtcClient::new(self.btc_parachain.clone()), + Config { + start_height: self.config.bitcoin_relay_start_height, + max_batch_size: self.config.max_batch_size, + timeout: Some(self.config.bitcoin_timeout), + required_btc_confirmations: self.config.required_btc_confirmations, + }, + ), + self.btc_parachain.clone(), + Duration::from_secs(1), + ), + ); + + let oracle_listener = wait_or_shutdown( + self.shutdown.clone(), + report_offline_oracle(self.btc_parachain.clone(), self.config.oracle_timeout), + ); + + let handle = self.handle.clone(); + + info!("Starting system services..."); + let _ = tokio::join!( + // runs json-rpc server for incoming requests + handle.spawn(async move { http_server.await }), + // keep track of all registered vaults (i.e. keep the `vaults` map up-to-date) + handle.spawn(async move { vaults_registration_listener.await }), + // keep vault wallets up-to-date + handle.spawn(async move { wallet_update_listener.await }), + // runs vault theft checks + handle.spawn(async move { vaults_listener.await }), + // runs sla listener to log events + handle.spawn(async move { sla_listener.await }), + // runs oracle liveness check + handle.spawn(async move { oracle_listener.await }), + // runs `NO_DATA` checks and submits status updates + handle.spawn(async move { relay_listener.await }), + // runs subscription service for status updates + handle.spawn(async move { status_update_listener.await }), + // runs blocking relayer + handle.spawn_blocking(move || block_on(relayer)) + ); + + Ok(()) + } +} diff --git a/staked-relayer/src/utils.rs b/staked-relayer/src/utils.rs index 50769627d..ed9d19d04 100644 --- a/staked-relayer/src/utils.rs +++ b/staked-relayer/src/utils.rs @@ -1,30 +1,34 @@ use crate::Error; -use log::error; -use runtime::{StakedRelayerPallet, MINIMUM_STAKE}; -use std::future::Future; -use std::sync::Arc; +use runtime::{StakedRelayerPallet, UtilFuncs, MINIMUM_STAKE}; use std::time::Duration; use tokio::time::delay_for; -pub async fn check_every(duration: Duration, check: impl Fn() -> F) -where - F: Future>, -{ +pub async fn is_registered(provider: &P) -> Result { + let account_id = provider.get_account_id(); + // get stake returns 0 if not registered, so check that either active or inactive stake is non-zero + let mut total_stake = provider.get_active_stake_by_id(account_id.clone()).await?; + total_stake = total_stake.saturating_add(provider.get_inactive_stake_by_id(account_id.clone()).await?); + Ok(total_stake >= MINIMUM_STAKE) +} + +pub async fn wait_until_registered(provider: &P, delay: Duration) { + // TODO: listen for register event loop { - delay_for(duration).await; - if let Err(e) = check().await { - error!("Error: {}", e.to_string()); + if is_registered(provider).await.unwrap_or(false) { + return; } + delay_for(delay).await; } } -pub async fn is_registered(polka_rpc: &Arc

) -> bool { - polka_rpc.get_stake().await.unwrap_or(0) >= MINIMUM_STAKE +pub async fn is_active(provider: &P) -> Result { + Ok(provider.get_active_stake().await? >= MINIMUM_STAKE) } -pub async fn wait_until_registered(polka_rpc: &Arc

, delay: Duration) { +pub async fn wait_until_active(provider: &P, delay: Duration) { + // TODO: add bond event and listen loop { - if is_registered(polka_rpc).await { + if is_active(provider).await.unwrap_or(false) { return; } delay_for(delay).await; diff --git a/staked-relayer/src/vault.rs b/staked-relayer/src/vault.rs index 15339072b..aaae9b3d9 100644 --- a/staked-relayer/src/vault.rs +++ b/staked-relayer/src/vault.rs @@ -1,18 +1,17 @@ -use crate::error::{get_retry_policy, Error}; -use crate::utils; +use crate::{ + error::{get_retry_policy, Error}, + utils, +}; use backoff::backoff::Backoff; use bitcoin::{BitcoinCoreApi, BlockHash, Transaction, TransactionExt as _, Txid}; -use futures::stream::iter; -use futures::stream::StreamExt; +use futures::stream::{iter, StreamExt}; use log::*; use runtime::{ pallets::vault_registry::{RegisterAddressEvent, RegisterVaultEvent}, - AccountId, BtcAddress, BtcRelayPallet, Error as RuntimeError, H256Le, PolkaBtcProvider, - PolkaBtcRuntime, PolkaBtcVault, StakedRelayerPallet, VaultRegistryPallet, + AccountId, BtcAddress, BtcRelayPallet, Error as RuntimeError, H256Le, PolkaBtcProvider, PolkaBtcRuntime, + PolkaBtcVault, StakedRelayerPallet, VaultRegistryPallet, }; -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; +use std::{collections::HashMap, sync::Arc, time::Duration}; use tokio::sync::RwLock; #[derive(Default)] @@ -40,34 +39,28 @@ impl Vaults { } } -pub async fn report_vault_thefts( +pub async fn report_vault_thefts( btc_height: u32, - btc_rpc: Arc, + btc_rpc: B, vaults: Arc, - polka_rpc: Arc

, + polka_rpc: P, delay: Duration, ) -> Result<(), Error> { VaultTheftMonitor::new(btc_height, btc_rpc, vaults, polka_rpc, delay) - .scan() + .process_blocks() .await } -pub struct VaultTheftMonitor { +pub struct VaultTheftMonitor { btc_height: u32, - btc_rpc: Arc, - polka_rpc: Arc

, + btc_rpc: B, + polka_rpc: P, vaults: Arc, delay: Duration, } -impl VaultTheftMonitor { - pub fn new( - btc_height: u32, - btc_rpc: Arc, - vaults: Arc, - polka_rpc: Arc

, - delay: Duration, - ) -> Self { +impl VaultTheftMonitor { + pub fn new(btc_height: u32, btc_rpc: B, vaults: Arc, polka_rpc: P, delay: Duration) -> Self { Self { btc_height, btc_rpc, @@ -77,11 +70,7 @@ impl VaultTheftMonit } } - async fn get_raw_tx_and_proof( - &self, - tx_id: Txid, - hash: &BlockHash, - ) -> Result<(Vec, Vec), Error> { + async fn get_raw_tx_and_proof(&self, tx_id: Txid, hash: &BlockHash) -> Result<(Vec, Vec), Error> { let raw_tx = self.btc_rpc.get_raw_tx_for(&tx_id, hash).await?; let proof = self.btc_rpc.get_proof_for(tx_id, hash).await?; Ok((raw_tx, proof)) @@ -103,12 +92,7 @@ impl VaultTheftMonit { info!("Transaction is invalid"); self.polka_rpc - .report_vault_theft( - vault_id, - H256Le::from_bytes_le(&tx_id.as_hash()), - proof, - raw_tx, - ) + .report_vault_theft(vault_id, H256Le::from_bytes_le(&tx_id.as_hash()), proof, raw_tx) .await?; } @@ -124,10 +108,7 @@ impl VaultTheftMonit // at this point we know that the transaction has `num_confirmations` on the bitcoin chain, // but the relay can introduce a delay, so wait until the relay also confirms the transaction. self.polka_rpc - .wait_for_block_in_relay( - H256Le::from_bytes_le(&block_hash.to_vec()), - num_confirmations, - ) + .wait_for_block_in_relay(H256Le::from_bytes_le(&block_hash.to_vec()), num_confirmations) .await?; let tx_id = tx.txid(); @@ -145,26 +126,19 @@ impl VaultTheftMonit Ok(()) } - pub async fn scan(&mut self) -> Result<(), Error> { - utils::wait_until_registered(&self.polka_rpc, self.delay).await; + pub async fn process_blocks(&mut self) -> Result<(), Error> { + utils::wait_until_active(&self.polka_rpc, self.delay).await; let num_confirmations = self.polka_rpc.get_bitcoin_confirmations().await?; let mut backoff = get_retry_policy(); - let mut stream = bitcoin::stream_in_chain_transactions( - self.btc_rpc.clone(), - self.btc_height, - num_confirmations, - ) - .await; + let mut stream = + bitcoin::stream_in_chain_transactions(self.btc_rpc.clone(), self.btc_height, num_confirmations).await; loop { match stream.next().await.unwrap() { - Ok((block_hash, tx)) => match self - .check_transaction(tx, block_hash, num_confirmations) - .await - { + Ok((block_hash, tx)) => match self.check_transaction(tx, block_hash, num_confirmations).await { Ok(_) => { backoff.reset(); continue; // don't execute the delay below @@ -186,10 +160,7 @@ impl VaultTheftMonit } } -pub async fn listen_for_wallet_updates( - polka_rpc: Arc, - vaults: Arc, -) -> Result<(), RuntimeError> { +pub async fn listen_for_wallet_updates(polka_rpc: PolkaBtcProvider, vaults: Arc) -> Result<(), RuntimeError> { let vaults = &vaults; polka_rpc .on_event::, _, _, _>( @@ -206,7 +177,7 @@ pub async fn listen_for_wallet_updates( } pub async fn listen_for_vaults_registered( - polka_rpc: Arc, + polka_rpc: PolkaBtcProvider, vaults: Arc, ) -> Result<(), RuntimeError> { polka_rpc @@ -237,12 +208,13 @@ mod tests { use super::*; use async_trait::async_trait; use bitcoin::{ - Block, Error as BitcoinError, GetBlockResult, LockedTransaction, PartialAddress, - Transaction, TransactionMetadata, PUBLIC_KEY_SIZE, + Block, BlockHeader, Error as BitcoinError, GetBlockResult, LockedTransaction, PartialAddress, Transaction, + TransactionMetadata, PUBLIC_KEY_SIZE, + }; + use runtime::{ + AccountId, BitcoinBlockHeight, Error as RuntimeError, ErrorCode, H256Le, PolkaBtcRichBlockHeader, + PolkaBtcStatusUpdate, RawBlockHeader, StatusCode, }; - use runtime::PolkaBtcStatusUpdate; - use runtime::{AccountId, Error as RuntimeError, ErrorCode, H256Le, StatusCode}; - use runtime::{BitcoinBlockHeight, RawBlockHeader, RichBlockHeader}; use sp_core::{H160, H256}; use sp_keyring::AccountKeyring; @@ -251,8 +223,8 @@ mod tests { #[async_trait] trait StakedRelayerPallet { - async fn get_stake(&self) -> Result; - async fn get_stake_by_id(&self, account_id: AccountId) -> Result; + async fn get_active_stake(&self) -> Result; + async fn get_active_stake_by_id(&self, account_id: AccountId) -> Result; async fn get_inactive_stake_by_id(&self, account_id: AccountId) -> Result; async fn register_staked_relayer(&self, stake: u128) -> Result<(), RuntimeError>; async fn deregister_staked_relayer(&self) -> Result<(), RuntimeError>; @@ -293,7 +265,7 @@ mod tests { async fn get_best_block(&self) -> Result; async fn get_best_block_height(&self) -> Result; async fn get_block_hash(&self, height: u32) -> Result; - async fn get_block_header(&self, hash: H256Le) -> Result; + async fn get_block_header(&self, hash: H256Le) -> Result; async fn initialize_btc_relay( &self, header: RawBlockHeader, @@ -310,6 +282,13 @@ mod tests { } } + impl Clone for MockProvider { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + mockall::mock! { Bitcoin {} @@ -319,7 +298,7 @@ mod tests { async fn get_block_count(&self) -> Result; async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, BitcoinError>; async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, BitcoinError>; - async fn get_block_hash_for(&self, height: u32) -> Result; + async fn get_block_hash(&self, height: u32) -> Result; async fn is_block_known(&self, block_hash: BlockHash) -> Result; async fn get_new_address(&self) -> Result; async fn get_new_public_key + 'static>(&self) -> Result; @@ -330,9 +309,10 @@ mod tests { ) -> Result<(), BitcoinError>; async fn get_best_block_hash(&self) -> Result; async fn get_block(&self, hash: &BlockHash) -> Result; + async fn get_block_header(&self, hash: &BlockHash) -> Result; async fn get_block_info(&self, hash: &BlockHash) -> Result; async fn get_mempool_transactions<'a>( - self: Arc, + self: &'a Self, ) -> Result> + Send +'a>, BitcoinError>; async fn wait_for_transaction_metadata( &self, @@ -368,6 +348,13 @@ mod tests { } } + impl Clone for MockBitcoin { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + #[tokio::test] async fn test_filter_matching_vaults() { let vaults = Vaults::from( @@ -380,14 +367,12 @@ mod tests { ); assert_eq!( - filter_matching_vaults(vec![BtcAddress::P2PKH(H160::from_slice(&[0; 20]))], &vaults) - .await, + filter_matching_vaults(vec![BtcAddress::P2PKH(H160::from_slice(&[0; 20]))], &vaults).await, vec![AccountKeyring::Bob.to_account_id()], ); assert_eq!( - filter_matching_vaults(vec![BtcAddress::P2PKH(H160::from_slice(&[1; 20]))], &vaults) - .await, + filter_matching_vaults(vec![BtcAddress::P2PKH(H160::from_slice(&[1; 20]))], &vaults).await, vec![], ); } @@ -395,9 +380,7 @@ mod tests { #[tokio::test] async fn test_report_valid_transaction() { let mut parachain = MockProvider::default(); - parachain - .expect_is_transaction_invalid() - .returning(|_, _| Ok(false)); + parachain.expect_is_transaction_invalid().returning(|_, _| Ok(false)); parachain .expect_report_vault_theft() .never() @@ -405,19 +388,14 @@ mod tests { let monitor = VaultTheftMonitor::new( 0, - Arc::new(MockBitcoin::default()), + MockBitcoin::default(), Arc::new(Vaults::default()), - Arc::new(parachain), + parachain, Duration::from_millis(100), ); monitor - .report_invalid( - AccountKeyring::Bob.to_account_id(), - &Txid::default(), - vec![], - vec![], - ) + .report_invalid(AccountKeyring::Bob.to_account_id(), &Txid::default(), vec![], vec![]) .await .unwrap(); } @@ -425,9 +403,7 @@ mod tests { #[tokio::test] async fn test_report_invalid_transaction() { let mut parachain = MockProvider::default(); - parachain - .expect_is_transaction_invalid() - .returning(|_, _| Ok(true)); + parachain.expect_is_transaction_invalid().returning(|_, _| Ok(true)); parachain .expect_report_vault_theft() .once() @@ -435,19 +411,14 @@ mod tests { let monitor = VaultTheftMonitor::new( 0, - Arc::new(MockBitcoin::default()), + MockBitcoin::default(), Arc::new(Vaults::default()), - Arc::new(parachain), + parachain, Duration::from_millis(100), ); monitor - .report_invalid( - AccountKeyring::Bob.to_account_id(), - &Txid::default(), - vec![], - vec![], - ) + .report_invalid(AccountKeyring::Bob.to_account_id(), &Txid::default(), vec![], vec![]) .await .unwrap(); } diff --git a/staked-relayer/tests/integration_tests.rs b/staked-relayer/tests/integration_tests.rs index e01fcfae5..cd4a5d40b 100644 --- a/staked-relayer/tests/integration_tests.rs +++ b/staked-relayer/tests/integration_tests.rs @@ -10,21 +10,18 @@ use futures::{ future::{join, Either}, pin_mut, Future, FutureExt, SinkExt, StreamExt, }; -use jsonrpsee::Client as JsonRpseeClient; use log::*; use runtime::{ pallets::staked_relayers::*, substrate_subxt::{Event, PairSigner}, - BtcAddress, ErrorCode, ExchangeRateOraclePallet, FeePallet, FixedPointNumber, FixedU128, - H256Le, IssuePallet, PolkaBtcProvider, PolkaBtcRuntime, RedeemPallet, ReplacePallet, - StakedRelayerPallet, StatusCode, UtilFuncs, VaultRegistryPallet, + BtcAddress, ErrorCode, ExchangeRateOraclePallet, FeePallet, FixedPointNumber, FixedU128, H256Le, IssuePallet, + PolkaBtcProvider, PolkaBtcRuntime, RedeemPallet, ReplacePallet, StakedRelayerPallet, StatusCode, UtilFuncs, + VaultRegistryPallet, }; use sp_core::H160; use sp_keyring::AccountKeyring; use staked_relayer; -use std::sync::Arc; -use std::time::Duration; - +use std::{sync::Arc, time::Duration}; use tokio::time::timeout; const TIMEOUT: Duration = Duration::from_secs(45); @@ -47,21 +44,14 @@ async fn test_report_vault_theft_succeeds() { root_provider.set_maturity_period(0).await.unwrap(); - relayer_provider - .register_staked_relayer(1000000) - .await - .unwrap(); + relayer_provider.register_staked_relayer(1000000).await.unwrap(); - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -76,10 +66,7 @@ async fn test_report_vault_theft_succeeds() { relayer_provider.clone(), Duration::from_secs(1), ), - staked_relayer::service::listen_for_wallet_updates( - relayer_provider.clone(), - vaults.clone(), - ), + staked_relayer::service::listen_for_wallet_updates(relayer_provider.clone(), vaults.clone()), ), async { // Theft detection works by extracting the public address from transaction inputs, @@ -100,20 +87,14 @@ async fn test_report_vault_theft_succeeds() { transaction.transaction.input[0].witness = vec![vec![], vec![5; 20]]; // extract the public address corresponding to the input script - let input_address = transaction - .transaction - .extract_input_addresses::()[0]; + let input_address = transaction.transaction.extract_input_addresses::()[0]; // now make the vault register it - vault_provider - .register_address(input_address) - .await - .unwrap(); + vault_provider.register_address(input_address).await.unwrap(); // now perform the theft btc_rpc.send_transaction(transaction).await.unwrap(); - assert_event::, _>(TIMEOUT, vault_provider, |_| true) - .await; + assert_event::, _>(TIMEOUT, vault_provider, |_| true).await; }, ) .await @@ -129,22 +110,14 @@ async fn test_oracle_offline_succeeds() { root_provider.set_maturity_period(0).await.unwrap(); - relayer_provider - .register_staked_relayer(1000000) - .await - .unwrap(); + relayer_provider.register_staked_relayer(1000000).await.unwrap(); test_service( - staked_relayer::service::report_offline_oracle( - relayer_provider.clone(), - Duration::from_secs(1), - ), + staked_relayer::service::report_offline_oracle(relayer_provider.clone(), Duration::from_secs(1)), async { - assert_event::, _>( - TIMEOUT, - relayer_provider.clone(), - |e| matches!(e.add_error, Some(runtime::ErrorCode::OracleOffline)), - ) + assert_event::, _>(TIMEOUT, relayer_provider.clone(), |e| { + matches!(e.add_error, Some(runtime::ErrorCode::OracleOffline)) + }) .await; }, ) @@ -161,24 +134,15 @@ async fn test_register_deregister_succeeds() { let root_provider = setup_provider(client.clone(), AccountKeyring::Alice).await; root_provider.set_maturity_period(0).await.unwrap(); - relayer_provider - .register_staked_relayer(1000000) - .await - .unwrap(); + relayer_provider.register_staked_relayer(1000000).await.unwrap(); - assert!(relayer_provider - .register_staked_relayer(1000000) - .await - .is_err()); + assert!(relayer_provider.register_staked_relayer(1000000).await.is_err()); relayer_provider.deregister_staked_relayer().await.unwrap(); assert!(relayer_provider.deregister_staked_relayer().await.is_err()); - relayer_provider - .register_staked_relayer(1000000) - .await - .unwrap(); + relayer_provider.register_staked_relayer(1000000).await.unwrap(); } // ignoring this for now after checking with @Sander, as the test times out @@ -201,8 +165,8 @@ async fn test_vote_status_no_data_succeeds() { let relayer_1 = register_relayer(AccountKeyring::Bob, 10000000).await; let relayer_2 = register_relayer(AccountKeyring::Charlie, 10000000).await; - let btc_rpc_1 = Arc::new(MockBitcoinCore::new(relayer_1.clone()).await); - let btc_rpc_2 = Arc::new(MockBitcoinCore::new_uninitialized(relayer_2.clone()).await); + let btc_rpc_1 = MockBitcoinCore::new(relayer_1.clone()).await; + let btc_rpc_2 = MockBitcoinCore::new_uninitialized(relayer_2.clone()).await; relayer_1 .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100)) @@ -211,10 +175,7 @@ async fn test_vote_status_no_data_succeeds() { let vault_provider = setup_provider(client.clone(), AccountKeyring::Eve).await; vault_provider - .register_vault( - 10000000000000, - btc_rpc_1.get_new_public_key().await.unwrap(), - ) + .register_vault(10000000000000, btc_rpc_1.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -227,26 +188,14 @@ async fn test_vote_status_no_data_succeeds() { .await .unwrap(); let metadata = btc_rpc_1 - .send_to_address( - issue.vault_btc_address, - issue.amount_btc as u64, - None, - TIMEOUT, - 0, - ) + .send_to_address(issue.vault_btc_address, issue.amount_btc as u64, None, TIMEOUT, 0) .await .unwrap(); - let update = assert_event::, _>( - TIMEOUT, - vault_provider, - |_| true, - ) - .await; + let update = + assert_event::, _>(TIMEOUT, vault_provider, |_| true).await; // ignore returned result; it likely has decoding errors - let _ = root_provider - .evaluate_status_update(update.status_update_id) - .await; + let _ = root_provider.evaluate_status_update(update.status_update_id).await; // we should not be able to use the block relayed by the faulty relayer assert!(user_provider diff --git a/testdata-gen/Cargo.toml b/testdata-gen/Cargo.toml index b30d7d50f..f51bec30c 100644 --- a/testdata-gen/Cargo.toml +++ b/testdata-gen/Cargo.toml @@ -1,17 +1,16 @@ [package] name = "testdata-gen" -version = "0.1.0" +version = "0.5.0" authors = ["Interlay "] edition = "2018" +[features] +default = ["bitcoin/regtest-mine-on-tx"] + [dependencies] tokio = { version = "0.2.22", features = ["full"] } parity-scale-codec = "2.0.0" -primitive-types = { default-features = false, version = "0.7.2", features = ["codec"]} -runtime = { path = "../runtime" } -relayer-core = { git = "https://gitlab.com/interlay/relayer-core", rev = "49deea6c1219d3a0e682e35444a08055a238fed7" } thiserror = "1.0" -bitcoin = { path = "../bitcoin", features = ["cli"] } clap = "3.0.0-beta.2" log = "0.4.0" env_logger = "0.7.1" @@ -19,13 +18,13 @@ hex = "0.4.2" serde = { version = "1.0.101", features = ["derive"] } serde_json = "1.0.59" reqwest = {version = "0.10.9", features = ["json"] } -jsonrpc-core = "16.0.0" +jsonrpc-core = "17.0.0" +futures = "0.3.5" + +# Workspace dependencies +bitcoin = { path = "../bitcoin", features = ["cli"] } +runtime = { path = "../runtime" } # Substrate dependencies sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } - -frame-system = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } - -[features] -default = ["bitcoin/regtest-mine-on-tx"] diff --git a/testdata-gen/README.md b/testdata-gen/README.md index 6793790e9..30d1e7def 100644 --- a/testdata-gen/README.md +++ b/testdata-gen/README.md @@ -24,60 +24,45 @@ This tool uses subcommands, e.g. `cargo run -- --keyring bob set-exchange-rate`, ``` USAGE: - cargo run -- [OPTIONS] --bitcoin-rpc-url --bitcoin-rpc-user --bitcoin-rpc-pass + testdata-gen [OPTIONS] --bitcoin-rpc-url --bitcoin-rpc-user --bitcoin-rpc-pass FLAGS: -h, --help Prints help information -V, --version Prints version information OPTIONS: - --bitcoin-rpc-pass [env: BITCOIN_RPC_PASS=] - --bitcoin-rpc-url [env: BITCOIN_RPC_URL=] - --bitcoin-rpc-user [env: BITCOIN_RPC_USER=] + --bitcoin-rpc-pass [env: BITCOIN_RPC_PASS=rpcpassword] + --bitcoin-rpc-url [env: BITCOIN_RPC_URL=http://localhost:18443] + --bitcoin-rpc-user [env: BITCOIN_RPC_USER=rpcuser] --keyfile Path to the json file containing key pairs in a map. Valid content of this file is e.g. - `{ "MyUser1": "", "MyUser2": "" }`. Credentials should be a - `0x`-prefixed 64-digit hex string, or a BIP-39 key phrase of 12, 15, 18, 21 or 24 words. - See `sp_core::from_string_with_seed` for more details - --keyname - The name of the account from the keyfile to use - --keyring - Keyring to use, mutually exclusive with keyfile [valid values: alice, bob, charlie, - dave, eve, ferdie] + `{ "MyUser1": "", "MyUser2": "" }` + + --keyname The name of the account from the keyfile to use + --keyring Keyring to use, mutually exclusive with keyfile --polka-btc-url Parachain URL, can be over WebSockets or HTTP [default: ws://127.0.0.1:9944] SUBCOMMANDS: - accept-replace Accept replace request of another vault - api-call Send a API request - ├── vault Send an API message to the vault - │ ├── lock-additional-collateral Tell the vault to lock additional collateral - │ ├── register-vault Tell the vault to register itself - │ ├── request-replace Tell the vault to place a replace request - │ ├── update-btc-address Tell the vault to update its BTC address - │ ├── withdraw-collateral Tell the vault to withdraw collateral - │ └── withdraw-replace Tell the vault to withdraw a replace request - └── relayer Send an API message to the staked relayer - ├── account-id Get the account id of the relayer - ├── deregister Tell the relayer to deregister itself - ├── register Tell the relayer to register itself - ├── suggest-status-update Tell the relayer to issue a status update suggestion - ├── system-health Get the status of the parachain - └── vote-on-status-update Tell the relayer to vote on a status update suggestion - execute-redeem Send BTC to user, must be called by vault - execute-replace Accept replace request of another vault - get-btc-tx-fees Get the current estimated bitcoin transaction fees - get-current-time Get the time as reported by the chain - get-exchange-rate Get the current DOT to BTC exchange rate - register-vault Register a new vault using the global keyring - request-issue Request issuance of PolkaBTC and transfer to vault - request-redeem Request that PolkaBTC be burned to redeem BTC - request-replace Request another vault to takeover - send-bitcoin Send BTC to an address - set-btc-tx-fees Set the current estimated bitcoin transaction fees - set-exchange-rate Set the DOT to BTC exchange rate - set-issue-period Set the period after which issue requests expire. - set-redeem-period Set the period after which redeem requests expire. - set-replace-period Set the period after which replace requests expire. + accept-replace Accept replace request of another vault + api-call Send a API request + execute-redeem Send BTC to user, must be called by vault + execute-replace Accept replace request of another vault + fund-accounts Transfer DOT collateral + get-btc-tx-fees Get the current estimated bitcoin transaction fees + get-current-time Get the time as reported by the chain + get-exchange-rate Get the current DOT to BTC exchange rate + help Prints this message or the help of the given subcommand(s) + register-vault Register a new vault using the global keyring + request-issue Request issuance of PolkaBTC and transfer to vault + request-redeem Request that PolkaBTC be burned to redeem BTC + request-replace Request another vault to takeover + send-bitcoin Send BTC to an address + set-btc-tx-fees Set the current estimated bitcoin transaction fees + set-exchange-rate Set the DOT to BTC exchange rate + set-issue-period Set issue period + set-redeem-period Set redeem period + set-relayer-maturity-period Set relayer maturity period + set-replace-period Set replace period ``` diff --git a/testdata-gen/scripts/run_relayers.sh b/testdata-gen/scripts/run_relayers.sh new file mode 100755 index 000000000..66644ad86 --- /dev/null +++ b/testdata-gen/scripts/run_relayers.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +NUM_RELAYERS=${NUM_RELAYERS:-5} + +RELAYER_AMOUNT=${RELAYER_AMOUNT:-1000000000000} # 100 DOT +RELAYER_STAKE=${RELAYER_STAKE:-100} # 0.00000001 DOT + +BTC_PARACHAIN_RPC=${BTC_PARACHAIN_RPC:-"ws://localhost:9944"} + +RELAYER_CLIENT_BIN=${RELAYER_CLIENT_BIN:-"${DIR}/../../target/debug/staked-relayer"} +TESTDATA_CLIENT_BIN=${TESTDATA_CLIENT_BIN:-"${DIR}/../../target/debug/testdata-gen"} + +declare -A secrets +declare -A accounts + +keyFile=$(mktemp) + +function finish { + rm $keyFile + kill -- -$$ +} +trap finish EXIT + +# populate keyfile +for i in $(seq 1 $NUM_RELAYERS); do + RELAYER_NAME="relayer-${i}" + + SECRET_KEY=$(subkey generate --output-type json) + SECRET_PHRASE=$(echo ${SECRET_KEY} | jq .secretPhrase) + secrets[${RELAYER_NAME}]=${SECRET_PHRASE} + + ACCOUNT_ID=$(echo ${SECRET_KEY} | jq -r .ss58Address) + accounts[${RELAYER_NAME}]=${ACCOUNT_ID} + echo "${RELAYER_NAME}=${ACCOUNT_ID}" +done + +for i in "${!secrets[@]}" +do + echo "\"$i\"" + echo "${secrets[$i]}" +done | +jq -n 'reduce inputs as $i ({}; . + { ($i): input })' > $keyFile + +${TESTDATA_CLIENT_BIN} --keyring alice --polka-btc-url ${BTC_PARACHAIN_RPC} \ + fund-accounts --accounts ${accounts[@]} --amount ${RELAYER_AMOUNT} + +for i in $(seq 1 $NUM_RELAYERS); do + RELAYER_NAME="relayer-${i}" + echo "Starting ${RELAYER_NAME}" + + ${RELAYER_CLIENT_BIN} \ + --polka-btc-url ${BTC_PARACHAIN_RPC} \ + --auto-register-with-stake ${RELAYER_STAKE} \ + --http-addr "[::0]:304$i" \ + --keyfile $keyFile \ + --keyname ${RELAYER_NAME} & + +done + +wait \ No newline at end of file diff --git a/testdata-gen/scripts/run_vaults.sh b/testdata-gen/scripts/run_vaults.sh new file mode 100755 index 000000000..23b513aa1 --- /dev/null +++ b/testdata-gen/scripts/run_vaults.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +NUM_VAULTS=${NUM_VAULTS:-5} + +VAULT_AMOUNT=${VAULT_AMOUNT:-1001000000000000} # 100,100 DOT +VAULT_COLLATERAL=${VAULT_COLLATERAL:-1000000000000000} # 100,000 DOT + +BTC_PARACHAIN_RPC=${BTC_PARACHAIN_RPC:-"ws://localhost:9944"} + +VAULT_CLIENT_BIN=${VAULT_CLIENT_BIN:-"${DIR}/../../target/debug/vault"} +TESTDATA_CLIENT_BIN=${TESTDATA_CLIENT_BIN:-"${DIR}/../../target/debug/testdata-gen"} + +declare -A secrets +declare -A accounts + +keyFile=$(mktemp) + +function finish { + rm $keyFile + kill -- -$$ +} +trap finish EXIT + +# populate keyfile +for i in $(seq 1 $NUM_VAULTS); do + VAULT_NAME="vault-${i}" + + SECRET_KEY=$(subkey generate --output-type json) + SECRET_PHRASE=$(echo ${SECRET_KEY} | jq .secretPhrase) + secrets[${VAULT_NAME}]=${SECRET_PHRASE} + + ACCOUNT_ID=$(echo ${SECRET_KEY} | jq -r .ss58Address) + accounts[${VAULT_NAME}]=${ACCOUNT_ID} + echo "${VAULT_NAME}=${ACCOUNT_ID}" +done + +for i in "${!secrets[@]}" +do + echo "\"$i\"" + echo "${secrets[$i]}" +done | +jq -n 'reduce inputs as $i ({}; . + { ($i): input })' > $keyFile + +${TESTDATA_CLIENT_BIN} --keyring alice --polka-btc-url ${BTC_PARACHAIN_RPC} \ + fund-accounts --accounts ${accounts[@]} --amount ${VAULT_AMOUNT} + +for i in $(seq 1 $NUM_VAULTS); do + VAULT_NAME="vault-${i}" + echo "Starting ${VAULT_NAME}" + + ${VAULT_CLIENT_BIN} \ + --polka-btc-url ${BTC_PARACHAIN_RPC} \ + --auto-register-with-collateral ${VAULT_COLLATERAL} \ + --http-addr "[::0]:303$i" \ + --keyfile $keyFile \ + --keyname ${VAULT_NAME} \ + --network regtest & + +done + +wait \ No newline at end of file diff --git a/testdata-gen/src/api.rs b/testdata-gen/src/api.rs index 052db845b..a833028fc 100644 --- a/testdata-gen/src/api.rs +++ b/testdata-gen/src/api.rs @@ -20,9 +20,8 @@ where D: Deserializer<'de>, { use serde::de::Error; - String::deserialize(deserializer).and_then(|string| { - Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string())) - }) + String::deserialize(deserializer) + .and_then(|string| Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string()))) } #[derive(serde::Deserialize)] diff --git a/testdata-gen/src/error.rs b/testdata-gen/src/error.rs index cc40f1dc3..95c4d5fe9 100644 --- a/testdata-gen/src/error.rs +++ b/testdata-gen/src/error.rs @@ -4,8 +4,7 @@ use jsonrpc_core::error::Error as JsonRpcError; use parity_scale_codec::Error as CodecError; use runtime::Error as RuntimeError; use serde_json::Error as SerdeJsonError; -use std::array::TryFromSliceError; -use std::io::Error as IoError; +use std::{array::TryFromSliceError, io::Error as IoError}; use thiserror::Error; #[derive(Error, Debug)] diff --git a/testdata-gen/src/issue.rs b/testdata-gen/src/issue.rs index 997bce4d3..b75b74354 100644 --- a/testdata-gen/src/issue.rs +++ b/testdata-gen/src/issue.rs @@ -4,18 +4,14 @@ use crate::{utils, Error}; use bitcoin::{BitcoinCore, BitcoinCoreApi}; use log::info; use runtime::{ - pallets::btc_relay::H256Le, AccountId, BtcAddress, IssuePallet, PolkaBtcIssueRequest, - PolkaBtcProvider, PolkaBtcRequestIssueEvent, UtilFuncs, + pallets::btc_relay::H256Le, AccountId, BtcAddress, IssuePallet, PolkaBtcIssueRequest, PolkaBtcProvider, + PolkaBtcRequestIssueEvent, UtilFuncs, }; use sp_core::H256; -use std::convert::TryInto; -use std::time::Duration; +use std::{convert::TryInto, time::Duration}; /// Fetch an issue request by it's ID -pub async fn get_issue_by_id( - issue_prov: &PolkaBtcProvider, - issue_id: H256, -) -> Result { +pub async fn get_issue_by_id(issue_prov: &PolkaBtcProvider, issue_id: H256) -> Result { let issue_request = issue_prov.get_issue_request(issue_id).await?; Ok(issue_request) diff --git a/testdata-gen/src/main.rs b/testdata-gen/src/main.rs index a1864dda3..cc63146a9 100644 --- a/testdata-gen/src/main.rs +++ b/testdata-gen/src/main.rs @@ -9,19 +9,17 @@ mod vault; use bitcoin::{BitcoinCore, BitcoinCoreApi, ConversionError, PartialAddress}; use clap::Clap; use error::Error; +use futures::future::try_join_all; use log::*; use parity_scale_codec::{Decode, Encode}; use runtime::{ - substrate_subxt::PairSigner, BtcAddress, ErrorCode as PolkaBtcErrorCode, - ExchangeRateOraclePallet, FeePallet, FixedPointNumber, FixedPointTraits::*, FixedU128, H256Le, - PolkaBtcProvider, PolkaBtcRuntime, RedeemPallet, StakedRelayerPallet, - StatusCode as PolkaBtcStatusCode, TimestampPallet, + substrate_subxt::PairSigner, AccountId, BtcAddress, DotBalancesPallet, ErrorCode as PolkaBtcErrorCode, + ExchangeRateOraclePallet, FeePallet, FixedPointNumber, FixedPointTraits::*, FixedU128, H256Le, PolkaBtcProvider, + PolkaBtcRuntime, RedeemPallet, StakedRelayerPallet, StatusCode as PolkaBtcStatusCode, TimestampPallet, }; use sp_core::H256; use sp_keyring::AccountKeyring; -use std::convert::TryInto; -use std::str::FromStr; -use std::time::Duration; +use std::{convert::TryInto, str::FromStr, sync::Arc, time::Duration}; #[derive(Debug, Encode, Decode)] struct BtcAddressFromStr(BtcAddress); @@ -89,6 +87,10 @@ struct Opts { #[clap(subcommand)] subcmd: SubCommand, + + /// Timeout in milliseconds to wait for connection to btc-parachain. + #[clap(long, default_value = "60000")] + connection_timeout_ms: u64, } #[derive(Clap)] @@ -129,6 +131,8 @@ enum SubCommand { SetReplacePeriod(SetReplacePeriodInfo), /// Set relayer maturity period. SetRelayerMaturityPeriod(SetRelayerMaturityPeriodInfo), + /// Transfer DOT collateral + FundAccounts(FundAccountsInfo), } #[derive(Clap)] @@ -472,12 +476,23 @@ struct VoteOnStatusUpdateJsonRpcRequest { pub approve: bool, } +#[derive(Clap, Encode, Decode, Debug)] +struct FundAccountsInfo { + /// Accounts to fund + #[clap(long)] + pub accounts: Vec, + + /// DOT amount + #[clap(long)] + pub amount: u128, +} + async fn get_btc_rpc( wallet_name: String, bitcoin_opts: bitcoin::cli::BitcoinOpts, network: BitcoinNetwork, ) -> Result { - let btc_rpc = BitcoinCore::new(bitcoin_opts.new_client(Some(&wallet_name))?, network.0); + let btc_rpc = BitcoinCore::new(Arc::new(bitcoin_opts.new_client(Some(&wallet_name))?), network.0); btc_rpc.create_wallet(&wallet_name).await?; Ok(btc_rpc) } @@ -490,7 +505,12 @@ async fn main() -> Result<(), Error> { let (key_pair, wallet_name) = opts.account_info.get_key_pair()?; let signer = PairSigner::::new(key_pair); - let provider = PolkaBtcProvider::from_url(opts.polka_btc_url, signer).await?; + let provider = PolkaBtcProvider::from_url_with_retry( + &opts.polka_btc_url, + signer, + Duration::from_millis(opts.connection_timeout_ms), + ) + .await?; match opts.subcmd { SubCommand::SetExchangeRate(info) => { @@ -521,12 +541,7 @@ async fn main() -> Result<(), Error> { } SubCommand::RegisterVault(info) => { let btc_rpc = get_btc_rpc(wallet_name, opts.bitcoin, info.bitcoin_network).await?; - vault::register_vault( - provider, - btc_rpc.get_new_public_key().await?, - info.collateral, - ) - .await?; + vault::register_vault(provider, btc_rpc.get_new_public_key().await?, info.collateral).await?; } SubCommand::RequestIssue(info) => { let vault_id = info.vault.to_account_id(); @@ -536,8 +551,7 @@ async fn main() -> Result<(), Error> { None => { // calculate required amount let amount_in_dot = provider.btc_to_dots(info.issue_amount).await?; - let required_griefing_collateral_rate = - provider.get_issue_griefing_collateral().await?; + let required_griefing_collateral_rate = provider.get_issue_griefing_collateral().await?; // we add 0.5 before we do the final integer division to round the result we return. // note that unwrapping is safe because we use a constant @@ -552,17 +566,13 @@ async fn main() -> Result<(), Error> { }; let griefing_collateral = calc_griefing_collateral().ok_or(Error::MathError)?; - info!( - "Griefing collateral not set; defaulting to {}", - griefing_collateral - ); + info!("Griefing collateral not set; defaulting to {}", griefing_collateral); griefing_collateral } }; let request_data = - issue::request_issue(&provider, info.issue_amount, griefing_collateral, vault_id) - .await?; + issue::request_issue(&provider, info.issue_amount, griefing_collateral, vault_id).await?; let vault_btc_address = request_data.vault_btc_address; @@ -591,10 +601,7 @@ async fn main() -> Result<(), Error> { return Err(Error::IssueCancelled); } - ( - issue_request.btc_address, - issue_request.amount + issue_request.fee, - ) + (issue_request.btc_address, issue_request.amount + issue_request.fee) } else { // expects cli configuration let btc_address = info.btc_address.ok_or(Error::ExpectedBitcoinAddress)?.0; @@ -639,9 +646,7 @@ async fn main() -> Result<(), Error> { .await?; } SubCommand::RequestReplace(info) => { - let replace_id = - replace::request_replace(&provider, info.replace_amount, info.griefing_collateral) - .await?; + let replace_id = replace::request_replace(&provider, info.replace_amount, info.griefing_collateral).await?; println!("{}", hex::encode(replace_id.as_bytes())); } SubCommand::AcceptReplace(info) => { @@ -707,6 +712,17 @@ async fn main() -> Result<(), Error> { SubCommand::SetRelayerMaturityPeriod(info) => { provider.set_maturity_period(info.period).await?; } + SubCommand::FundAccounts(info) => { + let provider = &provider; + let futures: Vec<_> = info + .accounts + .iter() + .map(|account_id| (account_id, info.amount)) + .map(|(account_id, amount)| async move { provider.transfer_to(account_id.clone(), amount).await }) + .collect(); + + try_join_all(futures).await?; + } } Ok(()) diff --git a/testdata-gen/src/redeem.rs b/testdata-gen/src/redeem.rs index ea9c92fef..9af7938a6 100644 --- a/testdata-gen/src/redeem.rs +++ b/testdata-gen/src/redeem.rs @@ -3,11 +3,9 @@ use crate::{utils, Error}; use bitcoin::{BitcoinCore, BitcoinCoreApi}; use log::info; -use runtime::pallets::btc_relay::H256Le; -use runtime::{AccountId, BtcAddress, PolkaBtcProvider, RedeemPallet, UtilFuncs}; +use runtime::{pallets::btc_relay::H256Le, AccountId, BtcAddress, PolkaBtcProvider, RedeemPallet, UtilFuncs}; use sp_core::H256; -use std::convert::TryInto; -use std::time::Duration; +use std::{convert::TryInto, time::Duration}; /// Request redeem of PolkaBTC pub async fn request_redeem( diff --git a/testdata-gen/src/replace.rs b/testdata-gen/src/replace.rs index e69998776..b41610d01 100644 --- a/testdata-gen/src/replace.rs +++ b/testdata-gen/src/replace.rs @@ -3,11 +3,9 @@ use crate::{utils, Error}; use bitcoin::{BitcoinCore, BitcoinCoreApi}; use log::info; -use runtime::pallets::btc_relay::H256Le; -use runtime::{BtcAddress, PolkaBtcProvider, ReplacePallet, UtilFuncs}; +use runtime::{pallets::btc_relay::H256Le, BtcAddress, PolkaBtcProvider, ReplacePallet, UtilFuncs}; use sp_core::H256; -use std::convert::TryInto; -use std::time::Duration; +use std::{convert::TryInto, time::Duration}; /// Request redeem of PolkaBTC pub async fn request_replace( @@ -15,9 +13,7 @@ pub async fn request_replace( amount: u128, griefing_collateral: u128, ) -> Result { - let replace_id = replace_prov - .request_replace(amount, griefing_collateral) - .await?; + let replace_id = replace_prov.request_replace(amount, griefing_collateral).await?; info!( "Requested {:?} to replace {:?} PolkaBTC", @@ -36,9 +32,7 @@ pub async fn accept_replace( ) -> Result<(), Error> { info!("Collateral: {}", collateral); let address = btc_rpc.get_new_address().await?; - replace_prov - .accept_replace(replace_id, collateral, address) - .await?; + replace_prov.accept_replace(replace_id, collateral, address).await?; Ok(()) } diff --git a/vault/Cargo.toml b/vault/Cargo.toml index 390cde160..b442f3bee 100644 --- a/vault/Cargo.toml +++ b/vault/Cargo.toml @@ -1,28 +1,34 @@ [package] name = "vault" -version = "0.2.6" +version = "0.5.0" authors = ["Interlay "] edition = "2018" +[features] +integration = [] + [dependencies] log = "0.4.0" env_logger = "0.7.1" -tokio = { version = "0.2.22", features = ["full"] } thiserror = "1.0" clap = "3.0.0-beta.2" -runtime = { path = "../runtime" } -bitcoin = { path = "../bitcoin", features = ["cli"] } +tokio = { version = "0.2.22", features = ["full"] } backoff = { version = "0.2.1", features = ["tokio"] } serde = "1.0.116" serde_json = { version = "1.0.57", features = ["raw_value"] } -hex = "0.4.2" parity-scale-codec = "2.0.0" -jsonrpc-http-server = "16.0.0" -jsonrpc-core = "16.0.0" +hex = "0.4.2" futures = "0.3.5" async-trait = "0.1.40" sha2 = "0.8.2" -jsonrpc-core-client = { version = "16.0.0", features = ["http"] } + +jsonrpc-http-server = "17.0.0" +jsonrpc-core = "17.0.0" +jsonrpc-core-client = { version = "17.0.0", features = ["http", "tls"] } + +# Workspace dependencies +bitcoin = { path = "../bitcoin", features = ["cli"] } +runtime = { path = "../runtime" } # Substrate dependencies sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } @@ -31,8 +37,6 @@ sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "roc [dev-dependencies] mockall = "0.8.1" -tempdir = "0.3.7" -rand = "0.7" -schnorrkel = "0.9.1" -jsonrpsee = "0.1.0" + +# Workspace dependencies runtime = { path = "../runtime", features = ["testing-utils"] } \ No newline at end of file diff --git a/vault/README.md b/vault/README.md index 2c2a380b1..46abe94d6 100644 --- a/vault/README.md +++ b/vault/README.md @@ -29,7 +29,7 @@ Download and start [Bitcoin Core](https://bitcoin.org/en/bitcoin-core/): bitcoind -regtest -server ``` -Build and run the [PolkaBTC Parachain](https://gitlab.com/interlay/btc-parachain): +Build and run the [PolkaBTC Parachain](https://github.com/interlay/btc-parachain): ``` git clone git@gitlab.com:interlay/btc-parachain.git @@ -58,7 +58,7 @@ For convenience, a copy of this output is included below. Note that the bitcoin ``` USAGE: - cargo run -- [FLAGS] [OPTIONS] --bitcoin-rpc-url --bitcoin-rpc-user --bitcoin-rpc-pass + vault [FLAGS] [OPTIONS] --bitcoin-rpc-url --bitcoin-rpc-user --bitcoin-rpc-pass FLAGS: -h, --help Prints help information @@ -75,12 +75,21 @@ OPTIONS: generated address --auto-register-with-faucet-url - Automatically register the vault with the collateral received from the faucet and a newly - generated address. The parameter is the URL of the faucet + Automatically register the vault with the collateral received from the faucet and a + newly generated address. The parameter is the URL of the faucet + + --bitcoin-rpc-pass + [env: BITCOIN_RPC_PASS=rpcpassword] + + --bitcoin-rpc-url + [env: BITCOIN_RPC_URL=http://localhost:18443] + + --bitcoin-rpc-user + [env: BITCOIN_RPC_USER=rpcuser] + + --bitcoin-timeout-ms + Timeout in milliseconds to poll Bitcoin [default: 6000] - --bitcoin-rpc-pass [env: BITCOIN_RPC_PASS=] - --bitcoin-rpc-url [env: BITCOIN_RPC_URL=] - --bitcoin-rpc-user [env: BITCOIN_RPC_USER=] --btc-confirmations How many bitcoin confirmations to wait for. If not specified, the parachain settings will be used (recommended) diff --git a/vault/docker-compose.yml b/vault/docker-compose.yml deleted file mode 100644 index dc53e321a..000000000 --- a/vault/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: "3.8" -services: - bitcoind: - image: "ruimarinho/bitcoin-core:0.20" - command: - - -testnet - - -server - - -prune=550 - - -par=1 - - -maxuploadtarget=200 - - -blocksonly - - -rpcbind=0.0.0.0 - - -rpcallowip=0.0.0.0/0 - - -rpcuser=rpcuser - - -rpcpassword=rpcpassword - - -fallbackfee=0.0002 - ports: - - "18332:18332" - volumes: - - ./cache:/home/bitcoin/.bitcoin/testnet3 - vault: - image: "registry.gitlab.com/interlay/polkabtc-clients/vault:0-4-0" - command: - - /bin/sh - - -c - - | - echo "Sleeping..." - sleep 1 - vault --bitcoin-rpc-url http://bitcoind:18332 --bitcoin-rpc-user rpcuser --bitcoin-rpc-pass rpcpassword --keyfile /keyring/keyfile.json --keyname polkabtcvault --network=testnet --auto-register-with-faucet-url 'http://beta.polkabtc.io/api/faucet' --polka-btc-url 'wss://beta.polkabtc.io/api/parachain' --http-addr '[::0]:3032' - ports: - - "3032:3032" - volumes: - - ./:/keyring diff --git a/vault/src/api.rs b/vault/src/api.rs deleted file mode 100644 index 32e177d3f..000000000 --- a/vault/src/api.rs +++ /dev/null @@ -1,224 +0,0 @@ -use super::Error; -use bitcoin::BitcoinCoreApi; -use futures::executor::block_on; -use hex::FromHex; -use jsonrpc_http_server::{ - jsonrpc_core::{ - serde_json::Value, Error as JsonRpcError, ErrorCode as JsonRpcErrorCode, IoHandler, Params, - }, - DomainsValidation, ServerBuilder, -}; -use log::info; -use parity_scale_codec::{Decode, Encode}; -use runtime::{ - BtcPublicKey, ExchangeRateOraclePallet, FeePallet, FixedPointNumber, - FixedPointTraits::{CheckedAdd, CheckedMul}, - PolkaBtcProvider, ReplacePallet, UtilFuncs, VaultRegistryPallet, -}; -use serde::{Deserialize, Deserializer}; -use sp_arithmetic::FixedU128; -use sp_core::crypto::Ss58Codec; -use sp_core::H256; -use std::{net::SocketAddr, sync::Arc}; - -#[derive(Debug, Clone, Deserialize)] -pub(crate) struct RawBytes(#[serde(deserialize_with = "hex_to_buffer")] pub(crate) Vec); - -pub fn hex_to_buffer<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - use serde::de::Error; - String::deserialize(deserializer).and_then(|string| { - Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string())) - }) -} - -fn parse_params(params: Params) -> Result { - let raw: [RawBytes; 1] = params.parse()?; - let req = Decode::decode(&mut &raw[0].0[..]).map_err(Error::CodecError)?; - Ok(req) -} - -fn handle_resp(resp: Result) -> Result { - match resp { - Ok(data) => Ok(format!("0x{}", hex::encode(data.encode())).into()), - Err(err) => Err(JsonRpcError { - code: JsonRpcErrorCode::InternalError, - message: err.to_string(), - data: None, - }), - } -} - -#[derive(Encode, Decode, Debug)] -struct AccountIdJsonRpcResponse { - account_id: String, -} - -fn _account_id(provider: &Arc) -> Result { - Ok(AccountIdJsonRpcResponse { - account_id: provider.get_account_id().to_ss58check(), - }) -} - -#[derive(Encode, Decode, Debug)] -struct ReplaceRequestJsonRpcRequest { - amount: u128, -} - -async fn _request_replace(provider: &Arc, params: Params) -> Result<(), Error> { - let req = parse_params::(params)?; - - let amount_in_dot = provider.btc_to_dots(req.amount).await?; - let griefing_collateral_percentage = provider.get_replace_griefing_collateral().await?; - let griefing_collateral = calculate_for(amount_in_dot, griefing_collateral_percentage)?; - let result = block_on(provider.request_replace(req.amount, griefing_collateral)); - info!( - "Requesting replace for amount = {} with griefing_collateral = {}: {:?}", - req.amount, griefing_collateral, result - ); - Ok(result.map(|_| ())?) -} - -/// Take the `percentage` of an `amount` -fn calculate_for(amount: u128, percentage: FixedU128) -> Result { - // we add 0.5 before we do the final integer division to round the result we return. - // note that unwrapping is safe because we use a constant - let rounding_addition = FixedU128::checked_from_rational(1, 2).unwrap(); - - FixedU128::checked_from_integer(amount) - .ok_or(Error::ArithmeticOverflow)? - .checked_mul(&percentage) - .ok_or(Error::ArithmeticOverflow)? - .checked_add(&rounding_addition) - .ok_or(Error::ArithmeticOverflow)? - .into_inner() - .checked_div(FixedU128::accuracy()) - .ok_or(Error::ArithmeticUnderflow) -} - -#[derive(Encode, Decode, Debug)] -struct RegisterVaultJsonRpcRequest { - collateral: u128, -} - -#[derive(Encode, Decode, Debug)] -struct RegisterVaultJsonRpcResponse { - public_key: BtcPublicKey, -} - -fn _register_vault( - provider: &Arc, - btc: &Arc, - params: Params, -) -> Result { - let req = parse_params::(params)?; - let public_key: BtcPublicKey = block_on(btc.get_new_public_key())?; - let result = block_on(provider.register_vault(req.collateral, public_key.clone())); - info!( - "Registering vault with bitcoind public_key {:?} and collateral = {}: {:?}", - public_key, req.collateral, result - ); - Ok(result.map(|_| RegisterVaultJsonRpcResponse { public_key })?) -} - -#[derive(Encode, Decode, Debug)] -struct ChangeCollateralJsonRpcRequest { - amount: u128, -} - -fn _lock_additional_collateral( - provider: &Arc, - params: Params, -) -> Result<(), Error> { - let req = parse_params::(params)?; - let result = block_on(provider.lock_additional_collateral(req.amount)); - info!( - "Locking additional collateral; amount {}: {:?}", - req.amount, result - ); - Ok(result?) -} - -fn _withdraw_collateral(provider: &Arc, params: Params) -> Result<(), Error> { - let req = parse_params::(params)?; - let result = block_on(provider.withdraw_collateral(req.amount)); - info!( - "Withdrawing collateral with amount {}: {:?}", - req.amount, result - ); - Ok(result?) -} - -#[derive(Encode, Decode, Debug)] -struct WithdrawReplaceJsonRpcRequest { - replace_id: H256, -} - -fn _withdraw_replace(provider: &Arc, params: Params) -> Result<(), Error> { - let req = parse_params::(params)?; - let result = block_on(provider.withdraw_replace(req.replace_id)); - info!( - "Withdrawing replace request {}: {:?}", - req.replace_id, result - ); - Ok(result?) -} - -pub async fn start( - provider: Arc, - btc: Arc, - addr: SocketAddr, - origin: String, -) { - let mut io = IoHandler::default(); - { - let provider = provider.clone(); - io.add_sync_method("account_id", move |_| handle_resp(_account_id(&provider))); - } - { - let provider = provider.clone(); - io.add_method("request_replace", move |params| { - let provider = provider.clone(); - async move { handle_resp(_request_replace(&provider, params).await) } - }); - } - { - let provider = provider.clone(); - let btc = btc.clone(); - io.add_sync_method("register_vault", move |params| { - handle_resp(_register_vault(&provider, &btc, params)) - }); - } - { - let provider = provider.clone(); - io.add_sync_method("lock_additional_collateral", move |params| { - handle_resp(_lock_additional_collateral(&provider, params)) - }); - } - { - let provider = provider.clone(); - io.add_sync_method("withdraw_collateral", move |params| { - handle_resp(_withdraw_collateral(&provider, params)) - }); - } - { - let provider = provider.clone(); - io.add_sync_method("withdraw_replace", move |params| { - handle_resp(_withdraw_replace(&provider, params)) - }); - } - - let server = ServerBuilder::new(io) - .rest_api(jsonrpc_http_server::RestApi::Unsecure) - .cors(DomainsValidation::AllowOnly(vec![origin.into()])) - .start_http(&addr) - .expect("Unable to start RPC server"); - - tokio::task::spawn_blocking(move || { - server.wait(); - }) - .await - .unwrap(); -} diff --git a/vault/src/cancellation.rs b/vault/src/cancellation.rs index ed87ac53f..fb82e61ac 100644 --- a/vault/src/cancellation.rs +++ b/vault/src/cancellation.rs @@ -1,12 +1,10 @@ use super::Error; use async_trait::async_trait; -use futures::channel::mpsc::Receiver; -use futures::*; +use futures::{channel::mpsc::Receiver, *}; use log::*; use runtime::{AccountId, IssuePallet, PolkaBtcHeader, ReplacePallet, UtilFuncs}; use sp_core::H256; use std::marker::{Send, Sync}; -use std::sync::Arc; pub enum RequestEvent { /// new issue requested / replace accepted @@ -15,8 +13,8 @@ pub enum RequestEvent { Executed(H256), } -pub struct CancellationScheduler { - provider: Arc

, +pub struct CancellationScheduler { + provider: P, vault_id: AccountId, period: Option, } @@ -50,20 +48,17 @@ pub trait Canceller

{ const TYPE_NAME: &'static str; /// Gets a list of open replace/issue requests - async fn get_open_requests( - provider: Arc

, - vault_id: AccountId, - ) -> Result, Error> + async fn get_open_requests(provider: &P, vault_id: AccountId) -> Result, Error> where P: 'async_trait; /// Gets the timeout period in number of blocks - async fn get_period(provider: Arc

) -> Result + async fn get_period(provider: &P) -> Result where P: 'async_trait; /// Cancels the issue/replace - async fn cancel_request(provider: Arc

, request_id: H256) -> Result<(), Error> + async fn cancel_request(provider: &P, request_id: H256) -> Result<(), Error> where P: 'async_trait; } @@ -71,13 +66,10 @@ pub trait Canceller

{ pub struct IssueCanceller; #[async_trait] -impl Canceller

for IssueCanceller { +impl Canceller

for IssueCanceller { const TYPE_NAME: &'static str = "issue"; - async fn get_open_requests( - provider: Arc

, - vault_id: AccountId, - ) -> Result, Error> + async fn get_open_requests(provider: &P, vault_id: AccountId) -> Result, Error> where P: 'async_trait, { @@ -94,14 +86,14 @@ impl Canceller

for IssueCancell Ok(ret) } - async fn get_period(provider: Arc

) -> Result + async fn get_period(provider: &P) -> Result where P: 'async_trait, { Ok(provider.get_issue_period().await?) } - async fn cancel_request(provider: Arc

, request_id: H256) -> Result<(), Error> + async fn cancel_request(provider: &P, request_id: H256) -> Result<(), Error> where P: 'async_trait, { @@ -115,10 +107,7 @@ pub struct ReplaceCanceller; impl Canceller

for ReplaceCanceller { const TYPE_NAME: &'static str = "replace"; - async fn get_open_requests( - provider: Arc

, - vault_id: AccountId, - ) -> Result, Error> + async fn get_open_requests(provider: &P, vault_id: AccountId) -> Result, Error> where P: 'async_trait, { @@ -135,14 +124,14 @@ impl Canceller

for ReplaceCance Ok(ret) } - async fn get_period(provider: Arc

) -> Result + async fn get_period(provider: &P) -> Result where P: 'async_trait, { Ok(provider.get_replace_period().await?) } - async fn cancel_request(provider: Arc

, request_id: H256) -> Result<(), Error> + async fn cancel_request(provider: &P, request_id: H256) -> Result<(), Error> where P: 'async_trait, { @@ -206,8 +195,8 @@ fn drain_expired(requests: &mut Vec, current_height: u32) -> Vec< } /// The actual cancellation scheduling and handling -impl CancellationScheduler

{ - pub fn new(provider: Arc

, vault_id: AccountId) -> CancellationScheduler

{ +impl CancellationScheduler

{ + pub fn new(provider: P, vault_id: AccountId) -> CancellationScheduler

{ CancellationScheduler { provider, vault_id, @@ -267,10 +256,7 @@ impl CancellationScheduler

{ } } - match selector - .select_event(block_listener, event_listener) - .await? - { + match selector.select_event(block_listener, event_listener).await? { BlockOrEvent::Block(header) => { debug!( "Received parachain block at height {} for {}", @@ -281,7 +267,7 @@ impl CancellationScheduler

{ let cancellable_requests = drain_expired(active_requests, header.number); for request in cancellable_requests { - match T::cancel_request(self.provider.clone(), request.id).await { + match T::cancel_request(&self.provider, request.id).await { Ok(_) => info!("Canceled {} #{}", T::TYPE_NAME, request.id), Err(e) => { // failed to cancel; get up-to-date request list in next iteration @@ -307,8 +293,7 @@ impl CancellationScheduler

{ /// Gets a list of requests that have been requested from this vault async fn get_open_requests>(&mut self) -> Result, Error> { - let open_requests = - T::get_open_requests(self.provider.clone(), self.vault_id.clone()).await?; + let open_requests = T::get_open_requests(&self.provider, self.vault_id.clone()).await?; if open_requests.is_empty() { return Ok(vec![]); @@ -352,7 +337,7 @@ impl CancellationScheduler

{ match self.period { Some(x) => Ok(x), None => { - let ret = T::get_period(self.provider.clone()).await?; + let ret = T::get_period(&self.provider).await?; self.period = Some(ret); Ok(ret) } @@ -370,8 +355,8 @@ mod tests { generic::Digest, traits::{BlakeTwo256, Hash}, }, - AccountId, BtcAddress, Error as RuntimeError, H256Le, PolkaBtcIssueRequest, - PolkaBtcReplaceRequest, PolkaBtcRequestIssueEvent, + AccountId, BtcAddress, Error as RuntimeError, H256Le, PolkaBtcIssueRequest, PolkaBtcReplaceRequest, + PolkaBtcRequestIssueEvent, }; use sp_core::H256; @@ -387,10 +372,7 @@ mod tests { struct TestEventSelector where - F: Fn( - &mut Receiver, - &mut Receiver, - ) -> Result, + F: Fn(&mut Receiver, &mut Receiver) -> Result, { on_event: F, } @@ -398,10 +380,7 @@ mod tests { #[async_trait] impl EventSelector for TestEventSelector where - F: Fn( - &mut Receiver, - &mut Receiver, - ) -> Result + F: Fn(&mut Receiver, &mut Receiver) -> Result + std::marker::Send, { /// Sleep until either the timeout has occured or an event has been received, and return @@ -479,6 +458,7 @@ mod tests { async fn get_replace_period(&self) -> Result; async fn set_replace_period(&self, period: u32) -> Result<(), RuntimeError>; } + #[async_trait] pub trait UtilFuncs { async fn get_current_chain_height(&self) -> Result; @@ -487,57 +467,55 @@ mod tests { } } + impl Clone for MockProvider { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + #[tokio::test] async fn test_get_open_process_delays_succeeds() { // open_time = 95, current_block = 100, period = 10: remaining = 5 + margin // open_time = 10, current_block = 100, period = 10: remaining = 0 // open_time = 85, current_block = 100, period = 10: remaining = -5 + margin let mut provider = MockProvider::default(); - provider - .expect_get_vault_issue_requests() - .times(1) - .returning(|_| { - Ok(vec![ - ( - H256::from_slice(&[1; 32]), - PolkaBtcIssueRequest { - opentime: 95, - ..Default::default() - }, - ), - ( - H256::from_slice(&[2; 32]), - PolkaBtcIssueRequest { - opentime: 10, - ..Default::default() - }, - ), - ( - H256::from_slice(&[3; 32]), - PolkaBtcIssueRequest { - opentime: 85, - ..Default::default() - }, - ), - ]) - }); + provider.expect_get_vault_issue_requests().times(1).returning(|_| { + Ok(vec![ + ( + H256::from_slice(&[1; 32]), + PolkaBtcIssueRequest { + opentime: 95, + ..Default::default() + }, + ), + ( + H256::from_slice(&[2; 32]), + PolkaBtcIssueRequest { + opentime: 10, + ..Default::default() + }, + ), + ( + H256::from_slice(&[3; 32]), + PolkaBtcIssueRequest { + opentime: 85, + ..Default::default() + }, + ), + ]) + }); provider .expect_get_current_chain_height() .times(1) .returning(|| Ok(100)); - provider - .expect_get_issue_period() - .times(1) - .returning(|| Ok(10)); + provider.expect_get_issue_period().times(1).returning(|| Ok(10)); - let mut canceller = CancellationScheduler::new(Arc::new(provider), Default::default()); + let mut canceller = CancellationScheduler::new(provider, Default::default()); // checks that the delay is calculated correctly, and that the vec is sorted assert_eq!( - canceller - .get_open_requests::() - .await - .unwrap(), + canceller.get_open_requests::().await.unwrap(), vec![ ActiveRequest { id: H256::from_slice(&[2; 32]), @@ -558,25 +536,19 @@ mod tests { async fn test_get_open_process_delays_with_invalid_opentime_fails() { // if current_block is 5 and the issue was open at 10, something went wrong... let mut provider = MockProvider::default(); - provider - .expect_get_vault_issue_requests() - .times(1) - .returning(|_| { - Ok(vec![( - H256::from_slice(&[1; 32]), - PolkaBtcIssueRequest { - opentime: 10, - ..Default::default() - }, - )]) - }); - provider - .expect_get_current_chain_height() - .times(1) - .returning(|| Ok(5)); + provider.expect_get_vault_issue_requests().times(1).returning(|_| { + Ok(vec![( + H256::from_slice(&[1; 32]), + PolkaBtcIssueRequest { + opentime: 10, + ..Default::default() + }, + )]) + }); + provider.expect_get_current_chain_height().times(1).returning(|| Ok(5)); provider.expect_get_issue_period().returning(|| Ok(10)); - let mut canceller = CancellationScheduler::new(Arc::new(provider), Default::default()); + let mut canceller = CancellationScheduler::new(provider, Default::default()); assert_err!( canceller.get_open_requests::().await, Error::InvalidOpenTime @@ -587,35 +559,25 @@ mod tests { async fn test_wait_for_event_succeeds() { // check that we actually cancel the issue when it expires let mut provider = MockProvider::default(); - provider - .expect_get_vault_issue_requests() - .times(1) - .returning(|_| { - Ok(vec![( - H256::from_slice(&[1; 32]), - PolkaBtcIssueRequest { - opentime: 10, - ..Default::default() - }, - )]) - }); - provider - .expect_get_current_chain_height() - .times(1) - .returning(|| Ok(15)); + provider.expect_get_vault_issue_requests().times(1).returning(|_| { + Ok(vec![( + H256::from_slice(&[1; 32]), + PolkaBtcIssueRequest { + opentime: 10, + ..Default::default() + }, + )]) + }); + provider.expect_get_current_chain_height().times(1).returning(|| Ok(15)); provider.expect_get_issue_period().returning(|| Ok(10)); // check that it cancels the issue - provider - .expect_cancel_issue() - .times(1) - .returning(|_| Ok(())); + provider.expect_cancel_issue().times(1).returning(|_| Ok(())); let (_, mut block_listener) = mpsc::channel::(16); let (_, mut event_listener) = mpsc::channel::(16); let mut active_processes: Vec = vec![]; - let mut cancellation_scheduler = - CancellationScheduler::new(Arc::new(provider), AccountId::default()); + let mut cancellation_scheduler = CancellationScheduler::new(provider, AccountId::default()); // simulate that we have a a new block let selector = TestEventSelector { @@ -671,16 +633,11 @@ mod tests { }, ]; - let mut cancellation_scheduler = - CancellationScheduler::new(Arc::new(provider), AccountId::default()); + let mut cancellation_scheduler = CancellationScheduler::new(provider, AccountId::default()); // simulate that the issue gets executed let selector = TestEventSelector { - on_event: |_, _| { - Ok(BlockOrEvent::Event(RequestEvent::Executed( - H256::from_slice(&[2; 32]), - ))) - }, + on_event: |_, _| Ok(BlockOrEvent::Event(RequestEvent::Executed(H256::from_slice(&[2; 32])))), }; // simulate that the issue gets executed @@ -700,10 +657,7 @@ mod tests { // check that the process with id 2 was removed assert_eq!( - active_processes - .into_iter() - .map(|x| x.id) - .collect::>(), + active_processes.into_iter().map(|x| x.id).collect::>(), vec![H256::from_slice(&[1; 32]), H256::from_slice(&[3; 32])] ); } @@ -713,37 +667,26 @@ mod tests { // checks that we query for new issues, and that when the issue gets executed, it // is removed from the list let mut provider = MockProvider::default(); - provider - .expect_get_vault_issue_requests() - .times(1) - .returning(|_| { - Ok(vec![( - H256::from_slice(&[1; 32]), - PolkaBtcIssueRequest { - opentime: 10, - ..Default::default() - }, - )]) - }); - provider - .expect_get_current_chain_height() - .times(1) - .returning(|| Ok(15)); + provider.expect_get_vault_issue_requests().times(1).returning(|_| { + Ok(vec![( + H256::from_slice(&[1; 32]), + PolkaBtcIssueRequest { + opentime: 10, + ..Default::default() + }, + )]) + }); + provider.expect_get_current_chain_height().times(1).returning(|| Ok(15)); provider.expect_get_issue_period().returning(|| Ok(10)); let (_, mut block_listener) = mpsc::channel::(16); let (_, mut event_listener) = mpsc::channel::(16); let mut active_processes: Vec = vec![]; - let mut cancellation_scheduler = - CancellationScheduler::new(Arc::new(provider), AccountId::default()); + let mut cancellation_scheduler = CancellationScheduler::new(provider, AccountId::default()); // simulate that the issue gets executed let selector = TestEventSelector { - on_event: |_, _| { - Ok(BlockOrEvent::Event(RequestEvent::Executed( - H256::from_slice(&[1; 32]), - ))) - }, + on_event: |_, _| Ok(BlockOrEvent::Event(RequestEvent::Executed(H256::from_slice(&[1; 32])))), }; assert_eq!( @@ -776,8 +719,7 @@ mod tests { let (_, mut block_listener) = mpsc::channel::(16); let (_, mut event_listener) = mpsc::channel::(16); let mut active_processes: Vec = vec![]; - let mut cancellation_scheduler = - CancellationScheduler::new(Arc::new(provider), AccountId::default()); + let mut cancellation_scheduler = CancellationScheduler::new(provider, AccountId::default()); // simulate that we have a timeout (new issue request opened) let selector = TestEventSelector { @@ -808,8 +750,7 @@ mod tests { let (_, mut block_listener) = mpsc::channel::(16); let (_, mut event_listener) = mpsc::channel::(16); let mut active_processes: Vec = vec![]; - let mut cancellation_scheduler = - CancellationScheduler::new(Arc::new(provider), AccountId::default()); + let mut cancellation_scheduler = CancellationScheduler::new(provider, AccountId::default()); // simulate that we have a timeout let selector = TestEventSelector { diff --git a/vault/src/collateral.rs b/vault/src/collateral.rs index 12d758778..4e225ea9b 100644 --- a/vault/src/collateral.rs +++ b/vault/src/collateral.rs @@ -1,14 +1,12 @@ use crate::error::Error; use log::*; use runtime::{ - pallets::exchange_rate_oracle::SetExchangeRateEvent, pallets::vault_registry::VaultStatus, - AccountId, DotBalancesPallet, PolkaBtcProvider, PolkaBtcRuntime, UtilFuncs, - VaultRegistryPallet, + pallets::{exchange_rate_oracle::SetExchangeRateEvent, vault_registry::VaultStatus}, + AccountId, DotBalancesPallet, PolkaBtcProvider, PolkaBtcRuntime, UtilFuncs, VaultRegistryPallet, }; -use std::sync::Arc; pub async fn maintain_collateralization_rate( - provider: Arc, + provider: PolkaBtcProvider, maximum_collateral: u128, ) -> Result<(), runtime::Error> { let provider = &provider; @@ -18,12 +16,8 @@ pub async fn maintain_collateralization_rate( info!("Received SetExchangeRateEvent"); // todo: implement retrying - match lock_required_collateral( - provider.clone(), - provider.get_account_id().clone(), - maximum_collateral, - ) - .await + match lock_required_collateral(provider.clone(), provider.get_account_id().clone(), maximum_collateral) + .await { // vault not being registered is ok, no need to log it Err(Error::RuntimeError(runtime::Error::VaultNotFound)) => {} @@ -50,7 +44,7 @@ pub async fn maintain_collateralization_rate( /// * `vault_id` - the id of this vault /// * `maximum_collateral` - the upperbound of total collateral that is allowed to be placed pub async fn lock_required_collateral( - provider: Arc

, + provider: P, vault_id: AccountId, maximum_collateral: u128, ) -> Result<(), Error> { @@ -60,9 +54,7 @@ pub async fn lock_required_collateral Self { + // NOTE: expectations dropped + Self::default() + } + } + #[tokio::test] async fn test_lock_required_collateral_case_1() { // case 1: required <= actual <= limit -- do nothing (already enough) @@ -185,12 +181,10 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(50)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(75)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(75)); let vault_id = AccountId::default(); - assert_ok!(lock_required_collateral(Arc::new(provider), vault_id, 100).await); + assert_ok!(lock_required_collateral(provider, vault_id, 100).await); } #[tokio::test] @@ -209,12 +203,10 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(200)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(200)); let vault_id = AccountId::default(); - assert_ok!(lock_required_collateral(Arc::new(provider), vault_id, 150).await); + assert_ok!(lock_required_collateral(provider, vault_id, 150).await); } #[tokio::test] @@ -233,12 +225,10 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(150)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(150)); let vault_id = AccountId::default(); - assert_ok!(lock_required_collateral(Arc::new(provider), vault_id, 75).await); + assert_ok!(lock_required_collateral(provider, vault_id, 75).await); } #[tokio::test] @@ -257,13 +247,11 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(75)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(75)); let vault_id = AccountId::default(); assert_err!( - lock_required_collateral(Arc::new(provider), vault_id, 50).await, + lock_required_collateral(provider, vault_id, 50).await, Error::InsufficientFunds ); } @@ -283,9 +271,7 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(25)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(25)); provider .expect_lock_additional_collateral() .withf(|&amount| amount == 50) @@ -294,7 +280,7 @@ mod tests { let vault_id = AccountId::default(); assert_err!( - lock_required_collateral(Arc::new(provider), vault_id, 75).await, + lock_required_collateral(provider, vault_id, 75).await, Error::InsufficientFunds ); } @@ -313,9 +299,7 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(25)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(25)); provider .expect_lock_additional_collateral() .withf(|&amount| amount == 75) @@ -323,7 +307,7 @@ mod tests { .returning(|_| Ok(())); let vault_id = AccountId::default(); - assert_ok!(lock_required_collateral(Arc::new(provider), vault_id, 200).await); + assert_ok!(lock_required_collateral(provider, vault_id, 200).await); } #[tokio::test] @@ -341,13 +325,11 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(25)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(25)); let vault_id = AccountId::default(); assert_err!( - lock_required_collateral(Arc::new(provider), vault_id, 25).await, + lock_required_collateral(provider, vault_id, 25).await, Error::InsufficientFunds ); } @@ -367,12 +349,10 @@ mod tests { provider .expect_get_required_collateral_for_vault() .returning(|_| Ok(100)); - provider - .expect_get_reserved_dot_balance() - .returning(|| Ok(100)); + provider.expect_get_reserved_dot_balance().returning(|| Ok(100)); let vault_id = AccountId::default(); - assert_ok!(lock_required_collateral(Arc::new(provider), vault_id, 200).await); + assert_ok!(lock_required_collateral(provider, vault_id, 200).await); } #[tokio::test] @@ -388,7 +368,7 @@ mod tests { let vault_id = AccountId::default(); assert_err!( - lock_required_collateral(Arc::new(provider), vault_id, 75).await, + lock_required_collateral(provider, vault_id, 75).await, Error::RuntimeError(runtime::Error::VaultNotFound) ); } diff --git a/vault/src/error.rs b/vault/src/error.rs index d53f1cdda..4b3c62a8b 100644 --- a/vault/src/error.rs +++ b/vault/src/error.rs @@ -9,6 +9,8 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum Error { + #[error("Internal error")] + InternalError, #[error("Insufficient funds available")] InsufficientFunds, #[error("Open time inconsistent with chain height")] @@ -29,11 +31,13 @@ pub enum Error { ArithmeticUnderflow, #[error("Mathematical operation error")] MathError, + #[error("Vault has uncompleted redeem requests")] + UncompletedRedeemRequests, + #[error("RPC error: {0}")] RpcError(#[from] RpcError), #[error("Hex conversion error: {0}")] FromHexError(#[from] FromHexError), - #[error("BitcoinError: {0}")] BitcoinError(#[from] BitcoinError), #[error("RuntimeError: {0}")] diff --git a/vault/src/execution.rs b/vault/src/execution.rs index 46390794b..09cdd7e27 100644 --- a/vault/src/execution.rs +++ b/vault/src/execution.rs @@ -1,6 +1,8 @@ -use crate::constants::*; -use crate::error::Error; -use crate::issue::{process_issue_requests, IssueRequests}; +use crate::{ + constants::*, + error::Error, + issue::{process_issue_requests, IssueRequests}, +}; use backoff::{future::FutureOperation as _, ExponentialBackoff}; use bitcoin::{BitcoinCoreApi, Transaction, TransactionExt, TransactionMetadata}; use futures::stream::StreamExt; @@ -11,9 +13,8 @@ use runtime::{ refund::RequestRefundEvent, replace::{AcceptReplaceEvent, AuctionReplaceEvent}, }, - BtcAddress, H256Le, PolkaBtcProvider, PolkaBtcRedeemRequest, PolkaBtcRefundRequest, - PolkaBtcReplaceRequest, PolkaBtcRuntime, RedeemPallet, RefundPallet, ReplacePallet, UtilFuncs, - VaultRegistryPallet, + BtcAddress, BtcRelayPallet, H256Le, PolkaBtcProvider, PolkaBtcRedeemRequest, PolkaBtcRefundRequest, + PolkaBtcReplaceRequest, PolkaBtcRuntime, RedeemPallet, RefundPallet, ReplacePallet, UtilFuncs, VaultRegistryPallet, }; use sp_core::H256; use std::{collections::HashMap, sync::Arc, time::Duration}; @@ -45,6 +46,7 @@ impl Request { request_type: RequestType::Redeem, } } + /// Constructs a Request for the given PolkaBtcReplaceRequest fn from_replace_request(hash: H256, request: PolkaBtcReplaceRequest) -> Option { Some(Request { @@ -55,6 +57,7 @@ impl Request { request_type: RequestType::Replace, }) } + /// Constructs a Request for the given PolkaBtcRefundRequest fn from_refund_request(hash: H256, request: PolkaBtcRefundRequest) -> Request { Request { @@ -65,6 +68,7 @@ impl Request { request_type: RequestType::Refund, } } + /// Constructs a Request for the given RequestRefundEvent pub fn from_refund_request_event(request: &RequestRefundEvent) -> Request { Request { @@ -75,6 +79,7 @@ impl Request { request_type: RequestType::Refund, } } + /// Constructs a Request for the given AcceptReplaceEvent pub fn from_accept_replace_event(request: &AcceptReplaceEvent) -> Request { Request { @@ -85,6 +90,7 @@ impl Request { request_type: RequestType::Replace, } } + /// Constructs a Request for the given AuctionReplaceEvent pub fn from_auction_replace_event(request: &AuctionReplaceEvent) -> Request { Request { @@ -95,6 +101,7 @@ impl Request { request_type: RequestType::Replace, } } + /// Constructs a Request for the given RequestRedeemEvent pub fn from_redeem_request_event(request: &RequestRedeemEvent) -> Request { Request { @@ -108,25 +115,23 @@ impl Request { /// Makes the bitcoin transfer and executes the request pub async fn pay_and_execute< - B: BitcoinCoreApi, - P: ReplacePallet + RefundPallet + RedeemPallet + VaultRegistryPallet + UtilFuncs + Send + Sync, + B: BitcoinCoreApi + Clone, + P: ReplacePallet + RefundPallet + RedeemPallet + VaultRegistryPallet + UtilFuncs + Clone + Send + Sync, >( &self, - provider: Arc

, - btc_rpc: Arc, + provider: P, + btc_rpc: B, num_confirmations: u32, ) -> Result<(), Error> { - let tx_metadata = self - .transfer_btc(provider.clone(), btc_rpc, num_confirmations) - .await?; + let tx_metadata = self.transfer_btc(&provider, btc_rpc, num_confirmations).await?; self.execute(provider, tx_metadata).await } /// Make a bitcoin transfer to fulfil the request - async fn transfer_btc( + async fn transfer_btc( &self, - provider: Arc

, - btc_rpc: Arc, + provider: &P, + btc_rpc: B, num_confirmations: u32, ) -> Result { info!("Sending bitcoin to {}", self.btc_address); @@ -169,7 +174,7 @@ impl Request { /// Executes the request. Upon failure it will retry async fn execute( &self, - provider: Arc

, + provider: P, tx_metadata: TransactionMetadata, ) -> Result<(), Error> { // select the execute function based on request_type @@ -183,7 +188,7 @@ impl Request { (|| async { // call the selected function (execute)( - &*provider, + &provider, self.hash, H256Le::from_bytes_le(tx_metadata.txid.as_ref()), tx_metadata.proof.clone(), @@ -209,12 +214,13 @@ impl Request { /// Queries the parachain for open requests/replaces and executes them. It checks the /// bitcoin blockchain to see if a payment has already been made. -pub async fn execute_open_requests( - provider: Arc, - btc_rpc: Arc, +pub async fn execute_open_requests( + provider: PolkaBtcProvider, + btc_rpc: B, num_confirmations: u32, ) -> Result<(), Error> { let vault_id = provider.get_account_id().clone(); + // get all open redeem/replaces and map them to the shared Request type let open_redeems = provider .clone() @@ -223,12 +229,14 @@ pub async fn execute_open_requests( .into_iter() .filter(|(_, request)| !request.completed && !request.cancelled) .map(|(hash, request)| Request::from_redeem_request(hash, request)); + let open_replaces = provider .get_old_vault_replace_requests(vault_id.clone()) .await? .into_iter() .filter(|(_, request)| !request.completed && !request.cancelled) .filter_map(|(hash, request)| Request::from_replace_request(hash, request)); + let open_refunds = provider .get_vault_refund_requests(vault_id) .await? @@ -249,13 +257,12 @@ pub async fn execute_open_requests( .map(|(_, request)| request.open_time.unwrap_or(u32::MAX)) .min() { - Some(x) => provider.clone().get_blockchain_height_at(x).await?, + Some(x) => provider.get_blockchain_height_at(x).await?, None => return Ok(()), // the iterator is empty so we have nothing to do }; - // iterate through transactions.. - let mut transaction_stream = - bitcoin::get_transactions(btc_rpc.clone(), btc_start_height).await?; + // iterate through transactions + let mut transaction_stream = bitcoin::get_transactions(&btc_rpc, btc_start_height).await?; while let Some(x) = transaction_stream.next().await { let tx = x?; @@ -277,20 +284,33 @@ pub async fn execute_open_requests( // Payment has been made, but it might not have been confirmed enough times yet let tx_metadata = btc_rpc .clone() - .wait_for_transaction_metadata( - tx.txid(), - BITCOIN_MAX_RETRYING_TIME, - num_confirmations, - ) + .wait_for_transaction_metadata(tx.txid(), BITCOIN_MAX_RETRYING_TIME, num_confirmations) .await; match tx_metadata { - Ok(tx_metadata) => match request.execute(provider.clone(), tx_metadata).await { - Ok(_) => { - info!("Executed request #{}", request.hash); + Ok(tx_metadata) => { + // we have enough btc confirmations, now make sure they have been relayed before we continue + if let Err(e) = provider + .wait_for_block_in_relay( + H256Le::from_bytes_le(&tx_metadata.block_hash.to_vec()), + num_confirmations, + ) + .await + { + error!( + "Error while waiting for block inclusion for request #{}: {}", + request.hash, e + ); + // continue; try to execute anyway + } + + match request.execute(provider.clone(), tx_metadata).await { + Ok(_) => { + info!("Executed request #{}", request.hash); + } + Err(e) => error!("Failed to execute request #{}: {}", request.hash, e), } - Err(e) => error!("Failed to execute request #{}: {}", request.hash, e), - }, + } Err(e) => error!( "Failed to confirm bitcoin transaction for request {}: {}", request.hash, e @@ -315,10 +335,7 @@ pub async fn execute_open_requests( request.request_type, request.hash ); - match request - .pay_and_execute(provider, btc_rpc, num_confirmations) - .await - { + match request.pay_and_execute(provider, btc_rpc, num_confirmations).await { Ok(_) => info!( "{:?} request #{} successfully executed", request.request_type, request.hash @@ -335,9 +352,9 @@ pub async fn execute_open_requests( } /// Execute open issue requests, retry if stream ends early. -pub async fn execute_open_issue_requests( - provider: Arc, - btc_rpc: Arc, +pub async fn execute_open_issue_requests( + provider: PolkaBtcProvider, + btc_rpc: B, issue_set: Arc, num_confirmations: u32, ) -> Result<(), Error> { @@ -368,256 +385,283 @@ fn get_request_for_btc_tx(tx: &Transaction, hash_map: &HashMap) - #[cfg(test)] mod tests { - // use super::*; - // use async_trait::async_trait; - // use bitcoin::{ - // Block, BlockHash, Error as BitcoinError, GetBlockResult, GetRawTransactionResult, - // LockedTransaction, Network, PartialAddress, Transaction, TransactionMetadata, Txid, - // }; - // use runtime::{AccountId, Error as RuntimeError, PolkaBtcVault}; - // use sp_core::H160; - // use std::future::Future; - // macro_rules! assert_ok { - // ( $x:expr $(,)? ) => { - // let is = $x; - // match is { - // Ok(_) => (), - // _ => assert!(false, "Expected Ok(_). Got {:#?}", is), - // } - // }; - // ( $x:expr, $y:expr $(,)? ) => { - // assert_eq!($x, Ok($y)); - // }; - // } - // macro_rules! assert_err { - // ($result:expr, $err:pat) => {{ - // match $result { - // Err($err) => (), - // Ok(v) => panic!("assertion failed: Ok({:?})", v), - // _ => panic!("expected: Err($err)"), - // } - // }}; - // } - - // mockall::mock! { - // Provider {} - - // #[async_trait] - // pub trait UtilFuncs { - // async fn get_current_chain_height(&self) -> Result; - // async fn get_blockchain_height_at(&self, parachain_height: u32) -> Result; - // fn get_account_id(&self) -> &AccountId; - // } - // #[async_trait] - // pub trait VaultRegistryPallet { - // async fn get_vault(&self, vault_id: AccountId) -> Result; - // async fn get_all_vaults(&self) -> Result, RuntimeError>; - // async fn register_vault(&self, collateral: u128, btc_address: BtcAddress) -> Result<(), RuntimeError>; - // async fn lock_additional_collateral(&self, amount: u128) -> Result<(), RuntimeError>; - // async fn withdraw_collateral(&self, amount: u128) -> Result<(), RuntimeError>; - // async fn update_btc_address(&self, address: BtcAddress) -> Result<(), RuntimeError>; - // async fn get_required_collateral_for_polkabtc(&self, amount_btc: u128) -> Result; - // async fn get_required_collateral_for_vault(&self, vault_id: AccountId) -> Result; - // async fn is_vault_below_auction_threshold(&self, vault_id: AccountId) -> Result; - // } - // #[async_trait] - // pub trait RedeemPallet { - // async fn get_redeem_request(&self, redeem_id: H256) -> Result; - // async fn request_redeem( - // &self, - // amount_polka_btc: u128, - // btc_address: BtcAddress, - // vault_id: AccountId, - // ) -> Result; - // async fn execute_redeem( - // &self, - // redeem_id: H256, - // tx_id: H256Le, - // merkle_proof: Vec, - // raw_tx: Vec, - // ) -> Result<(), RuntimeError>; - // async fn cancel_redeem(&self, redeem_id: H256, reimburse: bool) -> Result<(), RuntimeError>; - // async fn get_vault_redeem_requests( - // &self, - // account_id: AccountId, - // ) -> Result, RuntimeError>; - // async fn set_redeem_period(&self, period: u32) -> Result<(), RuntimeError>; - // } - // #[async_trait] - // pub trait ReplacePallet { - // async fn request_replace(&self, amount: u128, griefing_collateral: u128) - // -> Result; - // async fn withdraw_replace(&self, replace_id: H256) -> Result<(), RuntimeError>; - // async fn accept_replace(&self, replace_id: H256, collateral: u128) -> Result<(), RuntimeError>; - // async fn auction_replace( - // &self, - // old_vault: AccountId, - // btc_amount: u128, - // collateral: u128, - // ) -> Result<(), RuntimeError>; - // async fn execute_replace( - // &self, - // replace_id: H256, - // tx_id: H256Le, - // merkle_proof: Vec, - // raw_tx: Vec, - // ) -> Result<(), RuntimeError>; - // async fn cancel_replace(&self, replace_id: H256) -> Result<(), RuntimeError>; - // async fn get_new_vault_replace_requests( - // &self, - // account_id: AccountId, - // ) -> Result, RuntimeError>; - // async fn get_old_vault_replace_requests( - // &self, - // account_id: AccountId, - // ) -> Result, RuntimeError>; - // async fn get_replace_period(&self) -> Result; - // async fn set_replace_period(&self, period: u32) -> Result<(), RuntimeError>; - // async fn get_replace_request(&self, replace_id: H256) -> Result; - // } - // } - - // mockall::mock! { - // Bitcoin {} - - // #[async_trait] - // trait BitcoinCoreApi { - // async fn wait_for_block(&self, height: u32, delay: Duration) -> Result; - // async fn get_block_count(&self) -> Result; - // async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, BitcoinError>; - // async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, BitcoinError>; - // async fn get_block_hash_for(&self, height: u32) -> Result; - // async fn is_block_known(&self, block_hash: BlockHash) -> Result; - // async fn get_new_address(&self) -> Result; - // async fn get_best_block_hash(&self) -> Result; - // async fn get_block(&self, hash: &BlockHash) -> Result; - // async fn get_block_info(&self, hash: &BlockHash) -> Result; - // async fn get_mempool_transactions<'a>( - // self: Arc, - // ) -> Result> + 'a>, BitcoinError>; - // async fn wait_for_transaction_metadata( - // &self, - // txid: Txid, - // op_timeout: Duration, - // num_confirmations: u32, - // ) -> Result; - // async fn create_transaction( - // &self, - // address: A, - // sat: u64, - // request_id: Option, - // ) -> Result; - // async fn send_transaction(&self, transaction: LockedTransaction) -> Result; - // async fn create_and_send_transaction( - // &self, - // address: A, - // sat: u64, - // request_id: Option, - // ) -> Result; - // async fn send_to_address( - // &self, - // address: A, - // sat: u64, - // request_id: Option, - // op_timeout: Duration, - // num_confirmations: u32, - // ) -> Result; - // async fn create_wallet(&self, wallet: &str) -> Result<(), BitcoinError>; - // } - // } - - // fn dummy_transaction_metadata() -> TransactionMetadata { - // TransactionMetadata { - // block_hash: Default::default(), - // block_height: Default::default(), - // proof: Default::default(), - // raw_tx: Default::default(), - // txid: Default::default(), - // } - // } - - // TODO: re-enable these tests - - // #[tokio::test] - // async fn test_pay_and_execute_redeem_succeeds() { - // let mut provider = MockProvider::default(); - // let mut btc_rpc = MockBitcoin::default(); - // btc_rpc - // .expect_send_to_address::() - // .times(1) // checks that this function is not retried - // .returning(|_, _, _, _, _| Ok(dummy_transaction_metadata())); - - // provider - // .expect_execute_redeem() - // .times(1) - // .returning(|_, _, _, _| Ok(())); - - // let request = Request { - // amount: 100, - // btc_address: BtcAddress::P2SH(H160::from_slice(&[1; 20])), - // hash: H256::from_slice(&[1; 32]), - // open_time: None, - // request_type: RequestType::Redeem, - // }; - - // assert_ok!( - // request - // .pay_and_execute(Arc::new(provider), Arc::new(btc_rpc), 6) - // .await - // ); - // } - - // #[tokio::test] - // async fn test_pay_and_execute_replace_succeeds() { - // let mut provider = MockProvider::default(); - // let mut btc_rpc = MockBitcoin::default(); - // btc_rpc - // .expect_send_to_address::() - // .times(1) // checks that this function is not retried - // .returning(|_, _, _, _, _| Ok(dummy_transaction_metadata())); - - // provider - // .expect_execute_replace() - // .times(1) - // .returning(|_, _, _, _| Ok(())); - - // let request = Request { - // amount: 100, - // btc_address: BtcAddress::P2SH(H160::from_slice(&[1; 20])), - // hash: H256::from_slice(&[1; 32]), - // open_time: None, - // request_type: RequestType::Replace, - // }; - - // assert_ok!( - // request - // .pay_and_execute(Arc::new(provider), Arc::new(btc_rpc), 6) - // .await - // ); - // } - - // #[tokio::test] - // async fn test_pay_and_execute_no_bitcoin_retry() { - // let provider = MockProvider::default(); - // let mut btc_rpc = MockBitcoin::default(); - // btc_rpc - // .expect_send_to_address::() - // .times(1) // checks that this function is not retried - // .returning(|_, _, _, _, _| Err(BitcoinError::ConfirmationError)); - - // let request = Request { - // amount: 100, - // btc_address: BtcAddress::P2SH(H160::from_slice(&[1; 20])), - // hash: H256::from_slice(&[1; 32]), - // open_time: None, - // request_type: RequestType::Replace, - // }; - - // assert_err!( - // request - // .pay_and_execute(Arc::new(provider), Arc::new(btc_rpc), 6) - // .await, - // Error::BitcoinError(BitcoinError::ConfirmationError) - // ); - // } + use super::*; + use async_trait::async_trait; + use bitcoin::{ + Block, BlockHash, BlockHeader, Error as BitcoinError, GetBlockResult, LockedTransaction, PartialAddress, + Transaction, TransactionMetadata, Txid, PUBLIC_KEY_SIZE, + }; + use runtime::{AccountId, BlockNumber, BtcPublicKey, Error as RuntimeError, PolkaBtcVault}; + use sp_core::H160; + + macro_rules! assert_ok { + ( $x:expr $(,)? ) => { + let is = $x; + match is { + Ok(_) => (), + _ => assert!(false, "Expected Ok(_). Got {:#?}", is), + } + }; + ( $x:expr, $y:expr $(,)? ) => { + assert_eq!($x, Ok($y)); + }; + } + + mockall::mock! { + Provider {} + + #[async_trait] + pub trait UtilFuncs { + async fn get_current_chain_height(&self) -> Result; + async fn get_blockchain_height_at(&self, parachain_height: u32) -> Result; + fn get_account_id(&self) -> &AccountId; + } + + #[async_trait] + pub trait VaultRegistryPallet { + async fn get_vault(&self, vault_id: AccountId) -> Result; + async fn get_all_vaults(&self) -> Result, RuntimeError>; + async fn register_vault(&self, collateral: u128, public_key: BtcPublicKey) -> Result<(), RuntimeError>; + async fn lock_additional_collateral(&self, amount: u128) -> Result<(), RuntimeError>; + async fn withdraw_collateral(&self, amount: u128) -> Result<(), RuntimeError>; + async fn update_public_key(&self, public_key: BtcPublicKey) -> Result<(), RuntimeError>; + async fn register_address(&self, btc_address: BtcAddress) -> Result<(), RuntimeError>; + async fn get_required_collateral_for_polkabtc(&self, amount_btc: u128) -> Result; + async fn get_required_collateral_for_vault(&self, vault_id: AccountId) -> Result; + async fn is_vault_below_auction_threshold(&self, vault_id: AccountId) -> Result; + } + + #[async_trait] + pub trait RedeemPallet { + async fn request_redeem( + &self, + amount_polka_btc: u128, + btc_address: BtcAddress, + vault_id: AccountId, + ) -> Result; + async fn execute_redeem( + &self, + redeem_id: H256, + tx_id: H256Le, + merkle_proof: Vec, + raw_tx: Vec, + ) -> Result<(), RuntimeError>; + async fn cancel_redeem(&self, redeem_id: H256, reimburse: bool) -> Result<(), RuntimeError>; + async fn get_redeem_request(&self, redeem_id: H256) -> Result; + async fn get_vault_redeem_requests( + &self, + account_id: AccountId, + ) -> Result, RuntimeError>; + async fn get_redeem_period(&self) -> Result; + async fn set_redeem_period(&self, period: u32) -> Result<(), RuntimeError>; + } + + #[async_trait] + pub trait ReplacePallet { + async fn request_replace(&self, amount: u128, griefing_collateral: u128) + -> Result; + async fn withdraw_replace(&self, replace_id: H256) -> Result<(), RuntimeError>; + async fn accept_replace(&self, replace_id: H256, collateral: u128, btc_address: BtcAddress) -> Result<(), RuntimeError>; + async fn auction_replace( + &self, + old_vault: AccountId, + btc_amount: u128, + collateral: u128, + btc_address: BtcAddress, + ) -> Result<(), RuntimeError>; + async fn execute_replace( + &self, + replace_id: H256, + tx_id: H256Le, + merkle_proof: Vec, + raw_tx: Vec, + ) -> Result<(), RuntimeError>; + async fn cancel_replace(&self, replace_id: H256) -> Result<(), RuntimeError>; + async fn get_replace_request(&self, replace_id: H256) -> Result; + async fn get_new_vault_replace_requests( + &self, + account_id: AccountId, + ) -> Result, RuntimeError>; + async fn get_old_vault_replace_requests( + &self, + account_id: AccountId, + ) -> Result, RuntimeError>; + async fn get_replace_period(&self) -> Result; + async fn set_replace_period(&self, period: u32) -> Result<(), RuntimeError>; + } + + #[async_trait] + pub trait RefundPallet { + async fn execute_refund( + &self, + refund_id: H256, + tx_id: H256Le, + merkle_proof: Vec, + raw_tx: Vec, + ) -> Result<(), RuntimeError>; + async fn get_vault_refund_requests( + &self, + account_id: AccountId, + ) -> Result, RuntimeError>; + } + + } + + impl Clone for MockProvider { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + + mockall::mock! { + Bitcoin {} + + #[async_trait] + trait BitcoinCoreApi { + async fn wait_for_block(&self, height: u32, delay: Duration, num_confirmations: u32) -> Result; + async fn get_block_count(&self) -> Result; + async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, BitcoinError>; + async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, BitcoinError>; + async fn get_block_hash(&self, height: u32) -> Result; + async fn is_block_known(&self, block_hash: BlockHash) -> Result; + async fn get_new_address(&self) -> Result; + async fn get_new_public_key + 'static>(&self) -> Result; + async fn add_new_deposit_key + Send + Sync + 'static>( + &self, + public_key: P, + secret_key: Vec, + ) -> Result<(), BitcoinError>; + async fn get_best_block_hash(&self) -> Result; + async fn get_block(&self, hash: &BlockHash) -> Result; + async fn get_block_header(&self, hash: &BlockHash) -> Result; + async fn get_block_info(&self, hash: &BlockHash) -> Result; + async fn get_mempool_transactions<'a>( + self: &'a Self, + ) -> Result> + Send + 'a>, BitcoinError>; + async fn wait_for_transaction_metadata( + &self, + txid: Txid, + op_timeout: Duration, + num_confirmations: u32, + ) -> Result; + async fn create_transaction( + &self, + address: A, + sat: u64, + request_id: Option, + ) -> Result; + async fn send_transaction(&self, transaction: LockedTransaction) -> Result; + async fn create_and_send_transaction( + &self, + address: A, + sat: u64, + request_id: Option, + ) -> Result; + async fn send_to_address( + &self, + address: A, + sat: u64, + request_id: Option, + op_timeout: Duration, + num_confirmations: u32, + ) -> Result; + async fn create_wallet(&self, wallet: &str) -> Result<(), BitcoinError>; + async fn wallet_has_public_key

(&self, public_key: P) -> Result + where + P: Into<[u8; PUBLIC_KEY_SIZE]> + From<[u8; PUBLIC_KEY_SIZE]> + Clone + PartialEq + Send + Sync + 'static; + } + } + + impl Clone for MockBitcoin { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + + #[tokio::test] + async fn should_pay_and_execute_redeem() { + let mut provider = MockProvider::default(); + provider.expect_execute_redeem().times(1).returning(|_, _, _, _| Ok(())); + + let mut btc_rpc = MockBitcoin::default(); + btc_rpc.expect_create_transaction::().returning(|_, _, _| { + Ok(LockedTransaction::new( + Transaction { + version: 0, + lock_time: 0, + input: vec![], + output: vec![], + }, + None, + )) + }); + + btc_rpc.expect_send_transaction().returning(|_| Ok(Txid::default())); + + btc_rpc.expect_wait_for_transaction_metadata().returning(|_, _, _| { + Ok(TransactionMetadata { + txid: Txid::default(), + proof: vec![], + raw_tx: vec![], + block_height: 0, + block_hash: BlockHash::default(), + }) + }); + + let request = Request { + amount: 100, + btc_address: BtcAddress::P2SH(H160::from_slice(&[1; 20])), + hash: H256::from_slice(&[1; 32]), + open_time: None, + request_type: RequestType::Redeem, + }; + + assert_ok!(request.pay_and_execute(provider, btc_rpc, 6).await); + } + + #[tokio::test] + async fn should_pay_and_execute_replace() { + let mut provider = MockProvider::default(); + provider + .expect_execute_replace() + .times(1) + .returning(|_, _, _, _| Ok(())); + + let mut btc_rpc = MockBitcoin::default(); + btc_rpc.expect_create_transaction::().returning(|_, _, _| { + Ok(LockedTransaction::new( + Transaction { + version: 0, + lock_time: 0, + input: vec![], + output: vec![], + }, + None, + )) + }); + + btc_rpc.expect_send_transaction().returning(|_| Ok(Txid::default())); + + btc_rpc.expect_wait_for_transaction_metadata().returning(|_, _, _| { + Ok(TransactionMetadata { + txid: Txid::default(), + proof: vec![], + raw_tx: vec![], + block_height: 0, + block_hash: BlockHash::default(), + }) + }); + + let request = Request { + amount: 100, + btc_address: BtcAddress::P2SH(H160::from_slice(&[1; 20])), + hash: H256::from_slice(&[1; 32]), + open_time: None, + request_type: RequestType::Replace, + }; + + assert_ok!(request.pay_and_execute(provider, btc_rpc, 6).await); + } } diff --git a/vault/src/faucet.rs b/vault/src/faucet.rs index 34d66ad3c..3f1368ef0 100644 --- a/vault/src/faucet.rs +++ b/vault/src/faucet.rs @@ -1,31 +1,63 @@ -use crate::{api, error::Error}; +use crate::{error::Error, http, lock_additional_collateral}; +use bitcoin::BitcoinCoreApi; use jsonrpc_core::Value; -use jsonrpc_core_client::TypedClient; +use jsonrpc_core_client::{transports::http as jsonrpc_http, TypedClient}; use parity_scale_codec::{Decode, Encode}; -use runtime::AccountId; +use runtime::{AccountId, PolkaBtcProvider, VaultRegistryPallet, PLANCK_PER_DOT, TX_FEES}; #[derive(Encode, Decode, Debug, Clone, serde::Serialize)] struct FundAccountJsonRpcRequest { pub account_id: AccountId, } -pub async fn get_faucet_allowance( - faucet_connection: TypedClient, - allowance_type: &str, -) -> Result { +async fn get_faucet_allowance(faucet_connection: TypedClient, allowance_type: &str) -> Result { let raw_allowance = faucet_connection - .call_method::<(), api::RawBytes>(&allowance_type, "", ()) + .call_method::<(), http::RawBytes>(&allowance_type, "", ()) .await?; Ok(Decode::decode(&mut &raw_allowance.0[..])?) } -pub async fn get_funding(faucet_connection: TypedClient, vault_id: AccountId) -> Result<(), Error> { - let funding_request = FundAccountJsonRpcRequest { - account_id: vault_id, - }; +async fn get_funding(faucet_connection: TypedClient, vault_id: AccountId) -> Result<(), Error> { + let funding_request = FundAccountJsonRpcRequest { account_id: vault_id }; let eq = format!("0x{}", hex::encode(funding_request.encode())); faucet_connection .call_method::, Value>("fund_account", "", vec![eq.clone()]) .await?; Ok(()) } + +pub async fn fund_and_register( + provider: &PolkaBtcProvider, + bitcoin_core: &B, + faucet_url: &String, + vault_id: AccountId, +) -> Result<(), Error> { + let connection = jsonrpc_http::connect::(faucet_url).await?; + + // Receive user allowance from faucet + get_funding(connection.clone(), vault_id.clone()).await?; + + let user_allowance_in_dot: u128 = get_faucet_allowance(connection.clone(), "user_allowance").await?; + let registration_collateral = user_allowance_in_dot + .checked_mul(PLANCK_PER_DOT) + .ok_or(Error::ArithmeticOverflow)? + .checked_sub(TX_FEES) + .ok_or(Error::ArithmeticUnderflow)?; + + let public_key = bitcoin_core.get_new_public_key().await?; + provider.register_vault(registration_collateral, public_key).await?; + + // Receive vault allowance from faucet + get_funding(connection.clone(), vault_id).await?; + + let vault_allowance_in_dot: u128 = get_faucet_allowance(connection.clone(), "vault_allowance").await?; + let operational_collateral = vault_allowance_in_dot + .checked_mul(PLANCK_PER_DOT) + .ok_or(Error::ArithmeticOverflow)? + .checked_sub(TX_FEES) + .ok_or(Error::ArithmeticUnderflow)?; + + lock_additional_collateral(&provider, operational_collateral).await?; + + Ok(()) +} diff --git a/vault/src/http.rs b/vault/src/http.rs new file mode 100644 index 000000000..d01afe23d --- /dev/null +++ b/vault/src/http.rs @@ -0,0 +1,263 @@ +use super::Error; +use bitcoin::BitcoinCoreApi; +use hex::FromHex; +use jsonrpc_http_server::{ + jsonrpc_core::{serde_json::Value, Error as JsonRpcError, ErrorCode as JsonRpcErrorCode, IoHandler, Params}, + DomainsValidation, ServerBuilder, +}; +use log::info; +use parity_scale_codec::{Decode, Encode}; +use runtime::{ + BtcPublicKey, Error as RuntimeError, ExchangeRateOraclePallet, FeePallet, FixedPointNumber, + FixedPointTraits::{CheckedAdd, CheckedMul}, + PolkaBtcProvider, RedeemPallet, ReplacePallet, UtilFuncs, VaultRegistryPallet, HOURS, +}; +use serde::{Deserialize, Deserializer}; +use sp_arithmetic::FixedU128; +use sp_core::{crypto::Ss58Codec, H256}; +use std::{net::SocketAddr, time::Duration}; +use tokio::time::timeout; + +const HEALTH_DURATION: Duration = Duration::from_millis(5000); + +#[derive(Debug, Clone, Deserialize)] +pub(crate) struct RawBytes(#[serde(deserialize_with = "hex_to_buffer")] pub(crate) Vec); + +pub fn hex_to_buffer<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + use serde::de::Error; + String::deserialize(deserializer) + .and_then(|string| Vec::from_hex(&string[2..]).map_err(|err| Error::custom(err.to_string()))) +} + +fn parse_params(params: Params) -> Result { + let raw: [RawBytes; 1] = params.parse()?; + let req = Decode::decode(&mut &raw[0].0[..]).map_err(Error::CodecError)?; + Ok(req) +} + +fn handle_resp(resp: Result) -> Result { + match resp { + Ok(data) => Ok(format!("0x{}", hex::encode(data.encode())).into()), + Err(err) => Err(JsonRpcError { + code: JsonRpcErrorCode::InternalError, + message: err.to_string(), + data: None, + }), + } +} + +// NOTE: will return error on restart if vault doesn't have +// enough time to process open redeem requests +async fn _system_health(provider: &PolkaBtcProvider) -> Result<(), Error> { + let result = match timeout(HEALTH_DURATION, provider.get_latest_block()).await { + Ok(res) => res, + Err(err) => return Err(Error::RuntimeError(RuntimeError::from(err))), + }; + + let signed_block = result?.ok_or(Error::NoIncomingBlocks)?; + let current_height: u128 = signed_block.block.header.number.into(); + let redeem_period = provider.get_redeem_period().await?; + + // TODO: parameterize based on expiry + let has_uncompleted = provider + .get_vault_redeem_requests(provider.get_account_id().clone()) + .await? + .iter() + .filter(|(_, request)| { + !request.completed + && !request.cancelled + // ensure not expired + && Into::::into(request.opentime.saturating_add(redeem_period)) > current_height + }) + .any(|(_, request)| Into::::into(request.opentime.saturating_add(HOURS)) > current_height); + + if has_uncompleted { + Err(Error::UncompletedRedeemRequests) + } else { + Ok(()) + } +} + +#[derive(Encode, Decode, Debug)] +struct AccountIdJsonRpcResponse { + account_id: String, +} + +fn _account_id(provider: &PolkaBtcProvider) -> Result { + Ok(AccountIdJsonRpcResponse { + account_id: provider.get_account_id().to_ss58check(), + }) +} + +#[derive(Encode, Decode, Debug)] +struct ReplaceRequestJsonRpcRequest { + amount: u128, +} + +async fn _request_replace(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { + let req = parse_params::(params)?; + + let amount_in_dot = provider.btc_to_dots(req.amount).await?; + let griefing_collateral_percentage = provider.get_replace_griefing_collateral().await?; + let griefing_collateral = calculate_for(amount_in_dot, griefing_collateral_percentage)?; + let result = provider.request_replace(req.amount, griefing_collateral).await; + info!( + "Requesting replace for amount = {} with griefing_collateral = {}: {:?}", + req.amount, griefing_collateral, result + ); + Ok(result.map(|_| ())?) +} + +/// Take the `percentage` of an `amount` +fn calculate_for(amount: u128, percentage: FixedU128) -> Result { + // we add 0.5 before we do the final integer division to round the result we return. + // note that unwrapping is safe because we use a constant + let rounding_addition = FixedU128::checked_from_rational(1, 2).unwrap(); + + FixedU128::checked_from_integer(amount) + .ok_or(Error::ArithmeticOverflow)? + .checked_mul(&percentage) + .ok_or(Error::ArithmeticOverflow)? + .checked_add(&rounding_addition) + .ok_or(Error::ArithmeticOverflow)? + .into_inner() + .checked_div(FixedU128::accuracy()) + .ok_or(Error::ArithmeticUnderflow) +} + +#[derive(Encode, Decode, Debug)] +struct RegisterVaultJsonRpcRequest { + collateral: u128, +} + +#[derive(Encode, Decode, Debug)] +struct RegisterVaultJsonRpcResponse { + public_key: BtcPublicKey, +} + +async fn _register_vault( + provider: &PolkaBtcProvider, + btc: &B, + params: Params, +) -> Result { + let req = parse_params::(params)?; + let public_key: BtcPublicKey = btc.get_new_public_key().await?; + let result = provider.register_vault(req.collateral, public_key.clone()).await; + info!( + "Registering vault with bitcoind public_key {:?} and collateral = {}: {:?}", + public_key, req.collateral, result + ); + Ok(result.map(|_| RegisterVaultJsonRpcResponse { public_key })?) +} + +#[derive(Encode, Decode, Debug)] +struct ChangeCollateralJsonRpcRequest { + amount: u128, +} + +async fn _lock_additional_collateral(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { + let req = parse_params::(params)?; + let result = provider.lock_additional_collateral(req.amount).await; + info!("Locking additional collateral; amount {}: {:?}", req.amount, result); + Ok(result?) +} + +async fn _withdraw_collateral(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { + let req = parse_params::(params)?; + let result = provider.withdraw_collateral(req.amount).await; + info!("Withdrawing collateral with amount {}: {:?}", req.amount, result); + Ok(result?) +} + +#[derive(Encode, Decode, Debug)] +struct WithdrawReplaceJsonRpcRequest { + replace_id: H256, +} + +async fn _withdraw_replace(provider: &PolkaBtcProvider, params: Params) -> Result<(), Error> { + let req = parse_params::(params)?; + let result = provider.withdraw_replace(req.replace_id).await; + info!("Withdrawing replace request {}: {:?}", req.replace_id, result); + Ok(result?) +} + +pub fn start_http( + provider: PolkaBtcProvider, + bitcoin_core: B, + addr: SocketAddr, + origin: String, + handle: tokio::runtime::Handle, +) -> jsonrpc_http_server::CloseHandle { + let mut io = IoHandler::default(); + { + let provider = provider.clone(); + io.add_method("system_health", move |_| { + let provider = provider.clone(); + async move { handle_resp(_system_health(&provider).await) } + }); + } + { + let provider = provider.clone(); + io.add_method("account_id", move |_| { + let provider = provider.clone(); + async move { handle_resp(_account_id(&provider)) } + }); + } + { + let provider = provider.clone(); + io.add_method("request_replace", move |params| { + let provider = provider.clone(); + async move { handle_resp(_request_replace(&provider, params).await) } + }); + } + { + let provider = provider.clone(); + let bitcoin_core = bitcoin_core.clone(); + io.add_method("register_vault", move |params| { + let provider = provider.clone(); + let bitcoin_core = bitcoin_core.clone(); + async move { handle_resp(_register_vault(&provider, &bitcoin_core, params).await) } + }); + } + { + let provider = provider.clone(); + io.add_method("lock_additional_collateral", move |params| { + let provider = provider.clone(); + async move { handle_resp(_lock_additional_collateral(&provider, params).await) } + }); + } + { + let provider = provider.clone(); + io.add_method("withdraw_collateral", move |params| { + let provider = provider.clone(); + async move { handle_resp(_withdraw_collateral(&provider, params).await) } + }); + } + { + let provider = provider.clone(); + io.add_method("withdraw_replace", move |params| { + let provider = provider.clone(); + async move { handle_resp(_withdraw_replace(&provider, params).await) } + }); + } + + let server = ServerBuilder::new(io) + .event_loop_executor(handle.clone()) + .health_api(("/health", "system_health")) + .rest_api(jsonrpc_http_server::RestApi::Unsecure) + .cors(DomainsValidation::AllowOnly(vec![origin.into()])) + .start_http(&addr) + .expect("Unable to start RPC server"); + + let close_handle = server.close_handle(); + + handle.spawn_blocking(move || { + info!("Starting http server..."); + server.wait(); + }); + + close_handle +} diff --git a/vault/src/issue.rs b/vault/src/issue.rs index fb4c12b79..5e9af967e 100644 --- a/vault/src/issue.rs +++ b/vault/src/issue.rs @@ -1,20 +1,16 @@ -use crate::cancellation::RequestEvent; -use crate::Error; +use crate::{cancellation::RequestEvent, Error}; use bitcoin::{BitcoinCoreApi, BlockHash, Transaction, TransactionExt}; -use futures::channel::mpsc::Sender; -use futures::{SinkExt, StreamExt}; -use log::{error, info, trace}; +use futures::{channel::mpsc::Sender, SinkExt, StreamExt}; +use log::*; use runtime::{ pallets::issue::{CancelIssueEvent, ExecuteIssueEvent, RequestIssueEvent}, - BtcAddress, BtcPublicKey, BtcRelayPallet, H256Le, IssuePallet, PolkaBtcProvider, - PolkaBtcRuntime, UtilFuncs, + substrate_subxt::{Error as SubxtError, ModuleError as SubxtModuleError, RuntimeError as SubxtRuntimeError}, + BtcAddress, BtcPublicKey, BtcRelayPallet, Error as RuntimeError, H256Le, IssuePallet, PolkaBtcProvider, + PolkaBtcRuntime, UtilFuncs, ISSUE_COMPLETED_ERROR, ISSUE_MODULE, }; use sha2::{Digest, Sha256}; use sp_core::H256; -use std::borrow::Borrow; -use std::collections::HashMap; -use std::hash::Hash; -use std::sync::Arc; +use std::{borrow::Borrow, collections::HashMap, hash::Hash, sync::Arc}; use tokio::sync::Mutex; #[derive(Debug, Default)] @@ -63,13 +59,13 @@ where } } - /// Search the reversible map by value. - pub fn contains_value(&self, v: &Q) -> bool + /// Get the key associated with the value + pub fn get_key_for_value(&mut self, v: &Q) -> Option<&K> where V: Borrow, Q: Hash + Eq, { - self.0 .1.contains_key(v) + self.0 .1.get(v) } } @@ -84,9 +80,9 @@ impl IssueRequests { // initialize `issue_set` with currently open issues, and return the block height // from which to start watching the bitcoin chain -async fn initialize_issue_set( - provider: &Arc, - btc_rpc: &Arc, +async fn initialize_issue_set( + provider: &PolkaBtcProvider, + btc_rpc: &B, issue_set: &Arc, ) -> Result { let mut issue_set = issue_set.0.lock().await; @@ -107,17 +103,15 @@ async fn initialize_issue_set( /// execute issue requests on best-effort (i.e. don't retry on error), /// returns `NoIncomingBlocks` if stream ends, otherwise runs forever -pub async fn process_issue_requests( - provider: &Arc, - btc_rpc: &Arc, +pub async fn process_issue_requests( + provider: &PolkaBtcProvider, + btc_rpc: &B, issue_set: &Arc, num_confirmations: u32, ) -> Result<(), Error> { let btc_start_height = initialize_issue_set(provider, btc_rpc, issue_set).await?; - let mut stream = - bitcoin::stream_in_chain_transactions(btc_rpc.clone(), btc_start_height, num_confirmations) - .await; + let mut stream = bitcoin::stream_in_chain_transactions(btc_rpc.clone(), btc_start_height, num_confirmations).await; while let Some(Ok((block_hash, transaction))) = stream.next().await { if let Err(e) = process_transaction_and_execute_issue( @@ -137,9 +131,9 @@ pub async fn process_issue_requests( Err(Error::NoIncomingBlocks) } -pub async fn add_keys_from_past_issue_request( - provider: &Arc, - btc_rpc: &Arc, +pub async fn add_keys_from_past_issue_request( + provider: &PolkaBtcProvider, + btc_rpc: &B, ) -> Result<(), Error> { for (issue_id, request) in provider .get_vault_issue_requests(provider.get_account_id().clone()) @@ -154,9 +148,9 @@ pub async fn add_keys_from_past_issue_request( - provider: &Arc, - btc_rpc: &Arc, +async fn process_transaction_and_execute_issue( + provider: &PolkaBtcProvider, + btc_rpc: &B, issue_set: &Arc, num_confirmations: u32, block_hash: BlockHash, @@ -164,39 +158,67 @@ async fn process_transaction_and_execute_issue Result<(), Error> { let addresses = transaction.extract_output_addresses::(); let mut issue_requests = issue_set.0.lock().await; - if let Some(address) = addresses - .iter() - .find(|&vout| issue_requests.contains_value(vout)) - { + if let Some((issue_id, address)) = addresses.iter().find_map(|address| { + let issue_id = issue_requests.get_key_for_value(address)?; + Some((issue_id.clone(), address.clone())) + }) { + let issue = provider.get_issue_request(issue_id).await?; // tx has output to address - if let Some(issue_id) = issue_requests.remove_value(address) { - info!("Found tx for issue with id {}", issue_id); + match transaction.get_payment_amount_to(address) { + None => { + // this should never happen, so use WARN + warn!( + "Could not extract payment amount for transaction {}", + transaction.txid() + ); + return Ok(()); + } + Some(transferred) => { + let transferred = transferred as u128; + if transferred == issue.amount { + info!("Found tx for issue with id {}", issue_id); + } else { + info!( + "Found tx for issue with id {}. Expected amount = {}, got {}", + issue_id, issue.amount, transferred + ); + } + + if transferred < issue.amount { + // insufficient amount, don't execute + return Ok(()); + } - // at this point we know that the transaction has `num_confirmations` on the bitcoin chain, - // but the relay can introduce a delay, so wait until the relay also confirms the transaction. - provider - .wait_for_block_in_relay( - H256Le::from_bytes_le(&block_hash.to_vec()), - num_confirmations, - ) - .await?; + issue_requests.remove_value(&address); - // found tx, submit proof - let txid = transaction.txid(); - let raw_tx = btc_rpc.get_raw_tx_for(&txid, &block_hash).await?; - let proof = btc_rpc.get_proof_for(txid.clone(), &block_hash).await?; + // at this point we know that the transaction has `num_confirmations` on the bitcoin chain, + // but the relay can introduce a delay, so wait until the relay also confirms the transaction. + provider + .wait_for_block_in_relay(H256Le::from_bytes_le(&block_hash.to_vec()), num_confirmations) + .await?; - info!("Executing issue with id {}", issue_id); + // found tx, submit proof + let txid = transaction.txid(); + let raw_tx = btc_rpc.get_raw_tx_for(&txid, &block_hash).await?; + let proof = btc_rpc.get_proof_for(txid.clone(), &block_hash).await?; - // this will error if someone else executes the issue first - provider - .execute_issue( - issue_id, - H256Le::from_bytes_le(&txid.as_hash()), - proof, - raw_tx, - ) - .await?; + info!("Executing issue with id {}", issue_id); + match provider + .execute_issue(issue_id, H256Le::from_bytes_le(&txid.as_hash()), proof, raw_tx) + .await + { + Ok(_) => (), + Err(RuntimeError::XtError(SubxtError::Runtime(SubxtRuntimeError::Module(SubxtModuleError { + ref module, + ref error, + })))) + if module == ISSUE_MODULE && error == ISSUE_COMPLETED_ERROR => + { + info!("Issue {} has already been completed", issue_id); + } + Err(err) => return Err(err.into()), + }; + } } } @@ -205,8 +227,8 @@ async fn process_transaction_and_execute_issue( - btc_rpc: &Arc, +async fn add_new_deposit_key( + btc_rpc: &B, secure_id: H256, public_key: BtcPublicKey, ) -> Result<(), Error> { @@ -229,9 +251,9 @@ async fn add_new_deposit_key( /// * `provider` - the parachain RPC handle /// * `event_channel` - the channel over which to signal events /// * `issue_set` - all issue ids observed since vault started -pub async fn listen_for_issue_requests( - provider: Arc, - btc_rpc: Arc, +pub async fn listen_for_issue_requests( + provider: PolkaBtcProvider, + btc_rpc: B, event_channel: Sender, issue_set: Arc, ) -> Result<(), runtime::Error> { @@ -248,14 +270,8 @@ pub async fn listen_for_issue_requests, + provider: PolkaBtcProvider, event_channel: Sender, issue_set: Arc, ) -> Result<(), runtime::Error> { @@ -295,10 +311,7 @@ pub async fn listen_for_issue_executes( info!("Received execute issue event: {:?}", event); // try to send the event, but ignore the returned result since // the only way it can fail is if the channel is closed - let _ = event_channel - .clone() - .send(RequestEvent::Executed(event.issue_id)) - .await; + let _ = event_channel.clone().send(RequestEvent::Executed(event.issue_id)).await; } trace!("issue #{} executed, no longer watching", event.issue_id); @@ -316,7 +329,7 @@ pub async fn listen_for_issue_executes( /// * `provider` - the parachain RPC handle /// * `issue_set` - all issue ids observed since vault started pub async fn listen_for_issue_cancels( - provider: Arc, + provider: PolkaBtcProvider, issue_set: Arc, ) -> Result<(), runtime::Error> { let issue_set = &issue_set; diff --git a/vault/src/lib.rs b/vault/src/lib.rs index b92589105..db6b2d360 100644 --- a/vault/src/lib.rs +++ b/vault/src/lib.rs @@ -1,481 +1,44 @@ #![recursion_limit = "256"] -mod api; mod cancellation; mod collateral; mod constants; mod error; mod execution; mod faucet; +mod http; mod issue; mod redeem; mod refund; mod replace; +mod system; -use crate::collateral::lock_required_collateral; -use crate::{constants::*, faucet::*, refund::*}; -use bitcoin::BitcoinCoreApi; -use clap::Clap; -use core::str::FromStr; -use futures::channel::mpsc; -use futures::SinkExt; -use jsonrpc_core_client::{transports::http as jsonrpc_http, TypedClient}; use log::*; -use runtime::{ - pallets::sla::UpdateVaultSLAEvent, AccountId, BtcRelayPallet, Error as RuntimeError, - PolkaBtcHeader, PolkaBtcProvider, PolkaBtcRuntime, UtilFuncs, VaultRegistryPallet, - PLANCK_PER_DOT, TX_FEES, -}; -use std::sync::Arc; -use std::time::Duration; -use tokio::time::delay_for; +use runtime::{PolkaBtcProvider, VaultRegistryPallet}; pub use crate::error::Error; - pub mod service { - pub use crate::cancellation::CancellationScheduler; - pub use crate::cancellation::IssueCanceller; - pub use crate::cancellation::ReplaceCanceller; - pub use crate::collateral::maintain_collateralization_rate; - pub use crate::execution::execute_open_issue_requests; - pub use crate::execution::execute_open_requests; - pub use crate::issue::listen_for_issue_cancels; - pub use crate::issue::listen_for_issue_executes; - pub use crate::issue::listen_for_issue_requests; - pub use crate::redeem::listen_for_redeem_requests; - pub use crate::refund::listen_for_refund_requests; - pub use crate::replace::listen_for_accept_replace; - pub use crate::replace::listen_for_auction_replace; - pub use crate::replace::listen_for_execute_replace; - pub use crate::replace::listen_for_replace_requests; - pub use crate::replace::monitor_collateral_of_vaults; -} -pub use crate::cancellation::RequestEvent; -pub use crate::issue::IssueRequests; -use service::*; - -#[derive(Debug, Copy, Clone)] -pub struct BitcoinNetwork(pub bitcoin::Network); - -impl FromStr for BitcoinNetwork { - type Err = Error; - fn from_str(s: &str) -> Result { - match s { - "mainnet" => Ok(BitcoinNetwork(bitcoin::Network::Bitcoin)), - "testnet" => Ok(BitcoinNetwork(bitcoin::Network::Testnet)), - "regtest" => Ok(BitcoinNetwork(bitcoin::Network::Regtest)), - _ => Err(Error::InvalidBitcoinNetwork), - } - } -} - -/// The Vault client intermediates between Bitcoin Core -/// and the PolkaBTC Parachain. -#[derive(Clap, Debug, Clone)] -#[clap(version = "0.1", author = "Interlay ")] -pub struct Opts { - /// Parachain URL, can be over WebSockets or HTTP. - #[clap(long, default_value = "ws://127.0.0.1:9944")] - pub polka_btc_url: String, - - /// Address to listen on for JSON-RPC requests. - #[clap(long, default_value = "[::0]:3031")] - pub http_addr: String, - - /// Comma separated list of allowed origins. - #[clap(long, default_value = "*")] - pub rpc_cors_domain: String, - - /// Automatically register the vault with the given amount of collateral and a newly generated address. - #[clap(long)] - pub auto_register_with_collateral: Option, - - /// Automatically register the vault with the collateral received from the faucet and a newly generated address. - /// The parameter is the URL of the faucet - #[clap(long)] - pub auto_register_with_faucet_url: Option, - - /// Opt out of auctioning under-collateralized vaults. - #[clap(long)] - pub no_auto_auction: bool, - - /// Opt out of participation in replace requests. - #[clap(long)] - pub no_auto_replace: bool, - - /// Don't check the collateralization rate at startup. - #[clap(long)] - pub no_startup_collateral_increase: bool, - - /// Don't try to execute issues. - #[clap(long)] - pub no_issue_execution: bool, - - /// Don't run the RPC API. - #[clap(long)] - pub no_api: bool, - - /// Maximum total collateral to keep the vault securely collateralized. - #[clap(long, default_value = "1000000")] - pub max_collateral: u128, - - /// Timeout in milliseconds to repeat collateralization checks. - #[clap(long, default_value = "5000")] - pub collateral_timeout_ms: u64, - - /// How many bitcoin confirmations to wait for. If not specified, the - /// parachain settings will be used (recommended). - #[clap(long)] - pub btc_confirmations: Option, - - /// keyring / keyfile options. - #[clap(flatten)] - pub account_info: runtime::cli::ProviderUserOpts, - - /// Connection settings for Bitcoin Core. - #[clap(flatten)] - pub bitcoin: bitcoin::cli::BitcoinOpts, - - /// Bitcoin network type for address encoding. - #[clap(long, default_value = "regtest")] - pub network: BitcoinNetwork, -} - -async fn generate_btc_key_and_register( - vault_id: AccountId, - collateral: u128, - arc_provider: Arc, - btc_rpc: Arc, -) -> Result<(), Error> { - match arc_provider.clone().get_vault(vault_id.clone()).await { - Ok(_) => info!("Not registering vault -- already registered"), - Err(RuntimeError::VaultNotFound) => { - let public_key = btc_rpc.get_new_public_key().await?; - arc_provider - .clone() - .register_vault(collateral, public_key) - .await?; - info!("Automatically registered vault"); - } - Err(err) => return Err(err.into()), + pub use crate::{ + cancellation::{CancellationScheduler, IssueCanceller, ReplaceCanceller}, + collateral::maintain_collateralization_rate, + execution::{execute_open_issue_requests, execute_open_requests}, + issue::{listen_for_issue_cancels, listen_for_issue_executes, listen_for_issue_requests}, + redeem::listen_for_redeem_requests, + refund::listen_for_refund_requests, + replace::{ + listen_for_accept_replace, listen_for_auction_replace, listen_for_execute_replace, + listen_for_replace_requests, monitor_collateral_of_vaults, + }, }; - Ok(()) } +pub use crate::{ + cancellation::RequestEvent, + issue::IssueRequests, + system::{VaultService, VaultServiceConfig}, +}; -async fn lock_additional_collateral( - api: &Arc, - amount: u128, -) -> Result<(), Error> { +pub(crate) async fn lock_additional_collateral(api: &PolkaBtcProvider, amount: u128) -> Result<(), Error> { let result = api.lock_additional_collateral(amount).await; - info!( - "Locking additional collateral; amount {}: {:?}", - amount, result - ); + info!("Locking additional collateral; amount {}: {:?}", amount, result); Ok(result?) } - -pub async fn start( - opts: Opts, - arc_provider: Arc, - btc_rpc: Arc, -) -> Result<(), Error> { - let vault_id = arc_provider.clone().get_account_id().clone(); - - let num_confirmations = match opts.btc_confirmations { - Some(x) => x, - None => { - arc_provider - .clone() - .clone() - .get_bitcoin_confirmations() - .await? - } - }; - info!("Using {} bitcoin confirmations", num_confirmations); - - if let Some(collateral) = opts.auto_register_with_collateral { - generate_btc_key_and_register( - vault_id.clone(), - collateral, - arc_provider.clone(), - btc_rpc.clone(), - ) - .await? - } - - if let Some(faucet_url) = opts.auto_register_with_faucet_url { - let connection = jsonrpc_http::connect::(&faucet_url).await?; - - // Receive user allowance from faucet - match get_funding(connection.clone(), vault_id.clone()).await { - Ok(_) => { - let user_allowance_in_dot: u128 = - get_faucet_allowance(connection.clone(), "user_allowance").await?; - let registration_collateral = user_allowance_in_dot - .checked_mul(PLANCK_PER_DOT) - .ok_or(Error::MathError)? - .checked_sub(TX_FEES) - .ok_or(Error::MathError)?; - generate_btc_key_and_register( - vault_id.clone(), - registration_collateral, - arc_provider.clone(), - btc_rpc.clone(), - ) - .await?; - } - Err(e) => error!("Faucet error: {}", e.to_string()), - } - - // Receive vault allowance from faucet - match get_funding(connection.clone(), vault_id.clone()).await { - Ok(_) => { - let vault_allowance_in_dot: u128 = - get_faucet_allowance(connection.clone(), "vault_allowance").await?; - let operational_collateral = vault_allowance_in_dot - .checked_mul(PLANCK_PER_DOT) - .ok_or(Error::MathError)? - .checked_sub(TX_FEES) - .ok_or(Error::MathError)?; - lock_additional_collateral(&arc_provider.clone(), operational_collateral).await?; - } - Err(e) => error!("Faucet error: {}", e.to_string()), - } - } - - if let Ok(vault) = arc_provider.clone().get_vault(vault_id.clone()).await { - if !btc_rpc - .wallet_has_public_key(vault.wallet.public_key) - .await? - { - return Err(bitcoin::Error::MissingPublicKey.into()); - } - } - - issue::add_keys_from_past_issue_request(&arc_provider, &btc_rpc).await?; - - let open_request_executor = - execute_open_requests(arc_provider.clone(), btc_rpc.clone(), num_confirmations); - tokio::spawn(async move { - info!("Checking for open replace/redeem requests..."); - match open_request_executor.await { - Ok(_) => info!("Done processing open replace/redeem requests"), - Err(e) => error!("Failed to process open replace/redeem requests: {}", e), - } - }); - - if !opts.no_startup_collateral_increase { - // check if the vault is registered - match lock_required_collateral(arc_provider.clone(), vault_id.clone(), opts.max_collateral) - .await - { - Err(Error::RuntimeError(runtime::Error::VaultNotFound)) => {} // not registered - Err(e) => error!("Failed to lock required additional collateral: {}", e), - _ => {} // collateral level now OK - }; - } - - let collateral_maintainer = - maintain_collateralization_rate(arc_provider.clone(), opts.max_collateral); - - // wait for a new block to arrive, to prevent processing an event that potentially - // has been processed already prior to restarting - info!("Waiting for new block..."); - let startup_height = arc_provider.get_current_chain_height().await?; - while startup_height == arc_provider.get_current_chain_height().await? { - delay_for(CHAIN_HEIGHT_POLLING_INTERVAL).await; - } - info!("Starting to listen for events..."); - - let (issue_block_tx, issue_block_rx) = mpsc::channel::(16); - let (replace_block_tx, replace_block_rx) = mpsc::channel::(16); - let block_listener = arc_provider.clone(); - - // Issue handling - let issue_set = Arc::new(IssueRequests::new()); - let (issue_event_tx, issue_event_rx) = mpsc::channel::(32); - let mut issue_cancellation_scheduler = - CancellationScheduler::new(arc_provider.clone(), vault_id.clone()); - let issue_request_listener = listen_for_issue_requests( - arc_provider.clone(), - btc_rpc.clone(), - issue_event_tx.clone(), - issue_set.clone(), - ); - let issue_execute_listener = listen_for_issue_executes( - arc_provider.clone(), - issue_event_tx.clone(), - issue_set.clone(), - ); - let issue_cancel_listener = listen_for_issue_cancels(arc_provider.clone(), issue_set.clone()); - let issue_executor = execute_open_issue_requests( - arc_provider.clone(), - btc_rpc.clone(), - issue_set.clone(), - num_confirmations, - ); - - // replace handling - let (replace_event_tx, replace_event_rx) = mpsc::channel::(16); - let mut replace_cancellation_scheduler = - CancellationScheduler::new(arc_provider.clone(), vault_id.clone()); - let request_replace_listener = listen_for_replace_requests( - arc_provider.clone(), - btc_rpc.clone(), - replace_event_tx.clone(), - !opts.no_auto_replace, - ); - let accept_replace_listener = - listen_for_accept_replace(arc_provider.clone(), btc_rpc.clone(), num_confirmations); - let execute_replace_listener = - listen_for_execute_replace(arc_provider.clone(), replace_event_tx.clone()); - let auction_replace_listener = - listen_for_auction_replace(arc_provider.clone(), btc_rpc.clone(), num_confirmations); - let third_party_collateral_listener = monitor_collateral_of_vaults( - arc_provider.clone(), - btc_rpc.clone(), - replace_event_tx.clone(), - Duration::from_millis(opts.collateral_timeout_ms), - ); - - // redeem handling - let redeem_listener = - listen_for_redeem_requests(arc_provider.clone(), btc_rpc.clone(), num_confirmations); - - // refund handling - let refund_listener = - listen_for_refund_requests(arc_provider.clone(), btc_rpc.clone(), num_confirmations); - - let api_listener = if opts.no_api { - None - } else { - Some(api::start( - arc_provider.clone(), - btc_rpc.clone(), - opts.http_addr.parse()?, - opts.rpc_cors_domain, - )) - }; - - // misc copies of variables to move into spawn closures - let no_auto_auction = opts.no_auto_auction; - let no_issue_execution = opts.no_issue_execution; - let sla_event_provider = arc_provider.clone(); - - // starts all the tasks - let result = tokio::try_join!( - tokio::spawn(async move { - if let Some(api_listener) = api_listener { - api_listener.await; - } - }), - tokio::spawn(async move { - arc_provider - .on_event_error(|e| error!("Received error event: {}", e)) - .await - .unwrap(); - }), - tokio::spawn(async move { - let vault_id = sla_event_provider.get_account_id(); - sla_event_provider - .on_event::, _, _, _>( - |event| async move { - if &event.vault_id == vault_id { - info!("Received event: new total SLA score = {:?}", event.new_sla); - } - }, - |err| error!("Error (UpdateVaultSLAEvent): {}", err.to_string()), - ) - .await - .unwrap(); - }), - tokio::spawn(async move { - collateral_maintainer.await.unwrap(); - }), - tokio::spawn(async move { - let issue_block_tx = &issue_block_tx; - let replace_block_tx = &replace_block_tx; - - block_listener - .clone() - .on_block(move |header| async move { - issue_block_tx - .clone() - .send(header.clone()) - .await - .map_err(|_| RuntimeError::ChannelClosed)?; - replace_block_tx - .clone() - .send(header.clone()) - .await - .map_err(|_| RuntimeError::ChannelClosed)?; - Ok(()) - }) - .await - .unwrap(); - }), - tokio::spawn(async move { - issue_request_listener.await.unwrap(); - }), - tokio::spawn(async move { - issue_execute_listener.await.unwrap(); - }), - tokio::spawn(async move { - issue_cancellation_scheduler - .handle_cancellation::(issue_block_rx, issue_event_rx) - .await - .unwrap(); - }), - tokio::spawn(async move { - issue_cancel_listener.await.unwrap(); - }), - tokio::spawn(async move { - if !no_issue_execution { - issue_executor.await.unwrap(); - } - }), - // redeem handling - tokio::spawn(async move { - redeem_listener.await.unwrap(); - }), - // refund handling - tokio::spawn(async move { - refund_listener.await.unwrap(); - }), - // replace handling - tokio::spawn(async move { - request_replace_listener.await.unwrap(); - }), - tokio::spawn(async move { - accept_replace_listener.await.unwrap(); - }), - tokio::spawn(async move { - auction_replace_listener.await.unwrap(); - }), - tokio::spawn(async move { - execute_replace_listener.await.unwrap(); - }), - tokio::spawn(async move { - if !no_auto_auction { - third_party_collateral_listener.await.unwrap(); - } - }), - tokio::spawn(async move { - replace_cancellation_scheduler - .handle_cancellation::(replace_block_rx, replace_event_rx) - .await - .unwrap(); - }), - ); - match result { - Ok(_) => { - println!("Done"); - } - Err(err) => { - println!("Error: {}", err); - std::process::exit(1); - } - }; - - Ok(()) -} diff --git a/vault/src/main.rs b/vault/src/main.rs index 052759cdf..82e88c7d3 100644 --- a/vault/src/main.rs +++ b/vault/src/main.rs @@ -1,34 +1,156 @@ use bitcoin::{BitcoinCore, BitcoinCoreApi}; use clap::Clap; use log::*; -use runtime::substrate_subxt::PairSigner; -use runtime::{PolkaBtcProvider, PolkaBtcRuntime}; -use std::sync::Arc; -use vault::{start, Error, Opts}; +use runtime::{substrate_subxt::PairSigner, ConnectionManager, PolkaBtcRuntime}; +use std::{str::FromStr, sync::Arc, time::Duration}; -#[tokio::main] -async fn main() -> Result<(), Error> { - env_logger::init(); +use vault::{Error, VaultService, VaultServiceConfig}; + +#[derive(Debug, Copy, Clone)] +pub struct BitcoinNetwork(pub bitcoin::Network); + +impl FromStr for BitcoinNetwork { + type Err = Error; + fn from_str(s: &str) -> Result { + match s { + "mainnet" => Ok(BitcoinNetwork(bitcoin::Network::Bitcoin)), + "testnet" => Ok(BitcoinNetwork(bitcoin::Network::Testnet)), + "regtest" => Ok(BitcoinNetwork(bitcoin::Network::Regtest)), + _ => Err(Error::InvalidBitcoinNetwork), + } + } +} + +/// The Vault client intermediates between Bitcoin Core +/// and the PolkaBTC Parachain. +#[derive(Clap, Debug, Clone)] +#[clap(version = "0.2", author = "Interlay ")] +pub struct Opts { + /// Keyring / keyfile options. + #[clap(flatten)] + pub account_info: runtime::cli::ProviderUserOpts, + + /// Connection settings for the BTC-Parachain. + #[clap(flatten)] + pub parachain: runtime::cli::ConnectionOpts, + + /// Connection settings for Bitcoin Core. + #[clap(flatten)] + pub bitcoin: bitcoin::cli::BitcoinOpts, + + /// Address to listen on for JSON-RPC requests. + #[clap(long, default_value = "[::0]:3031")] + pub http_addr: String, + + /// Comma separated list of allowed origins. + #[clap(long, default_value = "*")] + pub rpc_cors_domain: String, + + /// Automatically register the vault with the given amount of collateral and a newly generated address. + #[clap(long)] + pub auto_register_with_collateral: Option, + + /// Automatically register the vault with the collateral received from the faucet and a newly generated address. + /// The parameter is the URL of the faucet + #[clap(long, conflicts_with("auto-register-with-collateral"))] + pub auto_register_with_faucet_url: Option, + + /// Opt out of auctioning under-collateralized vaults. + #[clap(long)] + pub no_auto_auction: bool, + + /// Opt out of participation in replace requests. + #[clap(long)] + pub no_auto_replace: bool, + + /// Don't check the collateralization rate at startup. + #[clap(long)] + pub no_startup_collateral_increase: bool, + + /// Don't try to execute issues. + #[clap(long)] + pub no_issue_execution: bool, + + /// Don't run the RPC API. + #[clap(long)] + pub no_api: bool, + + /// Maximum total collateral to keep the vault securely collateralized. + #[clap(long, default_value = "1000000")] + pub max_collateral: u128, + + /// Timeout in milliseconds to repeat collateralization checks. + #[clap(long, default_value = "5000")] + pub collateral_timeout_ms: u64, + + /// How many bitcoin confirmations to wait for. If not specified, the + /// parachain settings will be used (recommended). + #[clap(long)] + pub btc_confirmations: Option, + + /// Bitcoin network type for address encoding. + #[clap(long, default_value = "regtest")] + pub network: BitcoinNetwork, +} + +async fn start() -> Result<(), Error> { + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, log::LevelFilter::Info.as_str()), + ); let opts: Opts = Opts::parse(); - let intact_opts = opts.clone(); info!("Command line arguments: {:?}", opts.clone()); let (pair, wallet) = opts.account_info.get_key_pair()?; let signer = PairSigner::::new(pair); - let provider = PolkaBtcProvider::from_url(opts.polka_btc_url.clone(), signer).await?; - let arc_provider = Arc::new(provider.clone()); - let btc_rpc = Arc::new(BitcoinCore::new( - opts.bitcoin.new_client(Some(&wallet))?, + let bitcoin_core = BitcoinCore::new_with_retry( + Arc::new(opts.bitcoin.new_client(Some(&wallet))?), opts.network.0, - )); + Duration::from_millis(opts.bitcoin.bitcoin_connection_timeout_ms), + ) + .await?; // load wallet. Exit on failure, since without wallet we can't do a lot - btc_rpc + bitcoin_core .create_wallet(&wallet) .await .map_err(|e| Error::WalletInitializationFailure(e))?; - start(intact_opts, arc_provider, btc_rpc).await + // only open connection to parachain after bitcoind sync to prevent timeout + ConnectionManager::<_, _, VaultService>::new( + opts.parachain.polka_btc_url.clone(), + signer.clone(), + VaultServiceConfig { + bitcoin_core, + auto_register_with_collateral: opts.auto_register_with_collateral, + auto_register_with_faucet_url: opts.auto_register_with_faucet_url, + no_startup_collateral_increase: opts.no_startup_collateral_increase, + btc_confirmations: opts.btc_confirmations, + max_collateral: opts.max_collateral, + no_auto_replace: opts.no_auto_replace, + no_auto_auction: opts.no_auto_auction, + no_issue_execution: opts.no_issue_execution, + collateral_timeout: Duration::from_millis(opts.collateral_timeout_ms), + http_addr: opts.http_addr.parse()?, + rpc_cors_domain: opts.rpc_cors_domain, + }, + opts.parachain.into(), + tokio::runtime::Handle::current(), + ) + .start() + .await?; + + Ok(()) +} + +#[tokio::main] +async fn main() { + let exit_code = if let Err(err) = start().await { + eprintln!("Error: {}", err); + 1 + } else { + 0 + }; + std::process::exit(exit_code); } diff --git a/vault/src/redeem.rs b/vault/src/redeem.rs index 7db405bf9..86a113dba 100644 --- a/vault/src/redeem.rs +++ b/vault/src/redeem.rs @@ -2,7 +2,6 @@ use crate::execution::*; use bitcoin::BitcoinCoreApi; use log::{error, info}; use runtime::{pallets::redeem::RequestRedeemEvent, PolkaBtcProvider, PolkaBtcRuntime, UtilFuncs}; -use std::sync::Arc; /// Listen for RequestRedeemEvent directed at this vault; upon reception, transfer /// bitcoin and call execute_redeem @@ -13,9 +12,9 @@ use std::sync::Arc; /// * `btc_rpc` - the bitcoin RPC handle /// * `network` - network the bitcoin network used (i.e. regtest/testnet/mainnet) /// * `num_confirmations` - the number of bitcoin confirmation to await -pub async fn listen_for_redeem_requests( - provider: Arc, - btc_rpc: Arc, +pub async fn listen_for_redeem_requests( + provider: PolkaBtcProvider, + btc_rpc: B, num_confirmations: u32, ) -> Result<(), runtime::Error> { provider @@ -35,9 +34,7 @@ pub async fn listen_for_redeem_requests info!( diff --git a/vault/src/refund.rs b/vault/src/refund.rs index 92331f426..ebdf25d2d 100644 --- a/vault/src/refund.rs +++ b/vault/src/refund.rs @@ -2,7 +2,6 @@ use crate::execution::*; use bitcoin::BitcoinCoreApi; use log::{error, info}; use runtime::{pallets::refund::RequestRefundEvent, PolkaBtcProvider, PolkaBtcRuntime, UtilFuncs}; -use std::sync::Arc; /// Listen for RequestRefundEvent directed at this vault; upon reception, transfer /// bitcoin and call execute_refund @@ -13,9 +12,9 @@ use std::sync::Arc; /// * `btc_rpc` - the bitcoin RPC handle /// * `network` - network the bitcoin network used (i.e. regtest/testnet/mainnet) /// * `num_confirmations` - the number of bitcoin confirmation to await -pub async fn listen_for_refund_requests( - provider: Arc, - btc_rpc: Arc, +pub async fn listen_for_refund_requests( + provider: PolkaBtcProvider, + btc_rpc: B, num_confirmations: u32, ) -> Result<(), runtime::Error> { provider @@ -35,9 +34,7 @@ pub async fn listen_for_refund_requests info!( diff --git a/vault/src/replace.rs b/vault/src/replace.rs index d6a51a52e..753a4f215 100644 --- a/vault/src/replace.rs +++ b/vault/src/replace.rs @@ -1,19 +1,11 @@ -use crate::cancellation::RequestEvent; -use crate::error::Error; -use crate::execution::Request; +use crate::{cancellation::RequestEvent, error::Error, execution::Request}; use bitcoin::BitcoinCoreApi; -use futures::channel::mpsc::Sender; -use futures::SinkExt; +use futures::{channel::mpsc::Sender, SinkExt}; use log::*; use runtime::{ - pallets::replace::{ - AcceptReplaceEvent, AuctionReplaceEvent, ExecuteReplaceEvent, RequestReplaceEvent, - }, - pallets::vault_registry::VaultStatus, - DotBalancesPallet, PolkaBtcProvider, PolkaBtcRuntime, PolkaBtcVault, ReplacePallet, UtilFuncs, - VaultRegistryPallet, + pallets::replace::{AcceptReplaceEvent, AuctionReplaceEvent, ExecuteReplaceEvent, RequestReplaceEvent}, + DotBalancesPallet, PolkaBtcProvider, PolkaBtcRuntime, PolkaBtcVault, ReplacePallet, UtilFuncs, VaultRegistryPallet, }; -use std::sync::Arc; use std::time::Duration; use tokio::time::delay_for; @@ -25,9 +17,9 @@ use tokio::time::delay_for; /// * `provider` - the parachain RPC handle /// * `btc_rpc` - the bitcoin RPC handle /// * `num_confirmations` - the number of bitcoin confirmation to await -pub async fn listen_for_accept_replace( - provider: Arc, - btc_rpc: Arc, +pub async fn listen_for_accept_replace( + provider: PolkaBtcProvider, + btc_rpc: B, num_confirmations: u32, ) -> Result<(), runtime::Error> { let provider = &provider; @@ -48,9 +40,7 @@ pub async fn listen_for_accept_replace info!( @@ -78,9 +68,9 @@ pub async fn listen_for_accept_replace( - provider: Arc, - btc_rpc: Arc, +pub async fn listen_for_auction_replace( + provider: PolkaBtcProvider, + btc_rpc: B, num_confirmations: u32, ) -> Result<(), runtime::Error> { let provider = &provider; @@ -101,9 +91,7 @@ pub async fn listen_for_auction_replace info!( @@ -130,9 +118,9 @@ pub async fn listen_for_auction_replace( - provider: Arc, - btc_rpc: Arc, +pub async fn listen_for_replace_requests( + provider: PolkaBtcProvider, + btc_rpc: B, event_channel: Sender, accept_replace_requests: bool, ) -> Result<(), runtime::Error> { @@ -176,16 +164,14 @@ pub async fn listen_for_replace_requests( /// Attempts to accept a replace request. Does not retry RPC calls upon /// failure, since nothing is at stake at this point pub async fn handle_replace_request< - B: BitcoinCoreApi, + B: BitcoinCoreApi + Clone, P: DotBalancesPallet + ReplacePallet + VaultRegistryPallet, >( - provider: Arc

, - btc_rpc: Arc, + provider: P, + btc_rpc: B, event: &RequestReplaceEvent, ) -> Result<(), Error> { - let required_collateral = provider - .get_required_collateral_for_polkabtc(event.amount_btc) - .await?; + let required_collateral = provider.get_required_collateral_for_polkabtc(event.amount_btc).await?; let free_balance = provider.get_free_dot_balance().await?; @@ -193,11 +179,7 @@ pub async fn handle_replace_request< Err(Error::InsufficientFunds) } else { Ok(provider - .accept_replace( - event.replace_id, - required_collateral, - btc_rpc.get_new_address().await?, - ) + .accept_replace(event.replace_id, required_collateral, btc_rpc.get_new_address().await?) .await?) } } @@ -211,9 +193,9 @@ pub async fn handle_replace_request< /// * `btc_rpc` - the bitcoin RPC handle /// * `num_confirmations` - the number of bitcoin confirmation to await /// * `interval` - interval between checks -pub async fn monitor_collateral_of_vaults( - provider: Arc, - btc_rpc: Arc, +pub async fn monitor_collateral_of_vaults( + provider: PolkaBtcProvider, + btc_rpc: B, mut event_channel: Sender, interval: Duration, ) -> Result<(), runtime::Error> { @@ -222,10 +204,7 @@ pub async fn monitor_collateral_of_vaults( // polling is easier for now loop { if let Err(e) = check_collateral_of_vaults(&provider, &btc_rpc, &mut event_channel).await { - error!( - "Error while monitoring collateral of vaults: {}", - e.to_string() - ); + error!("Error while monitoring collateral of vaults: {}", e.to_string()); } delay_for(interval).await } @@ -235,9 +214,9 @@ pub async fn monitor_collateral_of_vaults( /// # Arguments /// /// * `provider` - the parachain RPC handle -pub async fn check_collateral_of_vaults( - provider: &Arc, - btc_rpc: &Arc, +pub async fn check_collateral_of_vaults( + provider: &PolkaBtcProvider, + btc_rpc: &B, event_channel: &mut Sender, ) -> Result<(), Error> { let vault_id = provider.get_account_id().clone(); @@ -245,7 +224,8 @@ pub async fn check_collateral_of_vaults( .get_all_vaults() .await? .into_iter() - .filter(|vault| vault.id != vault_id && matches!(vault.status, VaultStatus::Active)); + .filter(|vault| vault.id != vault_id); + for vault in vaults { trace!("Checking collateral of {}", vault.id); if provider @@ -253,13 +233,14 @@ pub async fn check_collateral_of_vaults( .await .unwrap_or(false) { - match auction_replace(&provider, &btc_rpc, &vault).await { + match auction_replace(provider, btc_rpc, &vault).await { Ok(_) => { info!("Auction replace for vault {} submitted", vault.id); // try to send the event, but ignore the returned result since // the only way it can fail is if the channel is closed let _ = event_channel.send(RequestEvent::Opened).await; } + Err(Error::InsufficientFunds) => debug!("Not auctioning vault {}", vault.id), Err(e) => error!("Failed to auction vault {}: {}", vault.id, e.to_string()), }; } @@ -267,18 +248,18 @@ pub async fn check_collateral_of_vaults( Ok(()) } -async fn auction_replace< - B: BitcoinCoreApi, - P: DotBalancesPallet + ReplacePallet + VaultRegistryPallet, ->( - provider: &Arc

, - btc_rpc: &Arc, +async fn auction_replace( + provider: &P, + btc_rpc: &B, vault: &PolkaBtcVault, ) -> Result<(), Error> { - let btc_amount = vault.issued_tokens; - let collateral = provider - .get_required_collateral_for_polkabtc(btc_amount) - .await?; + let btc_amount = vault + .issued_tokens + .checked_sub(vault.to_be_redeemed_tokens) + .ok_or(Error::ArithmeticUnderflow)? + .checked_sub(vault.to_be_replaced_tokens) + .ok_or(Error::ArithmeticUnderflow)?; + let collateral = provider.get_required_collateral_for_polkabtc(btc_amount).await?; // don't auction vault if we can't afford to replace it if collateral > provider.get_free_dot_balance().await? { @@ -310,7 +291,7 @@ async fn auction_replace< /// /// * `event_channel` - the channel over which to signal events pub async fn listen_for_execute_replace( - provider: Arc, + provider: PolkaBtcProvider, event_channel: Sender, ) -> Result<(), runtime::Error> { let event_channel = &event_channel; @@ -338,12 +319,12 @@ mod tests { use super::*; use async_trait::async_trait; use bitcoin::{ - Block, BlockHash, Error as BitcoinError, GetBlockResult, LockedTransaction, PartialAddress, + Block, BlockHash, BlockHeader, Error as BitcoinError, GetBlockResult, LockedTransaction, PartialAddress, Transaction, TransactionMetadata, Txid, PUBLIC_KEY_SIZE, }; use runtime::{ - pallets::Core, AccountId, BtcAddress, BtcPublicKey, Error as RuntimeError, H256Le, - PolkaBtcReplaceRequest, PolkaBtcRuntime, PolkaBtcVault, + pallets::Core, AccountId, BtcAddress, BtcPublicKey, Error as RuntimeError, H256Le, PolkaBtcReplaceRequest, + PolkaBtcRuntime, PolkaBtcVault, }; use sp_core::H256; use std::time::Duration; @@ -367,7 +348,7 @@ mod tests { async fn get_block_count(&self) -> Result; async fn get_raw_tx_for(&self, txid: &Txid, block_hash: &BlockHash) -> Result, BitcoinError>; async fn get_proof_for(&self, txid: Txid, block_hash: &BlockHash) -> Result, BitcoinError>; - async fn get_block_hash_for(&self, height: u32) -> Result; + async fn get_block_hash(&self, height: u32) -> Result; async fn is_block_known(&self, block_hash: BlockHash) -> Result; async fn get_new_address(&self) -> Result; async fn get_new_public_key + 'static>(&self) -> Result; @@ -378,9 +359,10 @@ mod tests { ) -> Result<(), BitcoinError>; async fn get_best_block_hash(&self) -> Result; async fn get_block(&self, hash: &BlockHash) -> Result; + async fn get_block_header(&self, hash: &BlockHash) -> Result; async fn get_block_info(&self, hash: &BlockHash) -> Result; async fn get_mempool_transactions<'a>( - self: Arc, + self: &'a Self, ) -> Result> + Send + 'a>, BitcoinError>; async fn wait_for_transaction_metadata( &self, @@ -416,6 +398,13 @@ mod tests { } } + impl Clone for MockBitcoin { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + mockall::mock! { Provider {} @@ -476,12 +465,17 @@ mod tests { } } + impl Clone for MockProvider { + fn clone(&self) -> Self { + // NOTE: expectations dropped + Self::default() + } + } + #[tokio::test] async fn test_handle_auction_replace_with_insufficient_collateral() { let mut bitcoin = MockBitcoin::default(); - bitcoin - .expect_get_new_address() - .returning(|| Ok(BtcAddress::default())); + bitcoin.expect_get_new_address().returning(|| Ok(BtcAddress::default())); let mut provider = MockProvider::default(); provider @@ -491,7 +485,7 @@ mod tests { let vault = PolkaBtcVault::default(); assert_err!( - auction_replace(&Arc::new(provider), &Arc::new(bitcoin), &vault).await, + auction_replace(&provider, &bitcoin, &vault).await, Error::InsufficientFunds ); } @@ -499,9 +493,7 @@ mod tests { #[tokio::test] async fn test_handle_replace_request_with_insufficient_balance() { let mut bitcoin = MockBitcoin::default(); - bitcoin - .expect_get_new_address() - .returning(|| Ok(BtcAddress::default())); + bitcoin.expect_get_new_address().returning(|| Ok(BtcAddress::default())); let mut provider = MockProvider::default(); provider @@ -516,7 +508,7 @@ mod tests { griefing_collateral: Default::default(), }; assert_err!( - handle_replace_request(Arc::new(provider), Arc::new(bitcoin), &event).await, + handle_replace_request(provider, bitcoin, &event).await, Error::InsufficientFunds ); } diff --git a/vault/src/system.rs b/vault/src/system.rs new file mode 100644 index 000000000..b045d821b --- /dev/null +++ b/vault/src/system.rs @@ -0,0 +1,364 @@ +use crate::{ + collateral::lock_required_collateral, constants::*, faucet, http::start_http, issue, service::*, Error, + IssueRequests, RequestEvent, +}; +use async_trait::async_trait; +use bitcoin::{BitcoinCore, BitcoinCoreApi}; +use futures::{channel::mpsc, SinkExt}; +use log::*; +use runtime::{ + on_shutdown, pallets::sla::UpdateVaultSLAEvent, wait_or_shutdown, AccountId, BtcRelayPallet, Error as RuntimeError, + PolkaBtcHeader, PolkaBtcProvider, PolkaBtcRuntime, Service, ShutdownReceiver, UtilFuncs, VaultRegistryPallet, +}; +use std::{net::SocketAddr, sync::Arc, time::Duration}; +use tokio::time::delay_for; + +#[derive(Clone)] +pub struct VaultServiceConfig { + /// the bitcoin RPC handle + pub bitcoin_core: BitcoinCore, + pub auto_register_with_collateral: Option, + pub auto_register_with_faucet_url: Option, + pub http_addr: SocketAddr, + pub rpc_cors_domain: String, + pub no_startup_collateral_increase: bool, + pub btc_confirmations: Option, + pub max_collateral: u128, + pub no_auto_replace: bool, + pub no_auto_auction: bool, + pub no_issue_execution: bool, + pub collateral_timeout: Duration, +} + +pub struct VaultService { + btc_parachain: PolkaBtcProvider, + config: VaultServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, +} + +#[async_trait] +impl Service for VaultService { + async fn start( + btc_parachain: PolkaBtcProvider, + config: VaultServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, + ) -> Result<(), RuntimeError> { + VaultService::new(btc_parachain, config, handle, shutdown) + .run_service() + .await + .map_err(|_| RuntimeError::ChannelClosed) + } +} + +impl VaultService { + fn new( + btc_parachain: PolkaBtcProvider, + config: VaultServiceConfig, + handle: tokio::runtime::Handle, + shutdown: ShutdownReceiver, + ) -> Self { + Self { + btc_parachain, + config, + handle, + shutdown, + } + } + + async fn run_service(&self) -> Result<(), Error> { + let bitcoin_core = self.config.bitcoin_core.clone(); + let handle = self.handle.clone(); + + let vault_id = self.btc_parachain.get_account_id().clone(); + + let num_confirmations = match self.config.btc_confirmations { + Some(x) => x, + None => self.btc_parachain.get_bitcoin_confirmations().await?, + }; + info!("Using {} bitcoin confirmations", num_confirmations); + + if let Some(collateral) = self.config.auto_register_with_collateral { + if !is_registered(&self.btc_parachain, vault_id.clone()).await? { + let public_key = bitcoin_core.get_new_public_key().await?; + self.btc_parachain.register_vault(collateral, public_key).await?; + info!("Automatically registered vault"); + } else { + info!("Not registering vault -- already registered"); + } + } else if let Some(faucet_url) = &self.config.auto_register_with_faucet_url { + if !is_registered(&self.btc_parachain, vault_id.clone()).await? { + faucet::fund_and_register(&self.btc_parachain, &bitcoin_core, faucet_url, vault_id.clone()).await?; + info!("Automatically registered vault"); + } else { + info!("Not registering vault -- already registered"); + } + } + + if let Ok(vault) = self.btc_parachain.get_vault(vault_id.clone()).await { + if !bitcoin_core.wallet_has_public_key(vault.wallet.public_key).await? { + return Err(bitcoin::Error::MissingPublicKey.into()); + } + } + + issue::add_keys_from_past_issue_request(&self.btc_parachain, &bitcoin_core).await?; + + let open_request_executor = + execute_open_requests(self.btc_parachain.clone(), bitcoin_core.clone(), num_confirmations); + handle.spawn(async move { + info!("Checking for open replace/redeem requests..."); + match open_request_executor.await { + Ok(_) => info!("Done processing open replace/redeem requests"), + Err(e) => error!("Failed to process open replace/redeem requests: {}", e), + } + }); + + if !self.config.no_startup_collateral_increase { + // check if the vault is registered + match lock_required_collateral(self.btc_parachain.clone(), vault_id.clone(), self.config.max_collateral) + .await + { + Err(Error::RuntimeError(runtime::Error::VaultNotFound)) => {} // not registered + Err(e) => error!("Failed to lock required additional collateral: {}", e), + _ => {} // collateral level now OK + }; + } + + let close_handle = start_http( + self.btc_parachain.clone(), + bitcoin_core.clone(), + self.config.http_addr, + self.config.rpc_cors_domain.clone(), + self.handle.clone(), + ); + + let http_server = on_shutdown(self.shutdown.clone(), async move { + close_handle.close(); + }); + + let collateral_maintainer = wait_or_shutdown( + self.shutdown.clone(), + maintain_collateralization_rate(self.btc_parachain.clone(), self.config.max_collateral), + ); + + // wait for a new block to arrive, to prevent processing an event that potentially + // has been processed already prior to restarting + info!("Waiting for new block..."); + let startup_height = self.btc_parachain.get_current_chain_height().await?; + while startup_height == self.btc_parachain.get_current_chain_height().await? { + delay_for(CHAIN_HEIGHT_POLLING_INTERVAL).await; + } + info!("Starting to listen for events..."); + + // issue handling + let issue_set = Arc::new(IssueRequests::new()); + let (issue_event_tx, issue_event_rx) = mpsc::channel::(32); + let (issue_block_tx, issue_block_rx) = mpsc::channel::(16); + + let issue_request_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_issue_requests( + self.btc_parachain.clone(), + bitcoin_core.clone(), + issue_event_tx.clone(), + issue_set.clone(), + ), + ); + + let issue_execute_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_issue_executes(self.btc_parachain.clone(), issue_event_tx.clone(), issue_set.clone()), + ); + + let issue_cancel_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_issue_cancels(self.btc_parachain.clone(), issue_set.clone()), + ); + + let mut issue_cancellation_scheduler = CancellationScheduler::new(self.btc_parachain.clone(), vault_id.clone()); + + let issue_block_provider = self.btc_parachain.clone(); + let issue_block_listener = wait_or_shutdown(self.shutdown.clone(), async move { + let issue_block_tx = &issue_block_tx; + issue_block_provider + .on_block(move |header| async move { + issue_block_tx + .clone() + .send(header.clone()) + .await + .map_err(|_| RuntimeError::ChannelClosed)?; + Ok(()) + }) + .await + }); + + let issue_cancel_scheduler = wait_or_shutdown(self.shutdown.clone(), async move { + issue_cancellation_scheduler + .handle_cancellation::(issue_block_rx, issue_event_rx) + .await + }); + + let issue_executor = wait_or_shutdown( + self.shutdown.clone(), + execute_open_issue_requests( + self.btc_parachain.clone(), + bitcoin_core.clone(), + issue_set.clone(), + num_confirmations, + ), + ); + + // replace handling + let (replace_event_tx, replace_event_rx) = mpsc::channel::(16); + let (replace_block_tx, replace_block_rx) = mpsc::channel::(16); + + let request_replace_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_replace_requests( + self.btc_parachain.clone(), + bitcoin_core.clone(), + replace_event_tx.clone(), + !self.config.no_auto_replace, + ), + ); + + let accept_replace_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_accept_replace(self.btc_parachain.clone(), bitcoin_core.clone(), num_confirmations), + ); + + let execute_replace_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_execute_replace(self.btc_parachain.clone(), replace_event_tx.clone()), + ); + + let auction_replace_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_auction_replace(self.btc_parachain.clone(), bitcoin_core.clone(), num_confirmations), + ); + + let mut replace_cancellation_scheduler = + CancellationScheduler::new(self.btc_parachain.clone(), vault_id.clone()); + + let replace_block_provider = self.btc_parachain.clone(); + let replace_block_listener = wait_or_shutdown(self.shutdown.clone(), async move { + let replace_block_tx = &replace_block_tx; + replace_block_provider + .on_block(move |header| async move { + replace_block_tx + .clone() + .send(header.clone()) + .await + .map_err(|_| RuntimeError::ChannelClosed)?; + Ok(()) + }) + .await + }); + + let replace_cancel_scheduler = wait_or_shutdown(self.shutdown.clone(), async move { + replace_cancellation_scheduler + .handle_cancellation::(replace_block_rx, replace_event_rx) + .await + }); + + let third_party_collateral_listener = wait_or_shutdown( + self.shutdown.clone(), + monitor_collateral_of_vaults( + self.btc_parachain.clone(), + bitcoin_core.clone(), + replace_event_tx.clone(), + self.config.collateral_timeout, + ), + ); + + // redeem handling + let redeem_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_redeem_requests(self.btc_parachain.clone(), bitcoin_core.clone(), num_confirmations), + ); + + // refund handling + let refund_listener = wait_or_shutdown( + self.shutdown.clone(), + listen_for_refund_requests(self.btc_parachain.clone(), bitcoin_core.clone(), num_confirmations), + ); + + let sla_provider = self.btc_parachain.clone(); + let sla_listener = wait_or_shutdown(self.shutdown.clone(), async move { + let vault_id = sla_provider.get_account_id(); + sla_provider + .on_event::, _, _, _>( + |event| async move { + if &event.vault_id == vault_id { + info!("Received event: new total SLA score = {:?}", event.new_sla); + } + }, + |err| error!("Error (UpdateVaultSLAEvent): {}", err.to_string()), + ) + .await + }); + + let err_provider = self.btc_parachain.clone(); + let err_listener = wait_or_shutdown(self.shutdown.clone(), async move { + err_provider + .on_event_error(|e| debug!("Received error event: {}", e)) + .await + }); + + // misc copies of variables to move into spawn closures + let no_auto_auction = self.config.no_auto_auction; + let no_issue_execution = self.config.no_issue_execution; + + // starts all the tasks + let _ = tokio::join!( + // runs json-rpc server for incoming requests + handle.spawn(async move { http_server.await }), + // runs error listener to log errors + handle.spawn(async move { err_listener.await }), + // runs sla listener to log events + handle.spawn(async move { sla_listener.await }), + // maintain collateralization rate + handle.spawn(async move { + collateral_maintainer.await; + }), + // issue handling + handle.spawn(async move { issue_request_listener.await }), + handle.spawn(async move { issue_execute_listener.await }), + handle.spawn(async move { issue_cancel_listener.await }), + handle.spawn(async move { issue_block_listener.await }), + handle.spawn(async move { issue_cancel_scheduler.await }), + handle.spawn(async move { + if !no_issue_execution { + let _ = issue_executor.await; + } + }), + // replace handling + handle.spawn(async move { request_replace_listener.await }), + handle.spawn(async move { accept_replace_listener.await }), + handle.spawn(async move { execute_replace_listener.await }), + handle.spawn(async move { auction_replace_listener.await }), + handle.spawn(async move { replace_block_listener.await }), + handle.spawn(async move { replace_cancel_scheduler.await }), + handle.spawn(async move { + if !no_auto_auction { + let _ = third_party_collateral_listener.await; + } + }), + // redeem handling + handle.spawn(async move { redeem_listener.await }), + // refund handling + handle.spawn(async move { refund_listener.await }), + ); + + Ok(()) + } +} + +pub(crate) async fn is_registered(provider: &PolkaBtcProvider, vault_id: AccountId) -> Result { + match provider.get_vault(vault_id).await { + Ok(_) => Ok(true), + Err(RuntimeError::VaultNotFound) => Ok(false), + Err(err) => Err(err.into()), + } +} diff --git a/vault/tests/integration_tests.rs b/vault/tests/integration_tests.rs index 4d836a7e2..8dd589a00 100644 --- a/vault/tests/integration_tests.rs +++ b/vault/tests/integration_tests.rs @@ -1,24 +1,23 @@ +#![cfg(feature = "integration")] + use bitcoin::BitcoinCoreApi; use futures::{ channel::mpsc, future::{join, join3, join4, try_join}, FutureExt, SinkExt, }; -use runtime::integration::*; use runtime::{ + integration::*, pallets::{issue::*, redeem::*, refund::*, replace::*, treasury::*, vault_registry::*}, - BtcAddress, ExchangeRateOraclePallet, FixedPointNumber, FixedU128, IssuePallet, PolkaBtcHeader, - PolkaBtcProvider, PolkaBtcRuntime, RedeemPallet, ReplacePallet, UtilFuncs, VaultRegistryPallet, + BtcAddress, ExchangeRateOraclePallet, FixedPointNumber, FixedU128, IssuePallet, PolkaBtcHeader, PolkaBtcProvider, + PolkaBtcRuntime, RedeemPallet, ReplacePallet, StakedRelayerPallet, UtilFuncs, VaultRegistryPallet, MINIMUM_STAKE, }; -use sp_core::H160; -use sp_core::H256; +use sp_core::{H160, H256}; use sp_keyring::AccountKeyring; -use std::sync::Arc; -use std::time::Duration; -use vault; -use vault::{IssueRequests, RequestEvent}; +use std::{sync::Arc, time::Duration}; +use vault::{self, IssueRequests, RequestEvent}; -const TIMEOUT: Duration = Duration::from_secs(45); +const TIMEOUT: Duration = Duration::from_secs(60); #[tokio::test(threaded_scheduler)] async fn test_redeem_succeeds() { @@ -27,10 +26,12 @@ async fn test_redeem_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100)) @@ -38,33 +39,20 @@ async fn test_redeem_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); - assert_issue( - &user_provider, - &btc_rpc, - vault_provider.get_account_id(), - issue_amount, - ) - .await; + assert_issue(&user_provider, &btc_rpc, vault_provider.get_account_id(), issue_amount).await; test_service( vault::service::listen_for_redeem_requests(vault_provider.clone(), btc_rpc, 0), async { let address = BtcAddress::P2PKH(H160::from_slice(&[2; 20])); let vault_id = vault_provider.clone().get_account_id().clone(); - let redeem_id = user_provider - .request_redeem(10000, address, vault_id) - .await - .unwrap(); + let redeem_id = user_provider.request_redeem(10000, address, vault_id).await.unwrap(); assert_redeem_event(TIMEOUT, user_provider, redeem_id).await; }, ) @@ -78,11 +66,13 @@ async fn test_replace_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let old_vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let new_vault_provider = setup_provider(client.clone(), AccountKeyring::Eve).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -90,20 +80,13 @@ async fn test_replace_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; old_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); new_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -124,29 +107,18 @@ async fn test_replace_succeeds() { replace_event_tx.clone(), true, ), - vault::service::listen_for_accept_replace( - old_vault_provider.clone(), - btc_rpc.clone(), - 0, - ), + vault::service::listen_for_accept_replace(old_vault_provider.clone(), btc_rpc.clone(), 0), ), async { - let replace_id = old_vault_provider - .request_replace(issue_amount, 1000000) - .await - .unwrap(); + let replace_id = old_vault_provider.request_replace(issue_amount, 1000000).await.unwrap(); - assert_event::, _>( - TIMEOUT, - old_vault_provider.clone(), - |e| e.replace_id == replace_id, - ) + assert_event::, _>(TIMEOUT, old_vault_provider.clone(), |e| { + e.replace_id == replace_id + }) .await; - assert_event::, _>( - TIMEOUT, - old_vault_provider.clone(), - |e| e.replace_id == replace_id, - ) + assert_event::, _>(TIMEOUT, old_vault_provider.clone(), |e| { + e.replace_id == replace_id + }) .await; }, ) @@ -160,10 +132,12 @@ async fn test_maintain_collateral_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -171,23 +145,13 @@ async fn test_maintain_collateral_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); - assert_issue( - &user_provider, - &btc_rpc, - vault_provider.get_account_id(), - issue_amount, - ) - .await; + assert_issue(&user_provider, &btc_rpc, vault_provider.get_account_id(), issue_amount).await; test_service( vault::service::maintain_collateralization_rate(vault_provider.clone(), 1000000000), @@ -197,14 +161,10 @@ async fn test_maintain_collateral_succeeds() { .set_exchange_rate_info(FixedU128::saturating_from_rational(110u128, 10000u128)) .await .unwrap(); - assert_event::, _>( - TIMEOUT, - vault_provider.clone(), - |e| { - assert_eq!(e.new_collateral, vault_collateral / 10); - true - }, - ) + assert_event::, _>(TIMEOUT, vault_provider.clone(), |e| { + assert_eq!(e.new_collateral, vault_collateral / 10); + true + }) .await; }, ) @@ -218,11 +178,13 @@ async fn test_withdraw_replace_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let old_vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let new_vault_provider = setup_provider(client.clone(), AccountKeyring::Eve).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -230,20 +192,13 @@ async fn test_withdraw_replace_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; old_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); new_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -259,24 +214,16 @@ async fn test_withdraw_replace_succeeds() { old_vault_provider .request_replace(issue_amount, 1000000) .map(Result::unwrap), - assert_event::, _>( - TIMEOUT, - old_vault_provider.clone(), - |_| true, - ), + assert_event::, _>(TIMEOUT, old_vault_provider.clone(), |_| true), ) .await; assert_eq!(replace_id, event.replace_id); join( - old_vault_provider - .withdraw_replace(replace_id) - .map(Result::unwrap), - assert_event::, _>( - TIMEOUT, - old_vault_provider.clone(), - |e| e.replace_id == replace_id, - ), + old_vault_provider.withdraw_replace(replace_id).map(Result::unwrap), + assert_event::, _>(TIMEOUT, old_vault_provider.clone(), |e| { + e.replace_id == replace_id + }), ) .await; @@ -298,11 +245,13 @@ async fn test_cancellation_succeeds() { let root_provider = setup_provider(client.clone(), AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let old_vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let new_vault_provider = setup_provider(client.clone(), AccountKeyring::Eve).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -310,20 +259,13 @@ async fn test_cancellation_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount * 10).await; + let vault_collateral = get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount * 10).await; old_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); new_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -367,10 +309,7 @@ async fn test_cancellation_succeeds() { let issue_canceller = issue_cancellation_scheduler .handle_cancellation::(issue_block_rx, issue_event_rx); let replace_canceller = replace_cancellation_scheduler - .handle_cancellation::( - replace_block_rx, - replace_event_rx, - ); + .handle_cancellation::(replace_block_rx, replace_event_rx); let block_listener = async move { let issue_block_tx = &issue_block_tx; @@ -414,19 +353,11 @@ async fn test_cancellation_succeeds() { .accept_replace(replace_id, 10000000, address) .await .unwrap(); - replace_event_tx - .clone() - .send(RequestEvent::Opened) - .await - .unwrap(); + replace_event_tx.clone().send(RequestEvent::Opened).await.unwrap(); // setup the to-be-cancelled issue let issue = user_provider - .request_issue( - issue_amount, - new_vault_provider.get_account_id().clone(), - 10000, - ) + .request_issue(issue_amount, new_vault_provider.get_account_id().clone(), 10000) .await .unwrap(); (replace_id, issue.issue_id) @@ -463,11 +394,13 @@ async fn test_auction_replace_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let old_vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let new_vault_provider = setup_provider(client.clone(), AccountKeyring::Eve).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -475,20 +408,13 @@ async fn test_auction_replace_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; old_vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); new_vault_provider - .register_vault( - vault_collateral * 2, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral * 2, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -509,31 +435,23 @@ async fn test_auction_replace_succeeds() { replace_event_tx.clone(), Duration::from_secs(1), ), - vault::service::listen_for_auction_replace( - old_vault_provider.clone(), - btc_rpc.clone(), - 0, - ), + vault::service::listen_for_auction_replace(old_vault_provider.clone(), btc_rpc.clone(), 0), ), async { let old_vault_id = old_vault_provider.get_account_id(); let new_vault_id = new_vault_provider.get_account_id(); join3( - // we need to go from 150% collateral to just below 120%. So increase dot-per-btc by just over 25% + // we need to go from 150% collateral to just below 120%. So increase dot-per-btc by just over 25% relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(126u128, 10000u128)) .map(Result::unwrap), - assert_event::, _>( - TIMEOUT, - old_vault_provider.clone(), - |e| &e.old_vault_id == old_vault_id, - ), - assert_event::, _>( - TIMEOUT, - old_vault_provider.clone(), - |e| &e.new_vault_id == new_vault_id, - ), + assert_event::, _>(TIMEOUT, old_vault_provider.clone(), |e| { + &e.old_vault_id == old_vault_id + }), + assert_event::, _>(TIMEOUT, old_vault_provider.clone(), |e| { + &e.new_vault_id == new_vault_id + }), ) .await; }, @@ -541,8 +459,7 @@ async fn test_auction_replace_succeeds() { .await; // check that the auctioned vault is still able to operate - let vault_collateral = - get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&old_vault_provider, issue_amount).await; old_vault_provider .lock_additional_collateral(vault_collateral) .await @@ -563,27 +480,24 @@ async fn test_refund_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) .await .unwrap(); - let refund_service = - vault::service::listen_for_refund_requests(vault_provider.clone(), btc_rpc.clone(), 0); + let refund_service = vault::service::listen_for_refund_requests(vault_provider.clone(), btc_rpc.clone(), 0); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -614,24 +528,15 @@ async fn test_refund_succeeds() { metadata.proof, metadata.raw_tx, ), - assert_event::, _>( - TIMEOUT, - user_provider.clone(), - |x| x.vault_id == vault_id, - ), - assert_event::, _>( - TIMEOUT, - user_provider.clone(), - |_| true, - ), + assert_event::, _>(TIMEOUT, user_provider.clone(), |x| { + x.vault_id == vault_id + }), + assert_event::, _>(TIMEOUT, user_provider.clone(), |_| true), ) .await; assert_eq!(refund_request.refund_id, refund_execution.refund_id); - assert_eq!( - refund_execution.amount, - (over_payment as f64 * 0.995) as u128 - ); + assert_eq!(refund_execution.amount, (over_payment as f64 * 0.995) as u128); }; test_service(refund_service, fut_user).await; @@ -644,31 +549,26 @@ async fn test_issue_overpayment_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) .await .unwrap(); - let refund_service = - vault::service::listen_for_refund_requests(vault_provider.clone(), btc_rpc.clone(), 0); + let refund_service = vault::service::listen_for_refund_requests(vault_provider.clone(), btc_rpc.clone(), 0); let issue_amount = 100000; let over_payment_factor = 3; - let vault_collateral = get_required_vault_collateral_for_issue( - &vault_provider, - issue_amount * over_payment_factor, - ) - .await; + let vault_collateral = + get_required_vault_collateral_for_issue(&vault_provider, issue_amount * over_payment_factor).await; vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); @@ -722,11 +622,13 @@ async fn test_automatic_issue_execution_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let vault1_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let vault2_provider = setup_provider(client.clone(), AccountKeyring::Eve).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -734,51 +636,32 @@ async fn test_automatic_issue_execution_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&vault1_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&vault1_provider, issue_amount).await; vault1_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); vault2_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); let fut_user = async { let issue = user_provider - .request_issue( - issue_amount, - vault1_provider.get_account_id().clone(), - 10000, - ) + .request_issue(issue_amount, vault1_provider.get_account_id().clone(), 10000) .await .unwrap(); btc_rpc - .send_to_address( - issue.vault_btc_address, - issue.amount_btc as u64, - None, - TIMEOUT, - 0, - ) + .send_to_address(issue.vault_btc_address, issue.amount_btc as u64, None, TIMEOUT, 0) .await .unwrap(); // wait for vault2 to execute this issue let vault_id = vault1_provider.get_account_id().clone(); - assert_event::, _>( - TIMEOUT, - user_provider.clone(), - move |x| x.vault_id == vault_id, - ) + assert_event::, _>(TIMEOUT, user_provider.clone(), move |x| { + x.vault_id == vault_id + }) .await; }; @@ -791,12 +674,7 @@ async fn test_automatic_issue_execution_succeeds() { issue_event_tx.clone(), issue_set.clone(), ), - vault::service::execute_open_issue_requests( - vault2_provider.clone(), - btc_rpc.clone(), - issue_set.clone(), - 0, - ), + vault::service::execute_open_issue_requests(vault2_provider.clone(), btc_rpc.clone(), issue_set.clone(), 0), ); test_service(service, fut_user).await; @@ -809,10 +687,12 @@ async fn test_execute_open_requests_succeeds() { let (client, _tmp_dir) = default_provider_client(AccountKeyring::Alice).await; let relayer_provider = setup_provider(client.clone(), AccountKeyring::Bob).await; + relayer_provider.register_staked_relayer(MINIMUM_STAKE).await.unwrap(); + let vault_provider = setup_provider(client.clone(), AccountKeyring::Charlie).await; let user_provider = setup_provider(client.clone(), AccountKeyring::Dave).await; - let btc_rpc = Arc::new(MockBitcoinCore::new(relayer_provider.clone()).await); + let btc_rpc = MockBitcoinCore::new(relayer_provider.clone()).await; relayer_provider .set_exchange_rate_info(FixedU128::saturating_from_rational(1u128, 100u128)) @@ -820,29 +700,19 @@ async fn test_execute_open_requests_succeeds() { .unwrap(); let issue_amount = 100000; - let vault_collateral = - get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; + let vault_collateral = get_required_vault_collateral_for_issue(&vault_provider, issue_amount).await; vault_provider - .register_vault( - vault_collateral, - btc_rpc.get_new_public_key().await.unwrap(), - ) + .register_vault(vault_collateral, btc_rpc.get_new_public_key().await.unwrap()) .await .unwrap(); - assert_issue( - &user_provider, - &btc_rpc, - vault_provider.get_account_id(), - issue_amount, - ) - .await; + assert_issue(&user_provider, &btc_rpc, vault_provider.get_account_id(), issue_amount).await; let address = BtcAddress::P2PKH(H160::from_slice(&[2; 20])); // place replace requests - let redeem_ids = futures::future::join_all((0..3u128).map(|_| { - user_provider.request_redeem(10000, address, vault_provider.get_account_id().clone()) - })) + let redeem_ids = futures::future::join_all( + (0..3u128).map(|_| user_provider.request_redeem(10000, address, vault_provider.get_account_id().clone())), + ) .await .into_iter() .map(|x| x.unwrap()) @@ -862,8 +732,7 @@ async fn test_execute_open_requests_succeeds() { btc_rpc.send_to_mempool(transaction).await; join3( - vault::service::execute_open_requests(vault_provider, btc_rpc.clone(), 0) - .map(Result::unwrap), + vault::service::execute_open_requests(vault_provider, btc_rpc.clone(), 0).map(Result::unwrap), assert_redeem_event(TIMEOUT, user_provider.clone(), redeem_ids[0]), assert_redeem_event(TIMEOUT, user_provider.clone(), redeem_ids[2]), ) @@ -876,11 +745,8 @@ async fn test_execute_open_requests_succeeds() { async fn assert_redeem_event( duration: Duration, - provider: Arc, + provider: PolkaBtcProvider, redeem_id: H256, ) -> ExecuteRedeemEvent { - assert_event::, _>(duration, provider, |x| { - x.redeem_id == redeem_id - }) - .await + assert_event::, _>(duration, provider, |x| x.redeem_id == redeem_id).await }