diff --git a/.deploy/kubernetes/Chart.yaml b/.deploy/kubernetes/Chart.yaml index 30c2a80d1e..2d4eef5c45 100644 --- a/.deploy/kubernetes/Chart.yaml +++ b/.deploy/kubernetes/Chart.yaml @@ -4,7 +4,7 @@ description: Helm chart for PolkaBTC type: application apiVersion: v2 version: 0.1.1 -appVersion: 2.0.0-rc6 +appVersion: 2.0.0 home: https://interlay.io/ sources: diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 1de565933b..0000000000 --- a/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2fd529f105..24b5b17135 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,55 +1,7 @@ -image: "registry.gitlab.com/interlay/btc-parachain:ci-nightly-2020-10-01" +include: + - project: interlay/tools/ci-scripts + file: /gitlab-templates/rust-base-gitlab-ci.yaml variables: - CARGO_HOME: $CI_PROJECT_DIR/.cargo - # RUSTC_WRAPPER: sccache - # SCCACHE_GCS_RW_MODE: READ_WRITE - DOCKER_HOST: tcp://docker:2375 - DOCKER_TLS_CERTDIR: "" + ARTIFACT_BIN_PATH: btc-parachain -before_script: - - rustc --version - - rustfmt --version - - cargo --version - - SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache & - - sccache -s - -after_script: - - sccache -s - -# Declare stages -stages: - - build # for crates and pallets - - test # for tests in dev - - deploy # for deployment in master - -# pallets and crates -test-pallets-and-crates: - stage: test - script: - - cargo fmt -- --check - - cargo check --all - - cargo build --release --verbose - - cargo test --all --release - cache: - key: cargo - paths: - - .cargo - only: - - merge_requests - -docker-publish: - stage: deploy - image: docker:19.03.12 - services: - - docker:19.03.12-dind - before_script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - script: - - docker pull $CI_REGISTRY_IMAGE:latest || true - - docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest . - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - - docker push $CI_REGISTRY_IMAGE:latest - only: - - master - - dev diff --git a/.vscode/settings.json b/.vscode/settings.json index e153e3a12c..61fb092315 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.formatOnSave": true, "[rust]": { - "editor.defaultFormatter": "rust-lang.rust" + "editor.defaultFormatter": "matklad.rust-analyzer" } } diff --git a/Cargo.lock b/Cargo.lock index 2b257abb9f..6e422a5ce0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,81 +36,47 @@ dependencies = [ [[package]] name = "aes" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7001367fde4c768a19d1029f0a8be5abd9308e1119846d5bd9ad26297b8faf5" +checksum = "dd2bc6d3f370b5666245ff421e231cba4353df936e26986d2918e61a8fd6aef6" dependencies = [ - "aes-soft 0.4.0", - "aesni 0.7.0", + "aes-soft", + "aesni", "block-cipher", ] -[[package]] -name = "aes-ctr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -dependencies = [ - "aes-soft 0.3.3", - "aesni 0.6.0", - "ctr", - "stream-cipher 0.3.2", -] - [[package]] name = "aes-gcm" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f5007801316299f922a6198d1d09a0bae95786815d066d5880d13f7c45ead1" +checksum = "0301c9e9c443494d970a07885e8cf3e587bae8356a1d5abd0999068413f7205f" dependencies = [ "aead", "aes", "block-cipher", "ghash", - "subtle 2.2.3", -] - -[[package]] -name = "aes-soft" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -dependencies = [ - "block-cipher-trait", - "byteorder 1.3.4", - "opaque-debug 0.2.3", + "subtle 2.3.0", ] [[package]] name = "aes-soft" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4925647ee64e5056cf231608957ce7c81e12d6d6e316b9ce1404778cc1d35fa7" +checksum = "63dd91889c49327ad7ef3b500fd1109dbd3c509a03db0d4a9ce413b79f575cb6" dependencies = [ "block-cipher", "byteorder 1.3.4", - "opaque-debug 0.2.3", -] - -[[package]] -name = "aesni" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -dependencies = [ - "block-cipher-trait", - "opaque-debug 0.2.3", - "stream-cipher 0.3.2", + "opaque-debug 0.3.0", ] [[package]] name = "aesni" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050d39b0b7688b3a3254394c3e30a9d66c41dcf9b05b0e2dbdc623f6505d264" +checksum = "0a6fe808308bb07d393e2ea47780043ec47683fcf19cf5efc8ca51c50cc8c68a" dependencies = [ "block-cipher", - "opaque-debug 0.2.3", + "opaque-debug 0.3.0", ] [[package]] @@ -168,9 +134,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" +checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" [[package]] name = "approx" @@ -229,9 +195,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59386c3aa61f4e14c4ddda1a6744c119b4bf278ec9f866d3c20bc5728ee0eb97" +checksum = "55576d57ea9e255e709ea13169645a9427987a6504791cf19b59908d5c922b3d" dependencies = [ "concurrent-queue", "event-listener", @@ -240,63 +206,76 @@ dependencies = [ [[package]] name = "async-executor" -version = "0.1.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f47c78ea98277cb1f5e6f60ba4fc762f5eafe9f6511bc2f7dfd8b75c225650" +checksum = "d373d78ded7d0b3fa8039375718cde0aace493f2e34fb60f51cbf567562ca801" dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell 1.4.1", + "vec-arena", +] + +[[package]] +name = "async-global-executor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fefeb39da249f4c33af940b779a56723ce45809ef5c54dad84bb538d4ffb6d9e" +dependencies = [ + "async-executor", "async-io", "futures-lite", - "multitask", - "parking 1.0.6", - "scoped-tls", - "waker-fn", + "num_cpus", + "once_cell 1.4.1", ] [[package]] name = "async-io" -version = "0.1.11" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae22a338d28c75b53702b66f77979062cb29675db376d99e451af4fa79dedb3" +checksum = "1a027f4b662e59d7070791e33baafd36affe67388965701b50039db5ebb240d2" dependencies = [ - "cfg-if", "concurrent-queue", + "fastrand", "futures-lite", "libc", + "log", + "nb-connect", "once_cell 1.4.1", - "parking 2.0.0", + "parking", "polling", - "socket2", "vec-arena", - "wepoll-sys-stjepang", + "waker-fn", "winapi 0.3.9", ] [[package]] name = "async-mutex" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065de1ccf10280d0d75c2f3a71a970ee1007c85c51aa3e7deee1df100f1dfadb" +checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" dependencies = [ "event-listener", ] [[package]] name = "async-std" -version = "1.6.3" +version = "1.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c8da367da62b8ff2313c406c9ac091c1b31d67a165becdd2de380d846260f7" +checksum = "a9fa76751505e8df1c7a77762f60486f60c71bbd9b8557f4da6ad47d083732ed" dependencies = [ - "async-executor", + "async-global-executor", "async-io", "async-mutex", - "async-task", "blocking", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite", - "futures-timer 3.0.2", + "gloo-timers", "kv-log-macro", "log", "memchr", @@ -310,9 +289,9 @@ dependencies = [ [[package]] name = "async-task" -version = "3.0.0" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" +checksum = "8ab27c1aa62945039e44edaeee1dc23c74cc0c303dd5fe0fb462a184f1c3a518" [[package]] name = "async-tls" @@ -320,7 +299,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df097e3f506bec0e1a24f06bb3c962c228f36671de841ff579cb99f371772634" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "rustls", "webpki", "webpki-roots 0.19.0", @@ -328,9 +307,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687c230d85c0a52504709705fc8a53e4a692b83a2184f03dae73e38e1e93a783" +checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0" dependencies = [ "proc-macro2", "quote", @@ -374,9 +353,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" +checksum = "ec1931848a574faa8f7c71a12ea00453ff5effbb5f51afe7f77d7a48cace6ac1" dependencies = [ "addr2line", "cfg-if", @@ -455,7 +434,7 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.1.1" +version = "0.2.3" dependencies = [ "bitcoin_hashes", "frame-support", @@ -566,22 +545,13 @@ dependencies = [ [[package]] name = "block-cipher" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa136449e765dc7faa244561ccae839c394048667929af599b5d931ebe7b7f10" +checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80" dependencies = [ "generic-array 0.14.4", ] -[[package]] -name = "block-cipher-trait" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -dependencies = [ - "generic-array 0.12.3", -] - [[package]] name = "block-padding" version = "0.1.5" @@ -599,15 +569,16 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "0.5.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5800d29218fea137b0880387e5948694a23c93fcdde157006966693a865c7c" +checksum = "c5aba2c74d15fe950254784fe497a999345606169c2288ccb771b72acdf41241" dependencies = [ "async-channel", + "async-task", "atomic-waker", + "fastrand", "futures-lite", "once_cell 1.4.1", - "waker-fn", ] [[package]] @@ -627,11 +598,16 @@ dependencies = [ [[package]] name = "btc-parachain" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "btc-parachain-runtime", + "frame-benchmarking", + "frame-benchmarking-cli", "jsonrpc-core", "module-exchange-rate-oracle-rpc", + "module-issue-rpc", + "module-redeem-rpc", + "module-replace-rpc", "module-staked-relayers-rpc", "module-vault-registry-rpc", "pallet-transaction-payment-rpc", @@ -663,20 +639,26 @@ dependencies = [ [[package]] name = "btc-parachain-runtime" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "bitcoin", "btc-relay", "collateral", "exchange-rate-oracle", + "frame-benchmarking", "frame-executive", "frame-support", "frame-system", + "frame-system-benchmarking", "frame-system-rpc-runtime-api", "hex", + "hex-literal", "issue", "mocktopus", "module-exchange-rate-oracle-rpc-runtime-api", + "module-issue-rpc-runtime-api", + "module-redeem-rpc-runtime-api", + "module-replace-rpc-runtime-api", "module-staked-relayers-rpc-runtime-api", "module-vault-registry-rpc-runtime-api", "pallet-aura", @@ -714,9 +696,10 @@ dependencies = [ [[package]] name = "btc-relay" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "bitcoin", + "frame-benchmarking", "frame-support", "frame-system", "hex", @@ -793,9 +776,9 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "cc" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" +checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" dependencies = [ "jobserver", ] @@ -817,36 +800,38 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chacha20" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c0f07ac275808b7bf9a39f2fd013aae1498be83632814c8c4e0bd53f2dc58" +checksum = "244fbce0d47e97e8ef2f63b81d5e05882cb518c68531eb33194990d7b7e85845" dependencies = [ - "stream-cipher 0.4.1", + "stream-cipher 0.7.1", "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b0c90556d8e3fec7cf18d84a2f53d27b21288f2fe481b830fadcf809e48205" +checksum = "9bf18d374d66df0c05cdddd528a7db98f78c28e2519b120855c4f84c5027b1f5" dependencies = [ "aead", "chacha20", "poly1305", - "stream-cipher 0.4.1", + "stream-cipher 0.7.1", "zeroize", ] [[package]] name = "chrono" -version = "0.4.15" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ + "libc", "num-integer", "num-traits", "time", + "winapi 0.3.9", ] [[package]] @@ -895,7 +880,7 @@ dependencies = [ [[package]] name = "collateral" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "frame-support", "frame-system", @@ -1067,12 +1052,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "cfg-if", "crossbeam-utils", + "maybe-uninit", ] [[package]] @@ -1146,7 +1131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.4", - "subtle 2.2.3", + "subtle 2.3.0", ] [[package]] @@ -1158,16 +1143,6 @@ dependencies = [ "sct", ] -[[package]] -name = "ctr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -dependencies = [ - "block-cipher-trait", - "stream-cipher 0.3.2", -] - [[package]] name = "cuckoofilter" version = "0.3.2" @@ -1187,7 +1162,7 @@ dependencies = [ "byteorder 1.3.4", "digest 0.8.1", "rand_core 0.5.1", - "subtle 2.2.3", + "subtle 2.3.0", "zeroize", ] @@ -1200,7 +1175,7 @@ dependencies = [ "byteorder 1.3.4", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.2.3", + "subtle 2.3.0", "zeroize", ] @@ -1212,9 +1187,9 @@ checksum = "d4d0e2d24e5ee3b23a01de38eefdcd978907890701f08ffffd4cb457ca4ee8d6" [[package]] name = "derive_more" -version = "0.99.9" +version = "0.99.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298998b1cf6b5b2c8a7b023dfd45821825ce3ba8a8af55c921a0e734e4653f76" +checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" dependencies = [ "proc-macro2", "quote", @@ -1299,18 +1274,18 @@ checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82" [[package]] name = "ed25519" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf038a7b6fd7ef78ad3348b63f3a17550877b0e28f8d68bcc94894d1412158bc" +checksum = "07dfc993ea376e864fe29a4099a61ca0bb994c6d7745a61bf60ddb3d64e05237" dependencies = [ "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d2e93f837d749c16d118e7ddf7a4dfd0ac8f452cf51e46e9348824e5ef6851" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.0.0", "ed25519", @@ -1322,9 +1297,9 @@ dependencies = [ [[package]] name = "either" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" @@ -1341,9 +1316,9 @@ dependencies = [ [[package]] name = "environmental" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" +checksum = "6576a1755ddffd988788025e75bce9e74b018f7cc226198fe931d077911c6d7e" [[package]] name = "erased-serde" @@ -1377,15 +1352,16 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cd41440ae7e4734bbd42302f63eaba892afc93a3912dad84006247f0dedb0e" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "exchange-rate-oracle" -version = "2.0.0-rc6" +version = "0.2.4" dependencies = [ "collateral", + "frame-benchmarking", "frame-support", "frame-system", "mocktopus", @@ -1407,7 +1383,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", ] [[package]] @@ -1446,15 +1422,18 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.3.5" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c85295147490b8fcf2ea3d104080a105a8b2c63f9c319e82c02d8e952388919" +checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +dependencies = [ + "instant", +] [[package]] name = "fdlimit" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da54a593b34c71b889ee45f5b5bb900c74148c5f7f8c6a9479ee7899f69603c" +checksum = "2c4c9e43643f5a3be4ca5b67d26b98031ff9db6806c3440ae32e02e3ceac3f1b" dependencies = [ "libc", ] @@ -1476,7 +1455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b" dependencies = [ "either", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 2.0.2", "log", "num-traits", @@ -1504,9 +1483,9 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" [[package]] name = "flate2" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94" +checksum = "da80be589a72651dcda34d8b35bcdc9b7254ad06325611074d9cc0fbb19f60ee" dependencies = [ "cfg-if", "crc32fast", @@ -1523,18 +1502,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d12a63160eac0a00a1dba821291465e7c4bdaeee489af2912dc3d4513a9d1c34" +checksum = "98d7f1c606d158d5af4479f2971f259d8dd262f03f6f7b5b37e92eec7b8de396" dependencies = [ "parity-scale-codec", ] [[package]] name = "frame-benchmarking" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d92ab79f0c46fe4347d5073a0e331d935ca8d8bde0d001c8938900716685c3" +checksum = "66a5e3fe43568300fdca1c1bfd45ea463a12cca8fbe6172a4f6d58cd54e3fbcc" dependencies = [ "frame-support", "frame-system", @@ -1549,16 +1528,36 @@ dependencies = [ "sp-storage", ] +[[package]] +name = "frame-benchmarking-cli" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337ff68053dc7f7af821bdd241f367c17deb2213cc1b88cda7b856e796b6690" +dependencies = [ + "frame-benchmarking", + "parity-scale-codec", + "sc-cli", + "sc-client-db", + "sc-executor", + "sc-service", + "sp-core", + "sp-externalities", + "sp-runtime", + "sp-state-machine", + "structopt", +] + [[package]] name = "frame-executive" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a0cd96943af326c968548906a3968d573c7c6ddfa645c4bd2ed8168c1b6c68" +checksum = "c843800f05a7ad4653bc0db53a15e3d9bdd1cf14103e15c29e8aca200dbb1188" dependencies = [ "frame-support", "frame-system", "parity-scale-codec", "serde", + "sp-core", "sp-io", "sp-runtime", "sp-std", @@ -1567,9 +1566,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "11.0.0-rc6" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b82bf25442501c9455fc60090d606e5a36cc6e6953a7afee87fcab4fe2865b" +checksum = "6b5640bfcb7111643807c63cd38ecdcc923d3253e525f23ab6b366002bf8ecd5" dependencies = [ "parity-scale-codec", "serde", @@ -1579,9 +1578,9 @@ dependencies = [ [[package]] name = "frame-support" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611cb2bafdb3aa6d77e35153ddf3da26203481b294959e00491e5ba6609ef3a1" +checksum = "807c32da14bd0e5fb751095335a07938cda6f1488f57d7b0539118e3434980a8" dependencies = [ "bitmask", "frame-metadata", @@ -1605,9 +1604,9 @@ dependencies = [ [[package]] name = "frame-support-procedural" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961165a915c5a0bcbb3976791c4e857639d773474336f9484aee21dfb2268b66" +checksum = "508dc2eb44a802f1876e3dc97a76aed8f18b993f75f6cb1975cb83cf45a5d981" dependencies = [ "frame-support-procedural-tools", "proc-macro2", @@ -1617,9 +1616,9 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4855863432cfb36407e2f18cd1e189cf70ee3259ed137409e6076fa8fd9bc92b" +checksum = "04f6d1dd14477123180c47024bcc24c1a624ea8631b4f00080d14089907397f4" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -1630,9 +1629,9 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e41f45abe08fa7bb27c38ed4141bdb24dfe9604b024726cfc931b12303de9a2" +checksum = "8ad38379ecedd632f286c7b94a4b9a15bffb635194de4dbf2b4458bc46cee28f" dependencies = [ "proc-macro2", "quote", @@ -1641,9 +1640,9 @@ dependencies = [ [[package]] name = "frame-system" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "646ced951522d31f4bda819a2c87ea7feac3abcb1b35fba38b1ecc52fc661e75" +checksum = "d172404f0e44b867f5fd14465a27f298b8828b53d7a7a555d3759e1dec3c8f0d" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -1656,11 +1655,26 @@ dependencies = [ "sp-version", ] +[[package]] +name = "frame-system-benchmarking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e3a70ce89455777c5a93c60943e8a404c0be66bd3f53605c4a4e79baa80e91" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "frame-system-rpc-runtime-api" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39200f032a6b99cab2d4bdf3579e35baf8e2a71c2e8aecb1aac35a19f1ecba19" +checksum = "9b128f689fd9d497c3a7e881be524a8a1e2d80e2661754add6e36c9dfdcbe373" dependencies = [ "parity-scale-codec", "sp-api", @@ -1702,15 +1716,15 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" [[package]] name = "futures" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +checksum = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" dependencies = [ "futures-channel", "futures-core", @@ -1723,9 +1737,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +checksum = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" dependencies = [ "futures-core", "futures-sink", @@ -1742,9 +1756,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +checksum = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" [[package]] name = "futures-core-preview" @@ -1758,7 +1772,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", "num_cpus", ] @@ -1768,8 +1782,8 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdcef58a173af8148b182684c9f2d5250875adbcaff7b5794073894f9d8634a9" dependencies = [ - "futures 0.1.29", - "futures 0.3.5", + "futures 0.1.30", + "futures 0.3.6", "lazy_static", "log", "parking_lot 0.9.0", @@ -1780,9 +1794,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +checksum = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" dependencies = [ "futures-core", "futures-task", @@ -1792,30 +1806,30 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +checksum = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" [[package]] name = "futures-lite" -version = "0.1.11" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97999970129b808f0ccba93211201d431fcc12d7e1ffae03a61b5cedd1a7ced2" +checksum = "7c48d23e382e1f50ad68d16cd23dd3c467f420d4933b629c3f183f33e9f560d8" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", - "parking 2.0.0", + "parking", "pin-project-lite", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +checksum = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1825,15 +1839,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +checksum = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +checksum = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" dependencies = [ "once_cell 1.4.1", ] @@ -1849,18 +1863,14 @@ name = "futures-timer" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" -dependencies = [ - "gloo-timers", - "send_wrapper", -] [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +checksum = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", "futures-channel", "futures-core", "futures-io", @@ -1894,7 +1904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce54d63f8b0c75023ed920d46fd71d0cbbb830b0ee012726b5b4f506fb6dea5b" dependencies = [ "bytes 0.5.6", - "futures 0.3.5", + "futures 0.3.6", "memchr", "pin-project", ] @@ -1948,9 +1958,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -2024,7 +2034,7 @@ dependencies = [ "byteorder 1.3.4", "bytes 0.4.12", "fnv", - "futures 0.1.29", + "futures 0.1.30", "http 0.1.21", "indexmap", "log", @@ -2097,6 +2107,12 @@ dependencies = [ "autocfg 1.0.1", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + [[package]] name = "heck" version = "0.3.1" @@ -2108,9 +2124,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] @@ -2123,22 +2139,15 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "hex-literal" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -dependencies = [ - "hex-literal-impl", - "proc-macro-hack", -] +checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" [[package]] -name = "hex-literal-impl" -version = "0.2.2" +name = "hex_fmt" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" -dependencies = [ - "proc-macro-hack", -] +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" [[package]] name = "hmac" @@ -2190,7 +2199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "http 0.1.21", "tokio-buf", ] @@ -2211,6 +2220,12 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + [[package]] name = "humantime" version = "1.3.0" @@ -2227,7 +2242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "futures-cpupool", "h2 0.1.26", "http 0.1.21", @@ -2252,9 +2267,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.13.7" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" +checksum = "2f3afcfae8af5ad0576a31e768415edb627824129e8e5a29b8bfccb2f234e835" dependencies = [ "bytes 0.5.6", "futures-channel", @@ -2264,10 +2279,10 @@ dependencies = [ "http 0.2.1", "http-body 0.3.1", "httparse", + "httpdate", "itoa", "pin-project", "socket2", - "time", "tokio 0.2.22", "tower-service", "tracing", @@ -2283,7 +2298,7 @@ dependencies = [ "bytes 0.5.6", "ct-logs", "futures-util", - "hyper 0.13.7", + "hyper 0.13.8", "log", "rustls", "rustls-native-certs", @@ -2323,15 +2338,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "impl-serde" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" -dependencies = [ - "serde", -] - [[package]] name = "impl-serde" version = "0.3.1" @@ -2354,26 +2360,32 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.8.2", + "hashbrown 0.9.1", "serde", ] [[package]] name = "instant" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" +checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" +dependencies = [ + "cfg-if", +] [[package]] name = "integer-sqrt" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] [[package]] name = "intervalier" @@ -2381,7 +2393,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "futures-timer 2.0.2", ] @@ -2408,12 +2420,13 @@ checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" [[package]] name = "issue" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "bitcoin", "btc-relay", "collateral", "exchange-rate-oracle", + "frame-benchmarking", "frame-support", "frame-system", "mocktopus", @@ -2467,21 +2480,21 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" +checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonrpc-client-transports" -version = "14.2.1" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2773fa94a2a1fd51efb89a8f45b8861023dbb415d18d3c9235ae9388d780f9ec" +checksum = "489b9c612e60c766f751ab40fcb43cbb55a1e10bb44a9b4307ed510ca598cbd7" dependencies = [ "failure", - "futures 0.1.29", + "futures 0.1.30", "jsonrpc-core", "jsonrpc-pubsub", "log", @@ -2492,11 +2505,11 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0747307121ffb9703afd93afbd0fb4f854c38fb873f2c8b90e0e902f27c7b62" +checksum = "0745a6379e3edc893c84ec203589790774e4247420033e71a76d3ab4687991fa" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", "log", "serde", "serde_derive", @@ -2505,18 +2518,18 @@ dependencies = [ [[package]] name = "jsonrpc-core-client" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34221123bc79b66279a3fde2d3363553835b43092d629b34f2e760c44dc94713" +checksum = "6f764902d7b891344a0acb65625f32f6f7c6db006952143bd650209fbe7d94db" dependencies = [ "jsonrpc-client-transports", ] [[package]] name = "jsonrpc-derive" -version = "14.2.1" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fadf6945e227246825a583514534d864554e9f23d80b3c77d034b10983db5ef" +checksum = "99a847f9ec7bb52149b2786a17c9cb260d6effc6b8eeb8c16b343a487a7563a3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2526,9 +2539,9 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da906d682799df05754480dac1b9e70ec92e12c19ebafd2662a5ea1c9fd6522" +checksum = "4fb5c4513b7b542f42da107942b7b759f27120b5cc894729f88254b28dff44b7" dependencies = [ "hyper 0.12.35", "jsonrpc-core", @@ -2541,9 +2554,9 @@ dependencies = [ [[package]] name = "jsonrpc-ipc-server" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dedccd693325d833963b549e959137f30a7a0ea650cde92feda81dc0c1393cb5" +checksum = "cf50e53e4eea8f421a7316c5f63e395f7bc7c4e786a6dc54d76fab6ff7aa7ce7" dependencies = [ "jsonrpc-core", "jsonrpc-server-utils", @@ -2555,9 +2568,9 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d44f5602a11d657946aac09357956d2841299ed422035edf140c552cb057986" +checksum = "639558e0604013be9787ae52f798506ae42bf4220fe587bdc5625871cc8b9c77" dependencies = [ "jsonrpc-core", "log", @@ -2568,9 +2581,9 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56cbfb462e7f902e21121d9f0d1c2b77b2c5b642e1a4e8f4ebfa2e15b94402bb" +checksum = "72f1f3990650c033bd8f6bd46deac76d990f9bbfb5f8dc8c4767bf0a00392176" dependencies = [ "bytes 0.4.12", "globset", @@ -2584,16 +2597,16 @@ dependencies = [ [[package]] name = "jsonrpc-ws-server" -version = "14.2.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903d3109fe7c4acb932b567e1e607e0f524ed04741b09fb0e61841bc40a022fc" +checksum = "6596fe75209b73a2a75ebe1dce4e60e03b88a2b25e8807b667597f6315150d22" dependencies = [ "jsonrpc-core", "jsonrpc-server-utils", "log", + "parity-ws", "parking_lot 0.10.2", "slab", - "ws", ] [[package]] @@ -2680,9 +2693,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.76" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" [[package]] name = "libloading" @@ -2702,12 +2715,13 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.22.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0306a49ee6a89468f96089906f36b0eef82c988dcfc8acf3e2dcd6ad1c859f85" +checksum = "571f5a4604c1a40d75651da141dfde29ad15329f537a779528803297d2220274" dependencies = [ + "atomic", "bytes 0.5.6", - "futures 0.3.5", + "futures 0.3.6", "lazy_static", "libp2p-core", "libp2p-core-derive", @@ -2719,12 +2733,11 @@ dependencies = [ "libp2p-kad", "libp2p-mdns", "libp2p-mplex", - "libp2p-noise 0.21.0", + "libp2p-noise", "libp2p-ping", "libp2p-plaintext", "libp2p-pnet", "libp2p-request-response", - "libp2p-secio", "libp2p-swarm", "libp2p-tcp", "libp2p-uds", @@ -2739,50 +2752,18 @@ dependencies = [ "wasm-timer", ] -[[package]] -name = "libp2p" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ebb6c031584a5af181fe3a1e4b074af5d0b1a3b31663200f0251f4bcff6b5c" -dependencies = [ - "atomic", - "bytes 0.5.6", - "futures 0.3.5", - "lazy_static", - "libp2p-core", - "libp2p-core-derive", - "libp2p-dns", - "libp2p-identify", - "libp2p-kad", - "libp2p-mdns", - "libp2p-mplex", - "libp2p-noise 0.22.0", - "libp2p-ping", - "libp2p-swarm", - "libp2p-tcp", - "libp2p-wasm-ext", - "libp2p-websocket", - "libp2p-yamux", - "multihash", - "parity-multiaddr", - "parking_lot 0.10.2", - "pin-project", - "smallvec 1.4.2", - "wasm-timer", -] - [[package]] name = "libp2p-core" -version = "0.20.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a694fd76d7c33a45a0e6e1525e9b9b5d11127c9c94e560ac0f8abba54ed80af" +checksum = "52f13ba8c7df0768af2eb391696d562c7de88cc3a35122531aaa6a7d77754d25" dependencies = [ "asn1_der", "bs58", "ed25519-dalek", "either", "fnv", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "lazy_static", "libsecp256k1", @@ -2817,35 +2798,35 @@ dependencies = [ [[package]] name = "libp2p-deflate" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abeff37fa533fead23fc71b14ed0a2aced36c0c65c3d0078aff07821fb71029e" +checksum = "74029ae187f35f4b8ddf26b9779a68b340045d708528a103917cdca49a296db5" dependencies = [ "flate2", - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", ] [[package]] name = "libp2p-dns" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751924b6b98e350005e0b87a822beb246792a3fb878c684e088f866158120ac" +checksum = "7cf319822e08dd65c8e060d2354e9f952895bbc433f5706c75ed010c152aee5e" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", "log", ] [[package]] name = "libp2p-floodsub" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d4f310a02441b681075037ffb41649ee8836619559311b801ef3d5cdbe14cf" +checksum = "d8a9acb43a3e4a4e413e0c4abe0fa49308df7c6335c88534757b647199cb8a51" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", "libp2p-swarm", "prost", @@ -2856,20 +2837,21 @@ dependencies = [ [[package]] name = "libp2p-gossipsub" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a70f76b6c53ae9c97c234498c799802e43f91766bcf4a2a1f94f9339617d713b" +checksum = "ab20fcb60edebe3173bbb708c6ac3444afdf1e3152dc2866b10c4f5497f17467" dependencies = [ "base64 0.11.0", "byteorder 1.3.4", "bytes 0.5.6", "fnv", - "futures 0.3.5", + "futures 0.3.6", "futures_codec", + "hex_fmt", "libp2p-core", "libp2p-swarm", "log", - "lru", + "lru_time_cache", "prost", "prost-build", "rand 0.7.3", @@ -2881,11 +2863,11 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912c00a7bf67e0e765daf0cc37e08f675ea26aba3d6d1fbfaee81f19a4c23049" +checksum = "56396ee63aa9164eacf40c2c5d2bda8c4133c2f57e1b0425d51d3a4e362583b1" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", "libp2p-swarm", "log", @@ -2897,15 +2879,15 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44ed3a4c8111c570ab2bffb30c6353178d7603ce3787e3c5f2493c8d3d16d1f0" +checksum = "cc7fa9047f8b8f544278a35c2d9d45d3b2c1785f2d86d4e1629d6edf97be3955" dependencies = [ "arrayvec 0.5.1", "bytes 0.5.6", "either", "fnv", - "futures 0.3.5", + "futures 0.3.6", "futures_codec", "libp2p-core", "libp2p-swarm", @@ -2924,15 +2906,15 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd004c668160fd922f7268b2cd1e4550ff69165d9c744e9eb5770086eb753d02" +checksum = "3173b5a6b2f690c29ae07798d85b9441a131ac76ddae9015ef22905b623d0c69" dependencies = [ "async-std", "data-encoding", "dns-parser", "either", - "futures 0.3.5", + "futures 0.3.6", "lazy_static", "libp2p-core", "libp2p-swarm", @@ -2946,13 +2928,13 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ae0ffacd30f073f96cd518b2c9cd2cb18ac27c3d136a4b23cf1af99f33e541" +checksum = "8a73a799cc8410b36e40b8f4c4b6babbcb9efd3727111bf517876e4acfa612d3" dependencies = [ "bytes 0.5.6", "fnv", - "futures 0.3.5", + "futures 0.3.6", "futures_codec", "libp2p-core", "log", @@ -2962,13 +2944,13 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f353f8966bbaaf7456535fffd3f366f153148773a0cf04b2ec3860955cb720e" +checksum = "6ef6c490042f549fb1025f2892dfe6083d97a77558f450c1feebe748ca9eb15a" dependencies = [ "bytes 0.5.6", "curve25519-dalek 2.1.0", - "futures 0.3.5", + "futures 0.3.6", "lazy_static", "libp2p-core", "log", @@ -2978,39 +2960,17 @@ dependencies = [ "sha2 0.8.2", "snow", "static_assertions", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "libp2p-noise" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e594f2de0c23c2b7ad14802c991a2e68e95315c6a6c7715e53801506f20135d" -dependencies = [ - "bytes 0.5.6", - "curve25519-dalek 2.1.0", - "futures 0.3.5", - "lazy_static", - "libp2p-core", - "log", - "prost", - "prost-build", - "rand 0.7.3", - "sha2 0.8.2", - "snow", - "static_assertions", - "x25519-dalek", + "x25519-dalek 0.6.0", "zeroize", ] [[package]] name = "libp2p-ping" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70130cf130e4ba6dc177366e72dd9f86f9e3588fa1a0c4145247e676f16affad" +checksum = "ad063c21dfcea4518ac9e8bd4119d33a5b26c41e674f602f41f05617a368a5c8" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", "libp2p-swarm", "log", @@ -3021,12 +2981,12 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f0308a97f6fdd37a2bc388070e471c3ce9d92aa45c99d75c87c2dc5d5cac96" +checksum = "903a12e99c72dbebefea258de887982adeacc7025baa1ceb10b7fa9928f54791" dependencies = [ "bytes 0.5.6", - "futures 0.3.5", + "futures 0.3.6", "futures_codec", "libp2p-core", "log", @@ -3043,7 +3003,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d0db10e139d22d7af0b23ed7949449ec86262798aa0fd01595abdbcb02dc87" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "log", "pin-project", "rand 0.7.3", @@ -3053,55 +3013,32 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f48682b48a96545a323edd150c1d64fc1e250240bba02866e9f902e3dc032a9" +checksum = "9c0c9e8a4cd69d97e9646c54313d007512f411aba8c5226cfcda16df6a6e84a3" dependencies = [ "async-trait", - "futures 0.3.5", + "bytes 0.5.6", + "futures 0.3.6", "libp2p-core", "libp2p-swarm", - "smallvec 1.4.2", - "wasm-timer", -] - -[[package]] -name = "libp2p-secio" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff43513c383f7cdab2736eb98465fc4c5dd5d1988df89749dc8a68950349d56" -dependencies = [ - "aes-ctr", - "ctr", - "futures 0.3.5", - "hmac", - "js-sys", - "lazy_static", - "libp2p-core", "log", - "parity-send-wrapper", - "pin-project", - "prost", - "prost-build", - "quicksink", + "lru 0.6.0", + "minicbor", "rand 0.7.3", - "ring", - "rw-stream-sink", - "sha2 0.8.2", - "static_assertions", - "twofish", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "smallvec 1.4.2", + "unsigned-varint 0.5.1", + "wasm-timer", ] [[package]] name = "libp2p-swarm" -version = "0.20.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88d5e2a090a2aadf042cd33484e2f015c6dab212567406a59deece5dedbd133" +checksum = "7193e444210132237b81b755ec7fe53f1c4bd2f53cf719729b94c0c72eb6eaa1" dependencies = [ - "futures 0.3.5", + "either", + "futures 0.3.6", "libp2p-core", "log", "rand 0.7.3", @@ -3112,12 +3049,12 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1fa2bbad054020cb875546a577a66a65a5bf42eff55ed5265f92ffee3cc052" +checksum = "44f42ec130d7a37a7e47bf4398026b7ad9185c08ed26972e2720f8b94112796f" dependencies = [ "async-std", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "get_if_addrs", "ipnet", @@ -3128,23 +3065,23 @@ dependencies = [ [[package]] name = "libp2p-uds" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9db9fce9e3588c3118475d9ca761c5c133b639a624a7341e2a61e4b28c376b8" +checksum = "dea7acb0a034f70d7db94c300eba3f65c0f6298820105624088a9609c9974d77" dependencies = [ "async-std", - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", "log", ] [[package]] name = "libp2p-wasm-ext" -version = "0.20.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0feb99e32fea20ffb1bbf56a6fb2614bff7325ff44a515728385170b3420d2c3" +checksum = "34c1faac6f92c21fbe155417957863ea822fba9e9fd5eb24c0912336a100e63f" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -3154,13 +3091,13 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.21.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046a5201f6e471f22b22b394e4d084269ed1e28cf7300f7b49874385db84c7bd" +checksum = "d650534ebd99f48f6fa292ed5db10d30df2444943afde4407ceeddab8e513fca" dependencies = [ "async-tls", "either", - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", "log", "quicksink", @@ -3174,13 +3111,13 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.20.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46ae9bf2f7d8a4be9c7e9b61df9de9dc1bd66419d669098f22f81f8d9571029a" +checksum = "781d9b9f043dcdabc40640807125368596b849fd4d96cdca2dcf052fdf6f33fd" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "libp2p-core", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "thiserror", "yamux", ] @@ -3209,15 +3146,15 @@ dependencies = [ "hmac-drbg", "rand 0.7.3", "sha2 0.8.2", - "subtle 2.2.3", + "subtle 2.3.0", "typenum", ] [[package]] name = "libz-sys" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b34178653005c1181711c333f0e5604a14a1b5115c814fd42304bdd16245e0" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" dependencies = [ "cc", "pkg-config", @@ -3295,6 +3232,21 @@ dependencies = [ "hashbrown 0.6.3", ] +[[package]] +name = "lru" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111b945ac72ec09eb7bc62a0fbdc3cc6e80555a7245f52a69d3921a75b53b153" +dependencies = [ + "hashbrown 0.8.2", +] + +[[package]] +name = "lru_time_cache" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb241df5c4caeb888755363fc95f8a896618dc0d435e9e775f7930cb099beab" + [[package]] name = "mach" version = "0.3.2" @@ -3352,9 +3304,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ "autocfg 1.0.1", ] @@ -3389,12 +3341,33 @@ dependencies = [ ] [[package]] -name = "miniz_oxide" +name = "minicbor" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc03ad6f8f548db7194a5ff5a6f96342ecae4e3ef67d2bf18bacc0e245cd041" +dependencies = [ + "minicbor-derive", +] + +[[package]] +name = "minicbor-derive" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d7559a8a40d0f97e1edea3220f698f78b1c5ab67532e49f68fde3910323b722" +checksum = "c214bf3d90099b52f3e4b328ae0fe34837fd0fab683ad1e10fceb4629106df48" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9" dependencies = [ "adler", + "autocfg 1.0.1", ] [[package]] @@ -3495,7 +3468,7 @@ dependencies = [ [[package]] name = "module-exchange-rate-oracle-rpc" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -3510,16 +3483,91 @@ dependencies = [ [[package]] name = "module-exchange-rate-oracle-rpc-runtime-api" -version = "2.0.0-rc6" +version = "0.2.3" +dependencies = [ + "frame-support", + "parity-scale-codec", + "sp-api", +] + +[[package]] +name = "module-issue-rpc" +version = "0.2.3" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "module-issue-rpc-runtime-api", + "parity-scale-codec", + "serde", + "sp-api", + "sp-blockchain", + "sp-runtime", +] + +[[package]] +name = "module-issue-rpc-runtime-api" +version = "0.2.3" +dependencies = [ + "frame-support", + "parity-scale-codec", + "sp-api", + "sp-std", +] + +[[package]] +name = "module-redeem-rpc" +version = "0.2.3" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "module-redeem-rpc-runtime-api", + "parity-scale-codec", + "serde", + "sp-api", + "sp-blockchain", + "sp-runtime", +] + +[[package]] +name = "module-redeem-rpc-runtime-api" +version = "0.2.3" +dependencies = [ + "frame-support", + "parity-scale-codec", + "sp-api", + "sp-std", +] + +[[package]] +name = "module-replace-rpc" +version = "0.2.3" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "module-replace-rpc-runtime-api", + "parity-scale-codec", + "serde", + "sp-api", + "sp-blockchain", + "sp-runtime", +] + +[[package]] +name = "module-replace-rpc-runtime-api" +version = "0.2.3" dependencies = [ "frame-support", "parity-scale-codec", "sp-api", + "sp-std", ] [[package]] name = "module-staked-relayers-rpc" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -3534,7 +3582,7 @@ dependencies = [ [[package]] name = "module-staked-relayers-rpc-runtime-api" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "frame-support", "parity-scale-codec", @@ -3544,7 +3592,7 @@ dependencies = [ [[package]] name = "module-vault-registry-rpc" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -3559,10 +3607,11 @@ dependencies = [ [[package]] name = "module-vault-registry-rpc-runtime-api" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "frame-support", "parity-scale-codec", + "serde", "sp-api", "sp-std", ] @@ -3585,7 +3634,7 @@ dependencies = [ "sha-1 0.9.1", "sha2 0.9.1", "sha3 0.9.1", - "unsigned-varint 0.5.0", + "unsigned-varint 0.5.1", ] [[package]] @@ -3598,25 +3647,14 @@ checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" name = "multistream-select" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9157e87afbc2ef0d84cc0345423d715f445edde00141c93721c162de35a05e5" -dependencies = [ - "bytes 0.5.6", - "futures 0.3.5", - "log", - "pin-project", - "smallvec 1.4.2", - "unsigned-varint 0.4.0", -] - -[[package]] -name = "multitask" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c09c35271e7dcdb5f709779111f2c8e8ab8e06c1b587c1c6a9e179d865aaa5b4" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", +checksum = "c9157e87afbc2ef0d84cc0345423d715f445edde00141c93721c162de35a05e5" +dependencies = [ + "bytes 0.5.6", + "futures 0.3.6", + "log", + "pin-project", + "smallvec 1.4.2", + "unsigned-varint 0.4.0", ] [[package]] @@ -3645,11 +3683,21 @@ dependencies = [ "rand 0.3.23", ] +[[package]] +name = "nb-connect" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "net2" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" dependencies = [ "cfg-if", "libc", @@ -3818,9 +3866,9 @@ dependencies = [ [[package]] name = "pallet-aura" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4703d28e17b24cd58caefd581e82a62ddf91c6ec1b445eb24d0260458c766b4f" +checksum = "3150af311603b2fd78d948c8e2346d6b2530403c3971ae684ccc46021c1ea198" dependencies = [ "frame-support", "frame-system", @@ -3838,9 +3886,9 @@ dependencies = [ [[package]] name = "pallet-authorship" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fdb8508be1e72614b2606837a3fba0b027510f14aba3c8a9c7de4afa86065fd" +checksum = "65706c382ae14ef2768e7411c5faaf1e0a310b4a86d17c3a93dfacb2c5987576" dependencies = [ "frame-support", "frame-system", @@ -3854,9 +3902,9 @@ dependencies = [ [[package]] name = "pallet-balances" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec78c836f1481626270edfa445c612ba8e3aa6601f418f31a9aa815ae3ab6584" +checksum = "56bf116724c3adb7eee6ae49adfc28d3d38d9d34bbfdcc009497120256309a37" dependencies = [ "frame-benchmarking", "frame-support", @@ -3869,9 +3917,9 @@ dependencies = [ [[package]] name = "pallet-finality-tracker" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af0e96ea661bd4cf5022e3f77469be78a8eaf287d93c5b1f44248ebf79efd5" +checksum = "d9414e60c78b94ae77ea8ccc4a86e3d5ebd1de93c236d3dd899abacefe5d7e82" dependencies = [ "frame-support", "frame-system", @@ -3886,9 +3934,9 @@ dependencies = [ [[package]] name = "pallet-grandpa" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d9fede55423af51a23dbdc833b0d724d1c256c74ed77806a8cf2848c0cfec1" +checksum = "3f8a3b81d434ce9ef2c34adf61afa5ecf2a6e386cd626369deda1ca2f7a3b076" dependencies = [ "frame-benchmarking", "frame-support", @@ -3909,9 +3957,9 @@ dependencies = [ [[package]] name = "pallet-randomness-collective-flip" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bfcc654b88d8e5e726bd617b14567210152d33da5c1acf661d3c4d90fd11d2" +checksum = "e6b62b8adc02901769b7756b054fa732b6d1aad01e8a2d6873a70fdcd38c59a1" dependencies = [ "frame-support", "frame-system", @@ -3923,9 +3971,9 @@ dependencies = [ [[package]] name = "pallet-session" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd352daf0e6d775b07edf90162e0af68875cc9d2d6c31bb401a120e718f016e3" +checksum = "8abf520fc0c3259be05f164d43d34d52c86aeef8e8c5fded40145394394fc75d" dependencies = [ "frame-support", "frame-system", @@ -3944,9 +3992,9 @@ dependencies = [ [[package]] name = "pallet-sudo" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b925ea02f36e558d0ff08becce040b11ddf319701fe5125935fd98ea6ab16bee" +checksum = "13642cbbb2ea520ca2021299baec604de102a1d033dd32812c946cb03f48f47e" dependencies = [ "frame-support", "frame-system", @@ -3959,9 +4007,9 @@ dependencies = [ [[package]] name = "pallet-timestamp" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8678ecd7743bc05eae24ac0c115b9c2893fdeee0a880fbd6263ee4c56ead2ce" +checksum = "ccddd55b713f541dff6ccf063cc7ddbc4fc41e92a9fdad8ec9562a0e3b465016" dependencies = [ "frame-benchmarking", "frame-support", @@ -3977,9 +4025,9 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90468edc32e247eb6c34b4f075c9a1da6ffdc289be9e51241a7748502e1e2f89" +checksum = "f9fe2fc67f2eb123199a5b8fb89a8e1c30e5d6d6b1d98e0330bac85c0d8c46f1" dependencies = [ "frame-support", "frame-system", @@ -3995,9 +4043,9 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc40837d4ce1e10f7fa499e4e7014771610ff1094f7007390c5d67044497789" +checksum = "90fb0463589eeb1be8a3237e7260d139240e7d113950904f5a3cae5502576078" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -4014,9 +4062,9 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c09ab6ee960dcd6dc06cf4e549bbbafc1ab5dcef5a6d491a14b8fbdcf8ddfe04" +checksum = "76c8b6676df5a4b411a283b9ea22551094710180fa5caebeae9eea8e9dbfa620" dependencies = [ "frame-support", "parity-scale-codec", @@ -4060,9 +4108,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "1.3.4" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d38aeaffc032ec69faa476b3caaca8d4dd7f3f798137ff30359e5c7869ceb6" +checksum = "7c740e5fbcb6847058b40ac7e5574766c6388f585e184d769910fe0d3a2ca861" dependencies = [ "arrayvec 0.5.1", "bitvec", @@ -4073,9 +4121,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd20ff7e0399b274a5f5bb37b712fccb5b3a64b9128200d1c3cc40fe709cb073" +checksum = "198db82bb1c18fc00176004462dd809b2a6d851669550aa17af6dacd21ae0c14" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4096,7 +4144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e57fea504fea33f9fbb5f49f378359030e7e026a6ab849bb9e8f0787376f1bf" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "libc", "log", "mio-named-pipes", @@ -4142,10 +4190,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" [[package]] -name = "parking" -version = "1.0.6" +name = "parity-ws" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c" +checksum = "9e02a625dd75084c2a7024f07c575b61b782f729d18702dabb3cdbf31911dc61" +dependencies = [ + "byteorder 1.3.4", + "bytes 0.4.12", + "httparse", + "log", + "mio", + "mio-extras", + "rand 0.7.3", + "sha-1 0.8.2", + "slab", + "url 2.1.1", +] [[package]] name = "parking" @@ -4312,18 +4372,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" +checksum = "13fbdfd6bdee3dc9be46452f86af4a4072975899cf8592466668620bebfbcc17" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" +checksum = "c82fb1329f632c3552cf352d14427d57a511b1cf41db93b3a7d77906a82dcc8e" dependencies = [ "proc-macro2", "quote", @@ -4332,9 +4392,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" +checksum = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" [[package]] name = "pin-utils" @@ -4356,31 +4416,31 @@ checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" [[package]] name = "polling" -version = "0.1.7" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c5afb3e8bc82c2780a807374bda0fb8886904d8e9d51e6f4f3743fb1dd27fb" +checksum = "7215a098a80ab8ebd6349db593dc5faf741781bad0c4b7c5701fea6af548d52c" dependencies = [ "cfg-if", "libc", "log", - "wepoll-sys-stjepang", + "wepoll-sys", "winapi 0.3.9", ] [[package]] name = "poly1305" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b42192ab143ed7619bf888a7f9c6733a9a2153b218e2cd557cfdb52fbf9bb1" +checksum = "22ce46de8e53ee414ca4d02bfefac75d8c12fba948b76622a40b4be34dfce980" dependencies = [ "universal-hash", ] [[package]] name = "polyval" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a50142b55ab3ed0e9f68dfb3709f1d90d29da24e91033f28b96330643107dc" +checksum = "a5884790f1ce3553ad55fec37b5aaac5882e0e845a2612df744d6c85c9bf046c" dependencies = [ "cfg-if", "universal-hash", @@ -4400,7 +4460,7 @@ checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8" dependencies = [ "fixed-hash", "impl-codec", - "impl-serde 0.3.1", + "impl-serde", "uint", ] @@ -4451,23 +4511,24 @@ checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "prometheus" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0ced56dee39a6e960c15c74dc48849d614586db2eaada6497477af7c7811cd" +checksum = "30d70cf4412832bcac9cffe27906f4a66e450d323525e977168c70d1b36120ae" dependencies = [ "cfg-if", "fnv", "lazy_static", - "spin", + "parking_lot 0.11.0", + "regex", "thiserror", ] @@ -4777,9 +4838,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270" +checksum = "dcf6960dc9a5b4ee8d3e4c5787b4a112a8818e0290a42ff664ad60692fdf2032" dependencies = [ "autocfg 1.0.1", "crossbeam-deque", @@ -4789,9 +4850,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0" +checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -4811,12 +4872,13 @@ dependencies = [ [[package]] name = "redeem" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "bitcoin", "btc-relay", "collateral", "exchange-rate-oracle", + "frame-benchmarking", "frame-support", "frame-system", "mocktopus", @@ -4932,35 +4994,15 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "rental" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8545debe98b2b139fb04cad8618b530e9b07c152d99a5de83c860b877d67847f" -dependencies = [ - "rental-impl", - "stable_deref_trait", -] - -[[package]] -name = "rental-impl" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475e68978dc5b743f2f40d8e0a8fdc83f1c5e78cbf4b8fa5e74e73beebc340de" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "replace" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "bitcoin", "btc-relay", "collateral", "exchange-rate-oracle", + "frame-benchmarking", "frame-support", "frame-system", "mocktopus", @@ -5090,7 +5132,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "pin-project", "static_assertions", ] @@ -5132,11 +5174,11 @@ dependencies = [ [[package]] name = "sc-basic-authorship" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a46695a66db86ce460cffd11a6aec080e00502e9372facd26b2b3517e0fb95f" +checksum = "527f6822cf592ac2b4a6ca7d04601c48d6728b8c03d9a9cc0488e4b535c69c6d" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -5157,9 +5199,9 @@ dependencies = [ [[package]] name = "sc-block-builder" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82383c69e2f293e6cd3b3e5ad3665b5d61a700a4478a31e0cbdcffdea10951a9" +checksum = "5bee59dc560f30e72ee95c224e3e75299b53b619e659a38af9db2639803c08ee" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -5175,11 +5217,12 @@ dependencies = [ [[package]] name = "sc-chain-spec" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6a3b2b731b95934560c5368769ba0450b372a0db04d5d80ab91a85d5be6d88" +checksum = "b3d0e4d53e723ee6bad8cadec9651086887d1d920996e1589ee7dfa767a7cba9" dependencies = [ "impl-trait-for-tuples", + "parity-scale-codec", "sc-chain-spec-derive", "sc-network", "sc-telemetry", @@ -5192,9 +5235,9 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7fd27254a972011700e661644588c836f8cf47bd5e4692e55590fcf31c7a86d" +checksum = "38af2ca789e2d2fa2aa0ec16d27dc648fa4d64ecb10760d2f552b2c86ea7a403" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5204,21 +5247,20 @@ dependencies = [ [[package]] name = "sc-cli" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa4f8b84f28478c4e3ae2e96857b289a0fd892884520d2c484ceefcd8aa959f" +checksum = "9a2ce2952f155bd72b85ff866c588b6bae8f1bc183275f1a7a54eee55535a640" dependencies = [ "ansi_term 0.12.1", "atty", "bip39", "chrono", "derive_more", - "env_logger", "fdlimit", - "futures 0.3.5", + "futures 0.3.6", "hex", "lazy_static", - "libp2p 0.22.0", + "libp2p", "log", "names", "nix", @@ -5248,17 +5290,20 @@ dependencies = [ "substrate-prometheus-endpoint", "time", "tokio 0.2.22", + "tracing", + "tracing-log", + "tracing-subscriber", ] [[package]] name = "sc-client-api" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ad0e67083f458010898ba79c6863ce841c8d55b3c8c507f9a8afae7a15a251" +checksum = "9fafb2b2861e847657c4656d2ae2249c9f3f6a76fb92a22f750325b77e1fb4c8" dependencies = [ "derive_more", "fnv", - "futures 0.3.5", + "futures 0.3.6", "hash-db", "hex-literal", "kvdb", @@ -5289,9 +5334,9 @@ dependencies = [ [[package]] name = "sc-client-db" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1073163402675b042550121a2e1cb7db98d51849abc3ebc871fd36e707ed0871" +checksum = "6bc82e81fafb162ceda7635932c8b5d65b8bc7b021e49546ab913e2e2458524d" dependencies = [ "blake2-rfc", "hash-db", @@ -5320,9 +5365,9 @@ dependencies = [ [[package]] name = "sc-consensus" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badd279fbfa94188cb49446eb9a4112fc7d3212f20faea3a8a00662341243f50" +checksum = "d6dd5b4e7a37bf78e85161bd6f01a09f0eb7cf49f2961d136885659ad6e30d49" dependencies = [ "sc-client-api", "sp-blockchain", @@ -5332,12 +5377,12 @@ dependencies = [ [[package]] name = "sc-consensus-aura" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062c611a8021db230b716eb06f6b71b11f126f3d7f36c0fbd2f9ee895a399af9" +checksum = "e0b4fbf217f3942ae545ad70cd5b5d567b4519b9acb07b35e0de5cce7e7ef195" dependencies = [ "derive_more", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -5364,11 +5409,11 @@ dependencies = [ [[package]] name = "sc-consensus-slots" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ea48422963ff4150d3535702c932791dab6471615f92a4d3a5f52647a556d6" +checksum = "69a334a099d5cac9054ea1ef1db4be8ed5518270027798f96d2a68c5bf69af8e" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -5388,9 +5433,9 @@ dependencies = [ [[package]] name = "sc-executor" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99435a9edd886f5f30be5d8ab0b328b9d1bd06e0949896640cc6311b3c2bd58d" +checksum = "af77c7fda9659559e257fe330af26e7c2e8f61583c2a5c45f4c9db73d58a902b" dependencies = [ "derive_more", "lazy_static", @@ -5417,9 +5462,9 @@ dependencies = [ [[package]] name = "sc-executor-common" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff18805f4cdfb46dbaab60765a87d3e3c25ae17032e4b2b807f7844f85ec5f9" +checksum = "6663e4d1d2f8255e6c1994ce548365a7631a82f7ab231d0b8a122cc2a0011949" dependencies = [ "derive_more", "log", @@ -5435,9 +5480,9 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec579a2de5717d393971b53f7db23b41da1f5da63b175b6e2c14e8e2c373a9b8" +checksum = "78aeea37a28b83af11fe621ee047758e125341db96efaf7f553a4180fe48d6b8" dependencies = [ "log", "parity-scale-codec", @@ -5451,9 +5496,9 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e6fae2f895f6e1d792dbd59e6a2bdbe786b8524e6e25de7ea44441e982596f" +checksum = "c5c7d29c1932c5c3281d5324ead624709c1798031df72908ce6012b3651dea0a" dependencies = [ "log", "parity-scale-codec", @@ -5470,14 +5515,14 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7511cbb2978ac3513e7ba33983398f322e235cab662bbf7661a5bd3fcadfea" +checksum = "4095b26b5717265d3dca8e2d70f977dfd4085f1c352dbf82217953da90a96e46" dependencies = [ "derive_more", "finality-grandpa", "fork-tree", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -5508,12 +5553,12 @@ dependencies = [ [[package]] name = "sc-informant" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "698b29fd10438f00eaa393ec725ae33b6e19162471c429ea69236d766bf3292e" +checksum = "b81dbdbba0420bb4c0bf2a79bcbb78de5bd1349aad8467b3115f82be579b2972" dependencies = [ "ansi_term 0.12.1", - "futures 0.3.5", + "futures 0.3.6", "log", "parity-util-mem", "sc-client-api", @@ -5527,9 +5572,9 @@ dependencies = [ [[package]] name = "sc-keystore" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528afd2d984ab1bc4667fb60b5d2fbd685bf286145f630be7bc8cdbff8d1858f" +checksum = "21bbf8b58ed80e1d375aaa8ee5dedf17f68fea30c900440a695fb630a1757283" dependencies = [ "derive_more", "hex", @@ -5539,14 +5584,14 @@ dependencies = [ "serde_json", "sp-application-crypto", "sp-core", - "subtle 2.2.3", + "subtle 2.3.0", ] [[package]] name = "sc-light" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2703ff0aff2636c45b0249cc144ee7f131b97d239f6696fc545ba16e295a1386" +checksum = "a00ce4c6f21d572549b8b8a55757a0e548ddd670ab89d9415125a4e09c0ffa74" dependencies = [ "hash-db", "lazy_static", @@ -5564,11 +5609,12 @@ dependencies = [ [[package]] name = "sc-network" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94cc74f4df8b0ab2c71d177c7bb1994fc3719276b8d9051b386d123d2f328ac9" +checksum = "b9e58ccd69ea8dd0c1e1d98e5e7ed2969aaf14d45dcf98416c679a968e752850" dependencies = [ "async-std", + "async-trait", "bitflags", "bs58", "bytes 0.5.6", @@ -5577,16 +5623,16 @@ dependencies = [ "erased-serde", "fnv", "fork-tree", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", "futures_codec", "hex", "ip_network", - "libp2p 0.23.0", + "libp2p", "linked-hash-map", "linked_hash_set", "log", - "lru", + "lru 0.4.3", "nohash-hasher", "parity-scale-codec", "parking_lot 0.10.2", @@ -5618,15 +5664,15 @@ dependencies = [ [[package]] name = "sc-network-gossip" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fd39e7a5216f2d06569c0a341945191b3e15d51aebf77542429f36db5759ba" +checksum = "f6ddb2a1cb6cd53b46e76f61c662d1561da4a7dc16a375c37849fd1f429b6803" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", - "libp2p 0.23.0", + "libp2p", "log", - "lru", + "lru 0.4.3", "sc-network", "sp-runtime", "wasm-timer", @@ -5634,15 +5680,15 @@ dependencies = [ [[package]] name = "sc-offchain" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdeeeb906e69fed938acfd4772295f7007ee7c253425359889a61916e1e2c43" +checksum = "79495bd858351489fcebeb4e47821e15329ad5606f0d7983836e069005c3d9dd" dependencies = [ "bytes 0.5.6", "fnv", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", - "hyper 0.13.7", + "hyper 0.13.8", "hyper-rustls", "log", "num_cpus", @@ -5662,12 +5708,12 @@ dependencies = [ [[package]] name = "sc-peerset" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cd0f82759563667f55b43bc3242fe0822516919a639b1deb3501d6600a2a52" +checksum = "bbfaa3d62db8ad549e6d21b6e353e00e2e7338c8623c01c79e8f36b035266a4b" dependencies = [ - "futures 0.3.5", - "libp2p 0.23.0", + "futures 0.3.6", + "libp2p", "log", "serde_json", "sp-utils", @@ -5676,9 +5722,9 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5fcf2e03848137feb140c3e718f1787ec2a41dfc11ec77eebc73e22e3fb579" +checksum = "d42c942480b516b4bd4a32d1434f634126220cb00c8d482658700cc58dc22c6f" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -5686,11 +5732,11 @@ dependencies = [ [[package]] name = "sc-rpc" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6de8c678e509abd67706c46110f47d7f17f8c86d2ae03c2d34dd1bf0af1ee" +checksum = "fbc3793d8ff10dbeb0b683151a1ea33570dc994195cc29451e0b72ce35179adc" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", @@ -5719,12 +5765,12 @@ dependencies = [ [[package]] name = "sc-rpc-api" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eee9cecea38a2052d41bc9f62a68ece2cb7a9f1b29c156bb49d77de1e7cb95a" +checksum = "cfb4b79b9b6b410c745a00eb4ead11b2ef0819e6eac970a5ec6415abf82777be" dependencies = [ "derive_more", - "futures 0.3.5", + "futures 0.3.6", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -5744,10 +5790,11 @@ dependencies = [ [[package]] name = "sc-rpc-server" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f45d489660ccfc6ab172c6b00520dcfa1468d6abaa8cd599521df25b7af0b6" +checksum = "2f9118867e60870b99cc1877edb4c35878babe6696335841e5b636dcba2fdb3d" dependencies = [ + "futures 0.1.30", "jsonrpc-core", "jsonrpc-http-server", "jsonrpc-ipc-server", @@ -5757,19 +5804,20 @@ dependencies = [ "serde", "serde_json", "sp-runtime", + "substrate-prometheus-endpoint", ] [[package]] name = "sc-service" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb40d43fed89449bac132f2d6e3a477bb8df1053797d8bb30d22f6a2db56816" +checksum = "e04b2096d7dac26c52656cd2c85bc208d2ca3316ea2185fd775763d558a980da" dependencies = [ "derive_more", "directories", "exit-future", - "futures 0.1.29", - "futures 0.3.5", + "futures 0.1.30", + "futures 0.3.6", "futures-timer 3.0.2", "hash-db", "jsonrpc-core", @@ -5811,6 +5859,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-state-machine", + "sp-tracing", "sp-transaction-pool", "sp-trie", "sp-utils", @@ -5823,9 +5872,9 @@ dependencies = [ [[package]] name = "sc-state-db" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c85bf121dc25232c82cd5aa905084a14e7aadbd650bc9a3334894728026369" +checksum = "56341f78caf54af053889d1e863ca9b03004a3f471947805226fa8a6be9c9a59" dependencies = [ "log", "parity-scale-codec", @@ -5838,13 +5887,13 @@ dependencies = [ [[package]] name = "sc-telemetry" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "690fb181755b30db7112f086ab815fdcb0ef273b703fc50d89e8e9930fb76ac3" +checksum = "5883219d0ccec3e4d50079ba63f8accc71659b93537cff66de326a382b138c4b" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", - "libp2p 0.23.0", + "libp2p", "log", "parking_lot 0.10.2", "pin-project", @@ -5860,9 +5909,9 @@ dependencies = [ [[package]] name = "sc-tracing" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01e6f4e38e0d0daf42df5abf7b908c248314fdf7a5ca2a87356bdfcce2d2fc8" +checksum = "695f005588c8b6957e56c86bc4624969a0c1a8e4e4d2f4fe0bb4039a26a10503" dependencies = [ "erased-serde", "log", @@ -5874,17 +5923,18 @@ dependencies = [ "slog", "sp-tracing", "tracing", + "tracing-core", "tracing-subscriber", ] [[package]] name = "sc-transaction-graph" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a4b349262cc33587bd53de7331f7ccd8bd2f29b7da1d0fab6e426cf6246559b" +checksum = "31fed765b519362f7ae824a2d3a2e6ee9912ac972e8ff61838d4ff0831cb3077" dependencies = [ "derive_more", - "futures 0.3.5", + "futures 0.3.6", "linked-hash-map", "log", "parity-util-mem", @@ -5901,12 +5951,12 @@ dependencies = [ [[package]] name = "sc-transaction-pool" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a885d3dda5239eb7c8c49b2beb3ff3cfaf771418450a302c0fb143ba6b242b8" +checksum = "248d4bcde22c936b462e4aa6c32e0f49a96942b123a1a46bc60cd02fbf907002" dependencies = [ "derive_more", - "futures 0.3.5", + "futures 0.3.6", "futures-diagnose", "intervalier", "log", @@ -5950,7 +6000,7 @@ dependencies = [ "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", - "subtle 2.2.3", + "subtle 2.3.0", "zeroize", ] @@ -6013,7 +6063,7 @@ dependencies = [ [[package]] name = "security" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "frame-support", "frame-system", @@ -6066,26 +6116,20 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - [[package]] name = "serde" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", @@ -6094,9 +6138,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" dependencies = [ "itoa", "ryu", @@ -6276,9 +6320,9 @@ checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "snow" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32bf8474159a95551661246cda4976e89356999e3cbfef36f493dacc3fae1e8e" +checksum = "795dd7aeeee24468e5a32661f6d27f7b5cbed802031b2d7640c7b10f8fb2dd50" dependencies = [ "aes-gcm", "blake2", @@ -6288,15 +6332,15 @@ dependencies = [ "ring", "rustc_version", "sha2 0.9.1", - "subtle 2.2.3", - "x25519-dalek", + "subtle 2.3.0", + "x25519-dalek 1.1.0", ] [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" dependencies = [ "cfg-if", "libc", @@ -6306,25 +6350,25 @@ dependencies = [ [[package]] name = "soketto" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85457366ae0c6ce56bf05a958aef14cd38513c236568618edbcd9a8c52cb80b0" +checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88" dependencies = [ "base64 0.12.3", "bytes 0.5.6", "flate2", - "futures 0.3.5", + "futures 0.3.6", "httparse", "log", "rand 0.7.3", - "sha-1 0.8.2", + "sha-1 0.9.1", ] [[package]] name = "sp-allocator" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16378a5000d98a01b87fa8a40a5bf02cc483545cbae8125c456954330eee78e4" +checksum = "9e79a1db780708b6b71e9914e2b1d11b3e61c9bfb492c88b1024115e1a6661da" dependencies = [ "derive_more", "log", @@ -6335,9 +6379,9 @@ dependencies = [ [[package]] name = "sp-api" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7467f7e20ded41f54cffec173588419dc9c3efb7fb1e73a4541a66774545f9cb" +checksum = "953a3296335d9761311763dbe6855109ea4bea915e27cf5633d8b01057898302" dependencies = [ "hash-db", "parity-scale-codec", @@ -6351,9 +6395,9 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da136f7fbc99517e5f6f16401110a16240f99d2fbff738b8666b0b10a1d638c7" +checksum = "8247ca24a2a881af2ac675c8ec33584944965d6d45645bbec16fe327ce42dce6" dependencies = [ "blake2-rfc", "proc-macro-crate", @@ -6364,9 +6408,9 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33508e0f9c96186eae2c73482ae02b463cb85fd80d42dc48d7b5cf778aad6ba" +checksum = "885eca124aa6ce0bba57c08bc48c4357096996d630a77f572580ef8e2e4df034" dependencies = [ "parity-scale-codec", "serde", @@ -6377,9 +6421,9 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f861e78b2de65df52d855ff668a00890160ab66afa25e8203f4240152e89085" +checksum = "667775bc50eb214225df18c92e4ec57acc7e2dc78d7d210eb4dd930db1a73995" dependencies = [ "integer-sqrt", "num-traits", @@ -6391,9 +6435,9 @@ dependencies = [ [[package]] name = "sp-authorship" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e57577889c29682da19110e3a30d14c8afcaac3df1cd8de7a9ac09583b3fab" +checksum = "58623adee1ed41752d76151762c80801758f88f85e4016d0338f2b01f4e7bd44" dependencies = [ "parity-scale-codec", "sp-inherents", @@ -6403,9 +6447,9 @@ dependencies = [ [[package]] name = "sp-block-builder" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6439b15294ed4eec9a2c330c7c834e2af2118cedd20db7f8be33bd2949c03800" +checksum = "07d7fca8aa126a9d295843d592f44b48d8cf93880862baeff2968164598ab26c" dependencies = [ "parity-scale-codec", "sp-api", @@ -6416,13 +6460,13 @@ dependencies = [ [[package]] name = "sp-blockchain" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f79c60117f539ee7a9c585722268f6b2b12999390f2c6ec53269977c10eae9c" +checksum = "e37387284973e2edceefaa673930282801ea238e5892a2cc6aa02f7f2e7601df" dependencies = [ "derive_more", "log", - "lru", + "lru 0.4.3", "parity-scale-codec", "parking_lot 0.10.2", "sp-block-builder", @@ -6434,9 +6478,9 @@ dependencies = [ [[package]] name = "sp-chain-spec" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9eb83a5f50c95172e462843184f8a3d55798b58a68f31c46054fff1ec16b19" +checksum = "150ce7661d02d4d0509a4a8364ab3b71a5ef2faf3f97d22d4b76bc0786d9e28b" dependencies = [ "serde", "serde_json", @@ -6444,14 +6488,14 @@ dependencies = [ [[package]] name = "sp-consensus" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24512668d65ee6026dd7e2fdfb18ea1aaeee0f59415a4abf969b67c2f968229d" +checksum = "b460103293bbf2f4193e43c4f031fdc099c5e27c782369bbb4dacc7765e84057" dependencies = [ "derive_more", - "futures 0.3.5", + "futures 0.3.6", "futures-timer 3.0.2", - "libp2p 0.23.0", + "libp2p", "log", "parity-scale-codec", "parking_lot 0.10.2", @@ -6471,9 +6515,9 @@ dependencies = [ [[package]] name = "sp-consensus-aura" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11e0d52c37986b11cf4babebf254ea334a7627934ee461c2daf5709bb8530514" +checksum = "8dc270d5c9c74960f44be4fe3e2e04886edf6a4a6fa85a57d381b242ce8b41e0" dependencies = [ "parity-scale-codec", "sp-api", @@ -6486,9 +6530,9 @@ dependencies = [ [[package]] name = "sp-consensus-slots" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "012661ac8e5a2190f8418fe9d34057adff72bcc627740224aba21805de34aa64" +checksum = "83ea323ccf4ec8aad353fbc9016a1cb8cbf0d872d33bc8874cb0753b014fb7fc" dependencies = [ "parity-scale-codec", "sp-runtime", @@ -6496,9 +6540,9 @@ dependencies = [ [[package]] name = "sp-core" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146765f2e906030c2d7fba4a685390407d5d0595b7e46716b2bcd6c7ac744579" +checksum = "e92ac5c674ee2cd9219d084301b4cbb82b28a94a0f3087bf4bea0ef3067ebb5c" dependencies = [ "base58", "blake2-rfc", @@ -6506,11 +6550,11 @@ dependencies = [ "derive_more", "dyn-clonable", "ed25519-dalek", - "futures 0.3.5", + "futures 0.3.6", "hash-db", "hash256-std-hasher", "hex", - "impl-serde 0.3.1", + "impl-serde", "lazy_static", "libsecp256k1", "log", @@ -6541,9 +6585,9 @@ dependencies = [ [[package]] name = "sp-database" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23faeb4e1c660ddaa0c06ba2a0d51697e0eda10c7d9568005c3bafeff65f3027" +checksum = "4c1c352eceefe5bcdfc27f13a2fd038fc571b7aca5146f2cd651d40e9d2457dd" dependencies = [ "kvdb", "parking_lot 0.10.2", @@ -6551,9 +6595,9 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc56e04bc64020aa6c1a35fb74991ab8d2aa46ffc0b133145103d8b6304f195" +checksum = "8a3750b084e0f4677f6e834a974f30b1ba97fc2fe00185c9d03611a2228446dc" dependencies = [ "proc-macro2", "quote", @@ -6562,9 +6606,9 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ff5c062c4c36814d8aa21031b3fc7a16816db879965a910b98f49c6d80914e" +checksum = "9d87fcd0e0fc5e025459cfe769803488d4894e36d0f8cef80b5239d2e7ef6580" dependencies = [ "environmental", "parity-scale-codec", @@ -6574,9 +6618,9 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823dfc3119fad75fc200408a3b85a0b05961aed0257e5d8ba23f8f2d03993cdb" +checksum = "789d960506306f34fb0a2da547956ba1f23d6a29032291a7284c943906feddcb" dependencies = [ "finality-grandpa", "log", @@ -6591,9 +6635,9 @@ dependencies = [ [[package]] name = "sp-finality-tracker" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4633e4857d88d8981c4d76a1b04a2a1a0c032d08245b6006a6c8d3f3f0da6df8" +checksum = "5d5433473273a116241010551b9acfdbd7d33a9fdcda45c390eb707971568154" dependencies = [ "parity-scale-codec", "sp-inherents", @@ -6602,9 +6646,9 @@ dependencies = [ [[package]] name = "sp-inherents" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a0c71c49638e89a2aa252d291625528d67a6efee6df0ffb88cbae32f3ca878e" +checksum = "365e5aee23640631e63e8634f1d804e33c8fcb521f4052910f29abaa2df1c1cf" dependencies = [ "derive_more", "parity-scale-codec", @@ -6615,11 +6659,11 @@ dependencies = [ [[package]] name = "sp-io" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3668b7ee3720ffbea89308832f04cee067c8d40a06f9ced818d890cb2aae112f" +checksum = "b9e1dee9244eb6cba1bef9b3a4ec288185e1380e455f1fd348b60252592c1cf0" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "hash-db", "libsecp256k1", "log", @@ -6633,13 +6677,15 @@ dependencies = [ "sp-tracing", "sp-trie", "sp-wasm-interface", + "tracing", + "tracing-core", ] [[package]] name = "sp-keyring" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99472908ac61a50b9973c492e277db3295ba2314294c2e36e8dd41842fae6fc5" +checksum = "3f76feeb27b218d58523931ea2d708b622c3bd96a3be1c3a5895bba0f7a54c13" dependencies = [ "lazy_static", "sp-core", @@ -6649,9 +6695,9 @@ dependencies = [ [[package]] name = "sp-offchain" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39724817f34c7311202eee09bdf3190f0c2f2f3852e1d228053227d44863217" +checksum = "fbd5e101b2510ad84adaeb4589e6a94fdc741242ab1e39b89c87a647133205ad" dependencies = [ "sp-api", "sp-core", @@ -6660,9 +6706,9 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56a3e76c47eca218aa86c8a02942c62d71fb47b01feb1fc38d8297f93929a35e" +checksum = "492126eb766b3b6740e4e4929d6527d37708598b7296a664f3680c0f0c1fc573" dependencies = [ "backtrace", "log", @@ -6670,9 +6716,9 @@ dependencies = [ [[package]] name = "sp-rpc" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f5c07f1dbfb9a50a1beaedaa9d2909758d25c94a591bfbd0a400b328fc7b22e" +checksum = "e5c6678f4b42421e6dcdf3896a0c81a403c29ef1cf8d74b046d59125d40da911" dependencies = [ "serde", "sp-core", @@ -6680,9 +6726,9 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb489c671d0dc1ec00f83550e259cc75ab5c25d0d41b901c7a35cda99da7964" +checksum = "62542f8ce9d5fcb43a4dd3c3a53326d33aacf9b0bc9d353d6fe9fd5ff3031747" dependencies = [ "either", "hash256-std-hasher", @@ -6703,9 +6749,9 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b63b4b5e0fd1488b545d908003cd8129c88c066af361f9b6483ac7c97d8f6c1" +checksum = "8b7e363c480cc8c9019b84f85d10c0b56a184079d5d840d2d1d55087ad835dc6" dependencies = [ "parity-scale-codec", "primitive-types", @@ -6720,9 +6766,9 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21c3ed5a0258faaa1370859bfdacf27d798f4205161a68289555eb1a1a6a4e41" +checksum = "85cf56a38544293e54dbe0aa7b6aed1e046bfc704b6fc3de7255897dca98ccb1" dependencies = [ "Inflector", "proc-macro-crate", @@ -6733,9 +6779,9 @@ dependencies = [ [[package]] name = "sp-serializer" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b99a01e4c61cabad1e383f014e559b1390f5f98c43ccdd0492c0fc195f4a4047" +checksum = "643933e971979094c9d4b27b015c7250985a262e405bb9ad090336d8ceb5b2b9" dependencies = [ "serde", "serde_json", @@ -6743,9 +6789,9 @@ dependencies = [ [[package]] name = "sp-session" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b571809d807be2244393de7ee5003e5b6f53187897d2302d988b38481bb4421" +checksum = "d138b1f548933003feaa967de49ed87066643073bcc41be45ef2daaa0991c133" dependencies = [ "parity-scale-codec", "sp-api", @@ -6757,9 +6803,9 @@ dependencies = [ [[package]] name = "sp-staking" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab31cfa1734a9548ebe4b87d10bcf658f835ee3b0c8f08f89f46eb7013f81a9" +checksum = "3b06f9839d8b4312486626bde31d6cd7763dd9b7d93ea9e70c01ca30f0998032" dependencies = [ "parity-scale-codec", "sp-runtime", @@ -6768,12 +6814,11 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f1d76c8c207b644ed9cabeeeb9eead95c72691db9e357fe56ab19285b36b2b4" +checksum = "5f58335de98bca196683a8ef22195a8a43b457b8bc705dba3124138ffc2ee720" dependencies = [ "hash-db", - "itertools 0.9.0", "log", "num-traits", "parity-scale-codec", @@ -6783,6 +6828,7 @@ dependencies = [ "sp-core", "sp-externalities", "sp-panic-handler", + "sp-std", "sp-trie", "trie-db", "trie-root", @@ -6790,17 +6836,17 @@ dependencies = [ [[package]] name = "sp-std" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd69654cdd9fa179dad52811220356dc2991f70b3b93e77c27f4e317d58c059b" +checksum = "fa2d6e166cead2d3b1d3d8fe0e787d076b7d0296b1760a0d7d340846d0ba42c5" [[package]] name = "sp-storage" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0dba5526e0a1d2acc3d969cdcdf89f4e0395a1a6e807f5aa517ef15bf0e710" +checksum = "0f4625e6f8f40995939560f48f89028f658b7929657c68d01c571c81ab5619ff" dependencies = [ - "impl-serde 0.2.3", + "impl-serde", "parity-scale-codec", "ref-cast", "serde", @@ -6810,9 +6856,9 @@ dependencies = [ [[package]] name = "sp-timestamp" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59b7c9ea91411e7d18be5009ac38775843778edde563d791a4ba40fecaec4de" +checksum = "0cb398f0a5d2798ad4e02450b3089534547b448d22ebe6f3b2c03f74170f58d1" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -6825,23 +6871,26 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50a43072c8a66b1f6cfec0bee7f3f2aa7866869317b5f430e8a2743551b77c4d" +checksum = "b9a5c42c5450991ca3a28c190e75122f5ccedbcb024953e7c357e7aa2afd8534" dependencies = [ "log", - "rental", + "parity-scale-codec", + "sp-std", "tracing", + "tracing-core", + "tracing-subscriber", ] [[package]] name = "sp-transaction-pool" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748dbe5c6420dceb48ddabda8ba2ba80e1ef184f32c207ef2f9cb87e56a4ebd" +checksum = "83b34ee48341c17c6e2f1e55f6076918f46b0c4505a99ad69ab1edda8b45bbd8" dependencies = [ "derive_more", - "futures 0.3.5", + "futures 0.3.6", "log", "parity-scale-codec", "serde", @@ -6852,9 +6901,9 @@ dependencies = [ [[package]] name = "sp-trie" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36b27498caf2238d68df9ed9a8bf326622142119328ae41b17cafc36c6acafab" +checksum = "f3aae57c8ae81ba978503137a8c625d2963eb425dd90dec0d96b4ed18d8bfd55" dependencies = [ "hash-db", "memory-db", @@ -6867,11 +6916,11 @@ dependencies = [ [[package]] name = "sp-utils" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45813274bd799a0e77d55f4ac225a59af1b4363142ca41bb38e29f699a76a81" +checksum = "84310a02e2ac89b5e288d7af980414fd88753e3caba92aab1983cd2819991150" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "futures-core", "futures-timer 3.0.2", "lazy_static", @@ -6880,11 +6929,11 @@ dependencies = [ [[package]] name = "sp-version" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d075c051dc9dc75685c484463729d50d21930aa9068f652734598f8a882f6e0" +checksum = "21935199c8765f0d02facc718f9c83149a70ea684fb03612e5161c682b38a301" dependencies = [ - "impl-serde 0.2.3", + "impl-serde", "parity-scale-codec", "serde", "sp-runtime", @@ -6893,9 +6942,9 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb0c2a1c2bdbbd67c1b8f20a9c85606122e7227b67cf5cd9faf3df2f454a66b" +checksum = "f1c28225e8b7ec7e260f8b46443f8731abda206334cb75c740d2407693f38167" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -6917,12 +6966,13 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "staked-relayers" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "bitcoin", "btc-relay", "collateral", "exchange-rate-oracle", + "frame-benchmarking", "frame-support", "frame-system", "hex", @@ -6970,10 +7020,11 @@ dependencies = [ [[package]] name = "stream-cipher" -version = "0.4.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f8ed9974042b8c3672ff3030a69fcc03b74c47c3d1ecb7755e8a3626011e88" +checksum = "c80e15f898d8d8f25db24c253ea615cc14acf418ff307822995814e7d42cfa89" dependencies = [ + "block-cipher", "generic-array 0.14.4", ] @@ -6994,9 +7045,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5" +checksum = "a33f6461027d7f08a13715659b2948e1602c31a3756aeae9378bfe7518c72e82" dependencies = [ "clap", "lazy_static", @@ -7005,9 +7056,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f" +checksum = "c92e775028122a4b3dd55d58f14fc5120289c69bee99df1d117ae30f84b225c9" dependencies = [ "heck", "proc-macro-error", @@ -7052,21 +7103,21 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf0107b85ed2f59e42d015274a3816ba3bd5b0f01a69818bc04d3ea94a242e3" +checksum = "f14feab86fe31e7d0a485d53d7c1c634c426f7ae5b8ce4f705b2e49a35713fcb" dependencies = [ "platforms", ] [[package]] name = "substrate-frame-rpc-system" -version = "2.0.0-rc6" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d33128123584134d38386e8ab5306eec77f336db7d4bb9e55e1ca90e477dcc" +checksum = "44e6202803178f25f71a3218a69341289d38c1369cc63e78dfe51577599163f7" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.5", + "futures 0.3.6", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -7085,14 +7136,14 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" -version = "0.8.0-rc6" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcccc8b56f8590db1f1e6acc8674187eb856ef42d7f93f3326e1fdbc10389f37" +checksum = "8d3e361741d066bfc29554b9f1bc8e4ac927eb4bd33dd8bb0486969edd8b0b5a" dependencies = [ "async-std", "derive_more", "futures-util", - "hyper 0.13.7", + "hyper 0.13.8", "log", "prometheus", "tokio 0.2.22", @@ -7112,15 +7163,15 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" +checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" [[package]] name = "syn" -version = "1.0.39" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" +checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" dependencies = [ "proc-macro2", "quote", @@ -7185,18 +7236,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" +checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" +checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" dependencies = [ "proc-macro2", "quote", @@ -7270,7 +7321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "mio", "num_cpus", "tokio-codec", @@ -7317,7 +7368,7 @@ checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ "bytes 0.4.12", "either", - "futures 0.1.29", + "futures 0.1.30", ] [[package]] @@ -7327,7 +7378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "tokio-io", ] @@ -7337,7 +7388,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", "tokio-executor 0.1.10", ] @@ -7348,7 +7399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" dependencies = [ "crossbeam-utils", - "futures 0.1.29", + "futures 0.1.30", ] [[package]] @@ -7368,7 +7419,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", "tokio-io", "tokio-threadpool", ] @@ -7380,7 +7431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "log", ] @@ -7391,7 +7442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d282d483052288b2308ba5ee795f5673b159c9bdf63c385a05609da782a5eae" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "mio", "mio-named-pipes", "tokio 0.1.22", @@ -7404,7 +7455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" dependencies = [ "crossbeam-utils", - "futures 0.1.29", + "futures 0.1.30", "lazy_static", "log", "mio", @@ -7434,7 +7485,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", ] [[package]] @@ -7444,7 +7495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" dependencies = [ "fnv", - "futures 0.1.29", + "futures 0.1.30", ] [[package]] @@ -7465,7 +7516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "iovec", "mio", "tokio-io", @@ -7481,7 +7532,7 @@ dependencies = [ "crossbeam-deque", "crossbeam-queue", "crossbeam-utils", - "futures 0.1.29", + "futures 0.1.30", "lazy_static", "log", "num_cpus", @@ -7496,7 +7547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ "crossbeam-utils", - "futures 0.1.29", + "futures 0.1.30", "slab", "tokio-executor 0.1.10", ] @@ -7508,7 +7559,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "log", "mio", "tokio-codec", @@ -7523,7 +7574,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" dependencies = [ "bytes 0.4.12", - "futures 0.1.29", + "futures 0.1.30", "iovec", "libc", "log", @@ -7565,12 +7616,13 @@ checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" [[package]] name = "tracing" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" +checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27" dependencies = [ "cfg-if", "log", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -7588,9 +7640,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" dependencies = [ "lazy_static", ] @@ -7608,9 +7660,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ccba2f8f16e0ed268fc765d9b7ff22e965e7185d32f8f1ec8294fe17d86e79" +checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" dependencies = [ "serde", "tracing-core", @@ -7618,9 +7670,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd165311cc4d7a555ad11cc77a37756df836182db0d81aac908c8184c584f40" +checksum = "82bb5079aa76438620837198db8a5c529fb9878c730bc2b28179b0241cf04c10" dependencies = [ "ansi_term 0.12.1", "chrono", @@ -7639,7 +7691,7 @@ dependencies = [ [[package]] name = "treasury" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "frame-support", "frame-system", @@ -7681,17 +7733,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "twofish" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" -dependencies = [ - "block-cipher-trait", - "byteorder 1.3.4", - "opaque-debug 0.2.3", -] - [[package]] name = "twox-hash" version = "1.5.0" @@ -7771,7 +7812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" dependencies = [ "generic-array 0.14.4", - "subtle 2.2.3", + "subtle 2.3.0", ] [[package]] @@ -7788,9 +7829,13 @@ dependencies = [ [[package]] name = "unsigned-varint" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98e44fc6af1e18c3a06666d829b4fd8d2714fb2dbffe8ab99d5dc7ea6baa628" +checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" +dependencies = [ + "futures-io", + "futures-util", +] [[package]] name = "untrusted" @@ -7822,10 +7867,11 @@ dependencies = [ [[package]] name = "vault-registry" -version = "2.0.0-rc6" +version = "0.2.3" dependencies = [ "collateral", "exchange-rate-oracle", + "frame-benchmarking", "frame-support", "frame-system", "mocktopus", @@ -7851,9 +7897,9 @@ checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" [[package]] name = "vec-arena" -version = "0.5.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb18268690309760d59ee1a9b21132c126ba384f374c59a94db4bc03adeb561" +checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" [[package]] name = "vec_map" @@ -7885,7 +7931,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "futures 0.1.29", + "futures 0.1.30", "log", "try-lock", ] @@ -7914,9 +7960,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -7924,9 +7970,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" dependencies = [ "bumpalo", "lazy_static", @@ -7939,9 +7985,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" +checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" dependencies = [ "cfg-if", "js-sys", @@ -7951,9 +7997,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7961,9 +8007,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" dependencies = [ "proc-macro2", "quote", @@ -7974,9 +8020,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" +checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" [[package]] name = "wasm-timer" @@ -7984,7 +8030,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "js-sys", "parking_lot 0.11.0", "pin-utils", @@ -8185,27 +8231,27 @@ dependencies = [ [[package]] name = "wast" -version = "23.0.0" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b080a48623c1b15193eac2e28c7b8d0e6b2e1c6c67ed46ddcd86063e78e504" +checksum = "d8c67a4386e4efe10563552848d8c6a4b7f941e69924a935495645c3f52b32d0" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c350d7431aa486488d28cdf75b57d59c02fab9cde20d93c52424510afe18ecc" +checksum = "4766d466249e23279e92c52033429eb91141c5efea1c4478138fa6f6ef4efe3e" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47" +checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" dependencies = [ "js-sys", "wasm-bindgen", @@ -8240,10 +8286,10 @@ dependencies = [ ] [[package]] -name = "wepoll-sys-stjepang" -version = "1.0.6" +name = "wepoll-sys" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" +checksum = "142bc2cba3fe88be1a8fcb55c727fa4cd5b0cf2d7438722792e22f26f04bc1e0" dependencies = [ "cc", ] @@ -8300,24 +8346,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "ws" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51a2c47b5798ccc774ffb93ff536aec7c4275d722fd9c740c83cdd1af1f2d94" -dependencies = [ - "byteorder 1.3.4", - "bytes 0.4.12", - "httparse", - "log", - "mio", - "mio-extras", - "rand 0.7.3", - "sha-1 0.8.2", - "slab", - "url 2.1.1", -] - [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -8339,34 +8367,45 @@ dependencies = [ "zeroize", ] +[[package]] +name = "x25519-dalek" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" +dependencies = [ + "curve25519-dalek 3.0.0", + "rand_core 0.5.1", + "zeroize", +] + [[package]] name = "yamux" -version = "0.4.9" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053585b18bca1a3d00e4b5ef93e72d4f49a10005374c455db7177e27149c899d" +checksum = "9aeb8c4043cac71c3c299dff107171c220d179492350ea198e109a414981b83c" dependencies = [ - "futures 0.3.5", + "futures 0.3.6", "log", "nohash-hasher", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rand 0.7.3", "static_assertions", ] [[package]] name = "zeroize" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" +checksum = "05f33972566adbd2d3588b0491eb94b98b43695c4ef897903470ede4f3f5a28a" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" +checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" dependencies = [ "proc-macro2", "quote", diff --git a/Dockerfile b/Dockerfile index cf874b777b..a1efc62d32 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# Standalone build # https://github.com/paritytech/substrate/blob/master/.maintain/Dockerfile FROM phusion/baseimage:0.10.2 as build @@ -18,24 +19,20 @@ RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ rustup toolchain install ${TOOLCHAIN} && \ rustup target add wasm32-unknown-unknown --toolchain ${TOOLCHAIN} && \ rustup default ${TOOLCHAIN} && \ - rustup default stable && \ cargo build "--$PROFILE" -FROM phusion/baseimage:0.10.2 +FROM bitnami/minideb:stretch ARG PROFILE=release COPY --from=build /src/target/$PROFILE/btc-parachain /usr/local/bin # Checks -RUN ldd /usr/local/bin/btc-parachain && \ +RUN chmod +x /usr/local/bin/btc-parachain && \ + ldd /usr/local/bin/btc-parachain && \ /usr/local/bin/btc-parachain --version -# Shrinking -RUN rm -rf /usr/lib/python* && \ - rm -rf /usr/bin /usr/sbin /usr/share/man - EXPOSE 30333 9933 9944 VOLUME ["/data"] -CMD ["/usr/local/bin/btc-parachain"] \ No newline at end of file +CMD ["/usr/local/bin/btc-parachain"] diff --git a/Dockerfile_release b/Dockerfile_release new file mode 100644 index 0000000000..661dd642fe --- /dev/null +++ b/Dockerfile_release @@ -0,0 +1,15 @@ +FROM bitnami/minideb:buster + +ARG PROFILE=release + +COPY target/${PROFILE}/btc-parachain /usr/local/bin + +# Checks +RUN chmod +x /usr/local/bin/btc-parachain && \ + ldd /usr/local/bin/btc-parachain && \ + /usr/local/bin/btc-parachain --version + +EXPOSE 30333 9933 9944 +VOLUME ["/data"] + +CMD ["/usr/local/bin/btc-parachain"] diff --git a/README.md b/README.md index a9bad62bc4..1a185c16d1 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,6 @@ The Substrate runtime makes use of various custom pallets and crates that are fo - [collateral](crates/collateral) [Alpha] Handles locking, releasing and slashing of collateral (e.g. DOT). - [exchange-rate-oracle](crates/exchange-rate-oracle): [Alpha] Exchange rate oracle. Integration with external provider pending. - [issue](crates/issue): [Alpha] Handles issuing of PolkaBTC. -- [priority-map](crates/priority-map): [WIP] Priority queue based on a mapping. Used to efficiently track ongoing forks and handle re-orgs. - [redeem](crates/redeem) [Alpha] Handles redeeming of PolkaBTC for BTC on Bitcoin. - [replace](crates/replace) [Alpha] Handles replacing vaults. - [security](crates/security): [Alpha] Security module, handling BTC Parachain status changes (error handling). @@ -124,6 +123,27 @@ cargo cov test cargo cov report --open ``` +### Running + +To run a local development node, use the `dev` chain spec. + +```shell +cargo run --release -- --dev +``` + +Clear the database using the `purge-chain` command. + +```shell +cargo run --release -- purge-chain --dev +``` + +To disable all btc-relay block inclusion checks, use the special `dev-no-btc` chain spec. +This is useful for testing without the overhead of running a block relayer. + +```shell +cargo run --release -- --chain dev-no-btc +``` + #### Test coverage Test coverage reports available under [docs/testcoverage.html](https://gitlab.com/interlay/btc-parachain/-/blob/dev/docs/testcoverage.html) diff --git a/crates/README.md b/crates/README.md index 0e4854b509..1c66123ab2 100644 --- a/crates/README.md +++ b/crates/README.md @@ -15,5 +15,4 @@ We are writing our own pallets to allow trustless issue and redeem of Bitcoin on We are also adding crates for helpers and libraries that can be used from within our pallets, but don't represent a runtime pallet. - Bitcoin: Bitcoin type, parsing and verification functions [bitcoin](./bitcoin) -- Priority-map: a WIP for a priority queue based on a mapping [priority-map](./priority-map) -- X-Core: Error types used across modules [x-core](./x-core) +- X-Core: Error types used across modules [x-core](./x-core) diff --git a/crates/bitcoin/Cargo.toml b/crates/bitcoin/Cargo.toml index 6a9a66ae48..9a2733ed7d 100644 --- a/crates/bitcoin/Cargo.toml +++ b/crates/bitcoin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = 'bitcoin' -version = '0.1.1' +version = '0.2.3' authors = ['Interlay Ltd '] edition = '2018' @@ -22,19 +22,19 @@ features= ['codec'] [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sha2] default-features = false -version = '0.8.1' +version = "0.8.2" [dependencies.hex] default-features = false diff --git a/crates/bitcoin/src/formatter.rs b/crates/bitcoin/src/formatter.rs index 85027f33bb..f0b10c9db3 100644 --- a/crates/bitcoin/src/formatter.rs +++ b/crates/bitcoin/src/formatter.rs @@ -425,6 +425,17 @@ mod tests { assert_eq!(result, expected); } + #[test] + fn test_format_u256_testnet() { + // 0xb8e4a3e93640d7a4623e92589e40960b4b20420478d7ed60662176c323cf4caa + let value = + U256::from_dec_str("1260618571951953247774709397757627131971305851995253681160192") + .unwrap(); + let result = value.format(); + let expected = hex::decode("d4c8001a").unwrap(); + assert_eq!(result, expected); + } + const PROOF_HEX: &str = "00004020e2ac770a4f511b7ed2f3b638fe12d39ff52b8ced104d360500000000000000006f5ca47842fdd12f46a274ce7060c701d0c1fcff294a826e19b88e8f3dcdbca8f560135e8b64051816587c9c1f0100000bc21da39408e165a8368a7df46a17af25b4c5e3778b45222e48da632412b3be56e3b1196586e514fba3145219e3d9edb1e0e2c71b4cedaf013d8512d121f55e1ae120e954338e4d63d0a446a466b4ec548704366a89c2513c0c47818e4f8af8fa141bcda354451c2a48425704decd178df3c2c518c2fee2a593058b2c2c2ddee80ebc68aa38c161fcbf32f336b9d06feb652893be3326b0fd755cf61e575a56d7cb6b4944a2e74e3fdb583885c9dd4849ab2fd974207d9693a3062d9ba5eb0ea1b7c2d9841297396526c43af19fa8e67f3a6c07f9c8333eda575556df0e8b86a65982f24022336589fae3d56d69d73474024ced4f3a63c7205623d5bd22daf8a58e69b4748539fcdc24e0241f8231278b560340a3eb112f2fd041dc7bd1a0f6ddc37b916c24b0f96a1e9e13b4ffc7ad9c3805cadb91520435821edd439ca70198c92187deb1dde075366006d963632a0fd1ca510b362bbd6cf1805ac70becd3d303ff2d00"; #[test] diff --git a/crates/bitcoin/src/merkle.rs b/crates/bitcoin/src/merkle.rs index 228e0fa044..6d3d15dc9f 100644 --- a/crates/bitcoin/src/merkle.rs +++ b/crates/bitcoin/src/merkle.rs @@ -155,17 +155,17 @@ impl MerkleProof { let mut proof_parser = BytesParser::new(merkle_proof); let block_header = proof_parser.parse()?; let transactions_count = proof_parser.parse()?; - let hashes: Vec = proof_parser.parse()?; - let flag_bits_count: CompactUint = proof_parser.parse()?; - let mut bytes: Vec = Vec::new(); - for _ in 0..flag_bits_count.value { - bytes.push(proof_parser.parse()?); + let hashes_count: CompactUint = proof_parser.parse()?; + let mut hashes = Vec::::new(); + for _ in 0..hashes_count.value { + hashes.push(proof_parser.parse()?); } - let mut flag_bits: Vec = vec![false; bytes.len() * 8]; - for (p, bit) in flag_bits.iter_mut().enumerate() { - *bit = (bytes[p / 8] & (1 << (p % 8) as u8)) != 0; + let flag_bits_count: CompactUint = proof_parser.parse()?; + let mut flag_bits = Vec::new(); + for _ in 0..flag_bits_count.value { + flag_bits.extend(proof_parser.parse::>()?); } Ok(MerkleProof { diff --git a/crates/btc-relay/Cargo.toml b/crates/btc-relay/Cargo.toml index 6fea8f2bdf..af59fe2b8b 100644 --- a/crates/btc-relay/Cargo.toml +++ b/crates/btc-relay/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "btc-relay" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" @@ -17,28 +17,28 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.timestamp] default-features = false package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.primitive-types] default-features = false @@ -57,15 +57,22 @@ path = '../security' default-features = false version = '0.4.2' +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true + [dev-dependencies] mocktopus = '0.7.0' +frame-benchmarking = { version = "2.0.0" } [dev-dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [features] default = ['std'] +no-btc = [] std = [ 'serde', 'codec/std', @@ -79,4 +86,10 @@ std = [ 'bitcoin/std', 'security/std', 'hex/std', + 'frame-benchmarking/std', +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] diff --git a/crates/btc-relay/src/benchmarking.rs b/crates/btc-relay/src/benchmarking.rs new file mode 100644 index 0000000000..4579c16bcd --- /dev/null +++ b/crates/btc-relay/src/benchmarking.rs @@ -0,0 +1,186 @@ +use super::*; +use crate::Module as BtcRelay; +use bitcoin::formatter::Formattable; +use bitcoin::types::{ + Address, Block, BlockBuilder, RawBlockHeader, Transaction, TransactionBuilder, + TransactionInputBuilder, TransactionOutput, +}; +use frame_benchmarking::{account, benchmarks}; +use frame_system::Module as System; +use frame_system::RawOrigin; +use sp_core::{H256, U256}; +use sp_std::prelude::*; + +fn mine_genesis(address: &Address, height: u32) -> Block { + let block = BlockBuilder::new() + .with_version(2) + .with_coinbase(address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_initialize(block_header, height).unwrap(); + + block +} + +fn mine_block_with_one_tx( + prev: Block, + address: &Address, + value: i32, + op_return: &[u8], +) -> (Block, Transaction) { + let prev_block_hash = prev.header.hash(); + + let transaction = TransactionBuilder::new() + .with_version(2) + .add_input( + TransactionInputBuilder::new() + .with_coinbase(false) + .with_previous_hash(prev.transactions[0].hash()) + .build(), + ) + .add_output(TransactionOutput::p2pkh(value.into(), address)) + .add_output(TransactionOutput::op_return(0, op_return)) + .build(); + + let block = BlockBuilder::new() + .with_previous_hash(prev_block_hash) + .with_version(2) + .with_coinbase(address, 50, 3) + .with_timestamp(1588813835) + .add_transaction(transaction.clone()) + .mine(U256::from(2).pow(254.into())); + + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_store_block_header(block_header).unwrap(); + + (block, transaction) +} + +benchmarks! { + _ {} + + initialize { + let height = 0; + let origin: T::AccountId = account("Origin", 0, 0); + + let address = Address::from([0; 20]); + let block = BlockBuilder::new() + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + + }: _(RawOrigin::Signed(origin), block_header, height.into()) + verify { + assert_eq!(BestBlockHeight::get(), height); + } + + store_block_header { + let origin: T::AccountId = account("Origin", 0, 0); + + let address = Address::from([0; 20]); + + let height = 0; + let confirmations = 6; + + let init_block = BlockBuilder::new() + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + + let init_block_hash = init_block.header.hash(); + let raw_block_header = RawBlockHeader::from_bytes(&init_block.header.format()) + .expect("could not serialize block header"); + + BtcRelay::::_initialize(raw_block_header, height).unwrap(); + + let block = BlockBuilder::new() + .with_previous_hash(init_block_hash) + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588814835) + .mine(U256::from(2).pow(254.into())); + + let raw_block_header = RawBlockHeader::from_bytes(&block.header.format()) + .expect("could not serialize block header"); + + }: _(RawOrigin::Signed(origin), raw_block_header) + + verify_and_validate_transaction { + let origin: T::AccountId = account("Origin", 0, 0); + + let address = Address::from([0; 20]); + let mut height = 0; + let block = mine_genesis::(&address, height); + height += 1; + + let value = 0; + let op_return = H256::zero().as_bytes().to_vec(); + let (block, transaction) = mine_block_with_one_tx::(block, &address, value, &op_return); + + let tx_id = transaction.tx_id(); + let tx_block_height = height; + let proof = block.merkle_proof(&vec![tx_id]).format(); + let raw_tx = transaction.format_with(true); + + System::::set_block_number(100.into()); + + }: _(RawOrigin::Signed(origin), tx_id, proof, 0, true, raw_tx, value.into(), address.as_bytes().to_vec(), op_return) + + verify_transaction_inclusion { + let origin: T::AccountId = account("Origin", 0, 0); + + let address = Address::from([0; 20]); + let mut height = 0; + let block = mine_genesis::(&address, height); + height += 1; + + let value = 0; + let op_return = H256::zero().as_bytes().to_vec(); + let (block, transaction) = mine_block_with_one_tx::(block, &address, value, &op_return); + + let tx_id = transaction.tx_id(); + let tx_block_height = height; + let proof = block.merkle_proof(&vec![tx_id]).format(); + + System::::set_block_number(100.into()); + + }: _(RawOrigin::Signed(origin), tx_id, proof, 0, true) + + validate_transaction { + let origin: T::AccountId = account("Origin", 0, 0); + + let address = Address::from([0; 20]); + let value = 0; + let op_return = H256::zero().as_bytes().to_vec(); + + let block = mine_genesis::(&address, 0); + let (_, transaction) = mine_block_with_one_tx::(block, &address, value, &op_return); + + let raw_tx = transaction.format_with(true); + + }: _(RawOrigin::Signed(origin), raw_tx, value.into(), address.as_bytes().to_vec(), op_return) + +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_benchmarks() { + ExtBuilder::build().execute_with(|| { + assert_ok!(test_benchmark_initialize::()); + assert_ok!(test_benchmark_store_block_header::()); + assert_ok!(test_benchmark_verify_and_validate_transaction::()); + assert_ok!(test_benchmark_verify_transaction_inclusion::()); + assert_ok!(test_benchmark_validate_transaction::()); + }); + } +} diff --git a/crates/btc-relay/src/default_weights.rs b/crates/btc-relay/src/default_weights.rs new file mode 100644 index 0000000000..1c95baf005 --- /dev/null +++ b/crates/btc-relay/src/default_weights.rs @@ -0,0 +1,28 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + fn initialize() -> Weight { + (56_974_000 as Weight) + .saturating_add(DbWeight::get().reads(1 as Weight)) + .saturating_add(DbWeight::get().writes(7 as Weight)) + } + fn store_block_header() -> Weight { + (113_143_000 as Weight) + .saturating_add(DbWeight::get().reads(6 as Weight)) + .saturating_add(DbWeight::get().writes(6 as Weight)) + } + fn verify_and_validate_transaction() -> Weight { + (125_227_000 as Weight).saturating_add(DbWeight::get().reads(7 as Weight)) + } + fn verify_transaction_inclusion() -> Weight { + (68_197_000 as Weight).saturating_add(DbWeight::get().reads(7 as Weight)) + } + fn validate_transaction() -> Weight { + (9_131_000 as Weight) + } +} diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index bc276ed6a1..3d08ed062b 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -8,6 +8,11 @@ // Substrate mod ext; +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] mod tests; @@ -21,6 +26,7 @@ extern crate mocktopus; use mocktopus::macros::mockable; use frame_support::debug; +use frame_support::weights::Weight; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::{DispatchError, DispatchResult}, @@ -42,6 +48,14 @@ use bitcoin::types::{ use bitcoin::Error as BitcoinError; use security::types::ErrorCode; +pub trait WeightInfo { + fn initialize() -> Weight; + fn store_block_header() -> Weight; + fn verify_and_validate_transaction() -> Weight; + fn verify_transaction_inclusion() -> Weight; + fn validate_transaction() -> Weight; +} + /// ## Configuration and Constants /// The pallet's configuration trait. /// For further reference, see: @@ -49,6 +63,9 @@ use security::types::ErrorCode; pub trait Trait: frame_system::Trait + security::Trait { /// The overarching event type. type Event: From + Into<::Event>; + + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; } /// Difficulty Adjustment Interval @@ -82,7 +99,7 @@ pub const ACCEPTED_NO_TRANSACTION_OUTPUTS: u32 = 2; // This pallet's storage items. decl_storage! { trait Store for Module as BTCRelay { - /// ## Storage + /// ## Storage /// Store Bitcoin block headers BlockHeaders: map hasher(blake2_128_concat) H256Le => RichBlockHeader; @@ -114,10 +131,29 @@ decl_storage! { StableParachainConfirmations get(fn parachain_confirmations) config(): T::BlockNumber; /// Whether the module should perform difficulty checks. - DifficultyCheck get(fn difficulty_check) config(): bool; + DisableDifficultyCheck get(fn disable_difficulty_check) config(): bool; + + /// Whether the module should perform inclusion checks. + DisableInclusionCheck get(fn disable_inclusion_check) config(): bool; + + /// Whether the module should perform OP_RETURN checks. + DisableOpReturnCheck get(fn disable_op_return_check) config(): bool; } } +macro_rules! extract_op_return { + ($($tx:expr),*) => { + { + $( + if let Ok(data) = $tx.script.extract_op_return_data() { + data + } else + )* + { return Err(Error::::NotOpReturn.into()); } + } + }; +} + decl_module! { pub struct Module for enum Call where origin: T::Origin { // Initialize errors @@ -132,7 +168,7 @@ decl_module! { /// * `block_header_bytes` - 80 byte raw Bitcoin block header. /// * `block_height` - Bitcoin block height of the submitted /// block header. - #[weight = 1000] + #[weight = ::WeightInfo::initialize()] fn initialize( origin, raw_block_header: RawBlockHeader, @@ -140,46 +176,7 @@ decl_module! { -> DispatchResult { let _ = ensure_signed(origin)?; - - // Check if BTC-Relay was already initialized - ensure!(!Self::best_block_exists(), Error::::AlreadyInitialized); - - // Parse the block header bytes to extract the required info - let basic_block_header = parse_block_header(&raw_block_header)?; - let block_header_hash = raw_block_header.hash(); - - // construct the BlockChain struct - let blockchain = Self::initialize_blockchain( - block_height, block_header_hash); - // Create rich block header - let block_header = RichBlockHeader { - block_hash: block_header_hash, - block_header: basic_block_header, - block_height: block_height, - chain_ref: blockchain.chain_id - }; - - // Store a new BlockHeader struct in BlockHeaders - Self::set_block_header_from_hash(block_header_hash, &block_header); - - // Store a pointer to BlockChain in ChainsIndex - Self::set_block_chain_from_id( - MAIN_CHAIN_ID, &blockchain); - - // Store the reference to the new BlockChain in Chains - Self::set_chain_from_position_and_id(0, MAIN_CHAIN_ID); - - // Set BestBlock and BestBlockHeight to the submitted block - Self::set_best_block(block_header_hash); - Self::set_best_block_height(block_height); - - // Emit a Initialized Event - Self::deposit_event(Event::Initialized( - block_height, block_header_hash - ) - ); - - Ok(()) + Self::_initialize(raw_block_header, block_height) } /// Stores a single new block header @@ -187,111 +184,12 @@ decl_module! { /// # Arguments /// /// * `raw_block_header` - 80 byte raw Bitcoin block header. - #[weight = 1000] + #[weight = ::WeightInfo::store_block_header()] fn store_block_header( origin, raw_block_header: RawBlockHeader ) -> DispatchResult { let _ = ensure_signed(origin)?; - // Make sure Parachain is not shutdown - ext::security::ensure_parachain_status_not_shutdown::()?; - - // Parse the block header bytes to extract the required info - let basic_block_header = Self::verify_block_header(&raw_block_header)?; - let block_header_hash = raw_block_header.hash(); - - let prev_header = Self::get_block_header_from_hash( - basic_block_header.hash_prev_block - )?; - - // get the block chain of the previous header - let prev_blockchain = Self::get_block_chain_from_id( - prev_header.chain_ref - )?; - - // Update the current block header - // check if the prev block is the highest block in the chain - // load the previous block header block height - let prev_block_height = prev_header.block_height; - - // update the current block header with height and chain ref - // Set the height of the block header - let current_block_height = prev_block_height + 1; - - // Update the blockchain - // check if we create a new blockchain or extend the existing one - debug::print!("Prev max height: {:?}\n", prev_blockchain.max_height); - debug::print!("Prev block height: {:?}\n", prev_block_height); - let is_fork = prev_blockchain.max_height != prev_block_height; - debug::print!("Fork detected: {:?}\n", is_fork); - - let blockchain = if is_fork { - // create new blockchain element - Self::create_blockchain(current_block_height, block_header_hash) - } else { - // extend the current chain - Self::extend_blockchain( - current_block_height, &block_header_hash, prev_blockchain)? - }; - - // Create rich block header - let block_header = RichBlockHeader { - block_hash: block_header_hash, - block_header: basic_block_header, - block_height: current_block_height, - chain_ref: blockchain.chain_id - }; - - - // Store a new BlockHeader struct in BlockHeaders - Self::set_block_header_from_hash(block_header_hash, &block_header); - - // Storing the blockchain depends if we extend or create a new chain - if is_fork { - // create a new chain - // Store a pointer to BlockChain in ChainsIndex - Self::set_block_chain_from_id(blockchain.chain_id, &blockchain); - // Store the reference to the blockchain in Chains - Self::insert_sorted(&blockchain)?; - } else { - // extended the chain - // Update the pointer to BlockChain in ChainsIndex - ::mutate(blockchain.chain_id, |_b| &blockchain); - - // check if ordering of Chains needs updating - Self::check_and_do_reorg(&blockchain)?; - - if blockchain.chain_id == MAIN_CHAIN_ID { - Self::set_best_block(block_header_hash); - Self::set_best_block_height(current_block_height) - } - }; - - // Determine if this block extends the main chain or a fork - let current_best_block = Self::get_best_block(); - - // print!("Best block hash: {:?} \n", current_best_block); - // print!("Current block hash: {:?} \n", block_header_hash); - if current_best_block == block_header_hash { - // extends the main chain - Self::deposit_event( - Event::StoreMainChainHeader( - current_block_height, - block_header_hash - ) - ); - } else { - // created a new fork or updated an existing one - Self::deposit_event( - Event::StoreForkHeader( - blockchain.chain_id, - current_block_height, - block_header_hash - ) - ); - }; - - - Ok(()) + Self::_store_block_header(raw_block_header) } /// Verifies the inclusion of `tx_id` in block at height `tx_block_height` and validates the given raw Bitcoin transaction, according to the @@ -315,7 +213,7 @@ decl_module! { /// of the BTC in the 1st / payment UTXO /// * `op_return_id` - 32 byte hash identifier expected in /// OP_RETURN (replay protection) - #[weight = 1000] + #[weight = ::WeightInfo::verify_and_validate_transaction()] fn verify_and_validate_transaction( origin, tx_id: H256Le, @@ -329,7 +227,6 @@ decl_module! { -> DispatchResult { let _ = ensure_signed(origin)?; - let transaction = Self::parse_transaction(&raw_tx)?; // Check that the passed raw_tx indeed matches the tx_id used for @@ -357,7 +254,7 @@ decl_module! { /// * `confirmations` - The number of confirmations needed to accept /// the proof /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` - #[weight = 1000] + #[weight = ::WeightInfo::verify_transaction_inclusion()] fn verify_transaction_inclusion( origin, tx_id: H256Le, @@ -366,7 +263,6 @@ decl_module! { insecure: bool) -> DispatchResult { let _ = ensure_signed(origin)?; - Self::_verify_transaction_inclusion(tx_id, raw_merkle_proof, confirmations, insecure)?; Ok(()) } @@ -387,7 +283,7 @@ decl_module! { /// of the BTC in the 1st / payment UTXO /// * `op_return_id` - 32 byte hash identifier expected in /// OP_RETURN (replay protection) - #[weight = 1000] + #[weight = ::WeightInfo::validate_transaction()] fn validate_transaction( origin, raw_tx: Vec, @@ -404,12 +300,145 @@ decl_module! { #[cfg_attr(test, mockable)] impl Module { + pub fn _initialize(raw_block_header: RawBlockHeader, block_height: u32) -> DispatchResult { + // Check if BTC-Relay was already initialized + ensure!(!Self::best_block_exists(), Error::::AlreadyInitialized); + + // Parse the block header bytes to extract the required info + let basic_block_header = parse_block_header(&raw_block_header)?; + let block_header_hash = raw_block_header.hash(); + + // construct the BlockChain struct + let blockchain = Self::initialize_blockchain(block_height, block_header_hash); + // Create rich block header + let block_header = RichBlockHeader { + block_hash: block_header_hash, + block_header: basic_block_header, + block_height: block_height, + chain_ref: blockchain.chain_id, + }; + + // Store a new BlockHeader struct in BlockHeaders + Self::set_block_header_from_hash(block_header_hash, &block_header); + + // Store a pointer to BlockChain in ChainsIndex + Self::set_block_chain_from_id(MAIN_CHAIN_ID, &blockchain); + + // Store the reference to the new BlockChain in Chains + Self::set_chain_from_position_and_id(0, MAIN_CHAIN_ID); + + // Set BestBlock and BestBlockHeight to the submitted block + Self::set_best_block(block_header_hash); + Self::set_best_block_height(block_height); + + // Emit a Initialized Event + Self::deposit_event(Event::Initialized(block_height, block_header_hash)); + + Ok(()) + } + + pub fn _store_block_header(raw_block_header: RawBlockHeader) -> DispatchResult { + // Make sure Parachain is not shutdown + ext::security::ensure_parachain_status_not_shutdown::()?; + + // Parse the block header bytes to extract the required info + let basic_block_header = Self::verify_block_header(&raw_block_header)?; + let block_header_hash = raw_block_header.hash(); + + let prev_header = Self::get_block_header_from_hash(basic_block_header.hash_prev_block)?; + + // get the block chain of the previous header + let prev_blockchain = Self::get_block_chain_from_id(prev_header.chain_ref)?; + + // Update the current block header + // check if the prev block is the highest block in the chain + // load the previous block header block height + let prev_block_height = prev_header.block_height; + + // update the current block header with height and chain ref + // Set the height of the block header + let current_block_height = prev_block_height + 1; + + // Update the blockchain + // check if we create a new blockchain or extend the existing one + debug::print!("Prev max height: {:?}\n", prev_blockchain.max_height); + debug::print!("Prev block height: {:?}\n", prev_block_height); + let is_fork = prev_blockchain.max_height != prev_block_height; + debug::print!("Fork detected: {:?}\n", is_fork); + + let blockchain = if is_fork { + // create new blockchain element + Self::create_blockchain(current_block_height, block_header_hash) + } else { + // extend the current chain + Self::extend_blockchain(current_block_height, &block_header_hash, prev_blockchain)? + }; + + // Create rich block header + let block_header = RichBlockHeader { + block_hash: block_header_hash, + block_header: basic_block_header, + block_height: current_block_height, + chain_ref: blockchain.chain_id, + }; + + // Store a new BlockHeader struct in BlockHeaders + Self::set_block_header_from_hash(block_header_hash, &block_header); + + // Storing the blockchain depends if we extend or create a new chain + if is_fork { + // create a new chain + // Store a pointer to BlockChain in ChainsIndex + Self::set_block_chain_from_id(blockchain.chain_id, &blockchain); + // Store the reference to the blockchain in Chains + Self::insert_sorted(&blockchain)?; + } else { + // extended the chain + // Update the pointer to BlockChain in ChainsIndex + ::mutate(blockchain.chain_id, |_b| &blockchain); + + // check if ordering of Chains needs updating + Self::check_and_do_reorg(&blockchain)?; + + if blockchain.chain_id == MAIN_CHAIN_ID { + Self::set_best_block(block_header_hash); + Self::set_best_block_height(current_block_height) + } + }; + + // Determine if this block extends the main chain or a fork + let current_best_block = Self::get_best_block(); + + // print!("Best block hash: {:?} \n", current_best_block); + // print!("Current block hash: {:?} \n", block_header_hash); + if current_best_block == block_header_hash { + // extends the main chain + Self::deposit_event(Event::StoreMainChainHeader( + current_block_height, + block_header_hash, + )); + } else { + // created a new fork or updated an existing one + Self::deposit_event(Event::StoreForkHeader( + blockchain.chain_id, + current_block_height, + block_header_hash, + )); + }; + + Ok(()) + } + pub fn _verify_transaction_inclusion( tx_id: H256Le, raw_merkle_proof: Vec, confirmations: u32, insecure: bool, ) -> Result<(), DispatchError> { + if Self::disable_inclusion_check() { + return Ok(()); + } + let best_block_height = Self::get_best_block_height(); Self::ensure_no_ongoing_fork(best_block_height)?; @@ -453,6 +482,102 @@ impl Module { Ok(()) } + fn extract_value( + transaction: Transaction, + recipient_btc_address: Vec, + ) -> Result> { + // Check if payment is first output + match transaction.outputs[0].extract_address() { + Ok(extr_recipient_btc_address) => { + if recipient_btc_address == extr_recipient_btc_address { + return Ok(transaction.outputs[0].value); + } + } + Err(_) => (), + }; + + // Check if payment is second output + match transaction.outputs[1].extract_address() { + Ok(extr_recipient_btc_address) => { + if recipient_btc_address == extr_recipient_btc_address { + return Ok(transaction.outputs[1].value); + } + } + Err(_) => (), + }; + + // Check if payment is third output + match transaction.outputs[2].extract_address() { + Ok(extr_recipient_btc_address) => { + if recipient_btc_address == extr_recipient_btc_address { + return Ok(transaction.outputs[2].value); + } + } + Err(_) => (), + }; + + // Payment UTXO sends to incorrect address + Err(Error::::WrongRecipient) + } + + fn extract_value_and_op_return( + transaction: Transaction, + recipient_btc_address: Vec, + ) -> Result<(i64, Vec), Error> { + ensure!( + // We would typically expect three outputs (payment, op_return, refund) but + // exceptionally the input amount may be exact so we would only require two + transaction.outputs.len() >= ACCEPTED_MIN_TRANSACTION_OUTPUTS as usize, + Error::::MalformedTransaction + ); + + // Check if payment is first output + match transaction.outputs[0].extract_address() { + Ok(extr_recipient_btc_address) => { + if recipient_btc_address == extr_recipient_btc_address { + return Ok(( + transaction.outputs[0].value, + extract_op_return!(transaction.outputs[1], transaction.outputs[2]), + )); + } + } + Err(_) => (), + }; + + // Check if payment is second output + match transaction.outputs[1].extract_address() { + Ok(extr_recipient_btc_address) => { + if recipient_btc_address == extr_recipient_btc_address { + return Ok(( + transaction.outputs[1].value, + extract_op_return!(transaction.outputs[0], transaction.outputs[2]), + )); + } + } + Err(_) => (), + }; + + // Check if payment is third output + match transaction.outputs[2].extract_address() { + Ok(extr_recipient_btc_address) => { + if recipient_btc_address == extr_recipient_btc_address { + return Ok(( + transaction.outputs[2].value, + extract_op_return!(transaction.outputs[0], transaction.outputs[1]), + )); + } + } + Err(_) => (), + }; + + // Payment UTXO sends to incorrect address + Err(Error::::WrongRecipient) + } + + pub fn is_op_return_disabled() -> bool { + Self::disable_op_return_check() + } + pub fn _validate_transaction( raw_tx: Vec, payment_value: i64, @@ -461,29 +586,18 @@ impl Module { ) -> Result<(), DispatchError> { let transaction = Self::parse_transaction(&raw_tx)?; - ensure!( - transaction.outputs.len() >= ACCEPTED_MIN_TRANSACTION_OUTPUTS as usize, - Error::::MalformedTransaction - ); + let extr_payment_value = if Self::is_op_return_disabled() { + Self::extract_value(transaction, recipient_btc_address)? + } else { + // NOTE: op_return UTXO should not contain any value + let (extr_payment_value, extr_op_return) = + Self::extract_value_and_op_return(transaction, recipient_btc_address)?; - // NOTE: op_return UTXO should not contain any value - let (extr_payment_value, extr_recipient_address, extr_op_return) = - match transaction.outputs[0].extract_address() { - Ok(address) => ( - // 1) Payment Utxo - // 2) OpReturn Utxo - transaction.outputs[0].value, - address, - transaction.outputs[1].script.extract_op_return_data()?, - ), - Err(_) => ( - // 1) OpReturn Utxo - // 2) Payment Utxo - transaction.outputs[1].value, - transaction.outputs[1].extract_address()?, - transaction.outputs[0].script.extract_op_return_data()?, - ), - }; + // Check if data UTXO has correct OP_RETURN value + ensure!(extr_op_return == op_return_id, Error::::InvalidOpReturn); + + extr_payment_value + }; // Check if payment UTXO transfers sufficient value ensure!( @@ -491,15 +605,6 @@ impl Module { Error::::InsufficientValue ); - // Check payment UTXO sends to correct address - ensure!( - extr_recipient_address == recipient_btc_address, - Error::::WrongRecipient - ); - - // Check if data UTXO has correct OP_RETURN value - ensure!(extr_op_return == op_return_id, Error::::InvalidOpReturn); - Ok(()) } @@ -779,7 +884,7 @@ impl Module { // Check that the diff. target is indeed correctly set in the block header, i.e., check for re-target. let block_height = prev_block_header.block_height + 1; - if !Self::difficulty_check() { + if Self::disable_difficulty_check() { return Ok(basic_block_header); } diff --git a/crates/btc-relay/src/mock.rs b/crates/btc-relay/src/mock.rs index 91dbe023d7..e945864a91 100644 --- a/crates/btc-relay/src/mock.rs +++ b/crates/btc-relay/src/mock.rs @@ -69,7 +69,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = (); @@ -80,6 +80,7 @@ impl frame_system::Trait for Test { impl Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl security::Trait for Test { @@ -103,7 +104,9 @@ impl ExtBuilder { GenesisConfig:: { bitcoin_confirmations: BITCOIN_CONFIRMATIONS, parachain_confirmations: PARACHAIN_CONFIRMATIONS, - difficulty_check: true, + disable_difficulty_check: false, + disable_inclusion_check: false, + disable_op_return_check: false, } .assimilate_storage(&mut storage) .unwrap(); diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index c1ddfad220..adf01d67a8 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -786,6 +786,31 @@ fn test_verify_block_header_low_diff_fails() { }); } +#[test] +fn test_validate_transaction_succeeds_with_payment() { + run_test(|| { + let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); + let payment_value: i64 = 2500200000; + let recipient_btc_address = + hex::decode("66c7060feb882664ae62ffad0051fe843e318e85".to_owned()).unwrap(); + + let outputs = vec![sample_valid_payment_output()]; + + BTCRelay::parse_transaction + .mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + + BTCRelay::is_op_return_disabled.mock_safe(move || MockResult::Return(true)); + + assert_ok!(BTCRelay::validate_transaction( + Origin::signed(3), + raw_tx, + payment_value, + recipient_btc_address, + vec![] + )); + }); +} + #[test] fn test_validate_transaction_succeeds_with_payment_and_op_return() { run_test(|| { @@ -840,6 +865,37 @@ fn test_validate_transaction_succeeds_with_op_return_and_payment() { }); } +#[test] +fn test_validate_transaction_succeeds_with_payment_and_refund_and_op_return() { + run_test(|| { + let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); + let payment_value: i64 = 2500200000; + let recipient_btc_address = + hex::decode("66c7060feb882664ae62ffad0051fe843e318e85".to_owned()).unwrap(); + let op_return_id = hex::decode( + "aa21a9ede5c17d15b8b1fa2811b7e6da66ffa5e1aaa05922c69068bf90cd585b95bb4675".to_owned(), + ) + .unwrap(); + + let outputs = vec![ + sample_valid_payment_output(), + sample_wrong_recipient_payment_output(), + sample_valid_data_output(), + ]; + + BTCRelay::parse_transaction + .mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + + assert_ok!(BTCRelay::validate_transaction( + Origin::signed(3), + raw_tx, + payment_value, + recipient_btc_address, + op_return_id + )); + }); +} + #[test] fn test_validate_transaction_invalid_no_outputs_fails() { run_test(|| { @@ -922,6 +978,7 @@ fn test_validate_transaction_wrong_recipient_fails() { .unwrap(); let outputs = vec![ + sample_wrong_recipient_payment_output(), sample_wrong_recipient_payment_output(), sample_valid_data_output(), ]; diff --git a/crates/collateral/Cargo.toml b/crates/collateral/Cargo.toml index 39e1602838..47cb6211b3 100644 --- a/crates/collateral/Cargo.toml +++ b/crates/collateral/Cargo.toml @@ -4,7 +4,7 @@ description = 'Collateral module' edition = '2018' homepage = 'https://interlay.gitlab.io/polkabtc-spec/spec/collateral.html' name = 'collateral' -version = '2.0.0-rc6' +version = '0.2.3' [dependencies.serde] version = '1.0.101' @@ -19,27 +19,27 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dev-dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dev-dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dev-dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [features] default = ['std'] diff --git a/crates/collateral/src/mock.rs b/crates/collateral/src/mock.rs index 7e9a2c6be0..e6f19fbeb2 100644 --- a/crates/collateral/src/mock.rs +++ b/crates/collateral/src/mock.rs @@ -68,7 +68,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -79,8 +79,11 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } + impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); diff --git a/crates/exchange-rate-oracle/Cargo.toml b/crates/exchange-rate-oracle/Cargo.toml index b946ae8b31..dc8afd40fd 100644 --- a/crates/exchange-rate-oracle/Cargo.toml +++ b/crates/exchange-rate-oracle/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "exchange-rate-oracle" -version = "2.0.0-rc6" +version = '0.2.4' authors = ["Interlay Ltd"] edition = "2018" @@ -20,7 +20,18 @@ std = [ 'collateral/std', 'treasury/std', 'security/std', + 'frame-benchmarking/std', ] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] + +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true [dependencies.serde] version = '1.0.101' @@ -35,37 +46,37 @@ version = '1.3.4' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.timestamp] default-features = false package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false package = 'pallet-balances' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.collateral] default-features = false @@ -81,3 +92,4 @@ path = '../security' [dev-dependencies] mocktopus = "0.7.0" +frame-benchmarking = { version = "2.0.0" } diff --git a/crates/exchange-rate-oracle/rpc/Cargo.toml b/crates/exchange-rate-oracle/rpc/Cargo.toml index f2a912ff22..a0b0802882 100644 --- a/crates/exchange-rate-oracle/rpc/Cargo.toml +++ b/crates/exchange-rate-oracle/rpc/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "module-exchange-rate-oracle-rpc" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" [dependencies] serde = { version = "1.0.101", features = ["derive"] } codec = { package = "parity-scale-codec", version = '1.3.4' } -jsonrpc-core = "14.0.5" -jsonrpc-core-client = "14.0.5" -jsonrpc-derive = "14.0.5" -sp-runtime = { version = "2.0.0-rc6" } -sp-api = { version = "2.0.0-rc6" } -sp-blockchain = { version = "2.0.0-rc6" } +jsonrpc-core = "15.0.0" +jsonrpc-core-client = "15.0.0" +jsonrpc-derive = "15.0.0" +sp-runtime = { version = "2.0.0" } +sp-api = { version = "2.0.0" } +sp-blockchain = { version = "2.0.0" } module-exchange-rate-oracle-rpc-runtime-api = { path = "runtime-api" } diff --git a/crates/exchange-rate-oracle/rpc/runtime-api/Cargo.toml b/crates/exchange-rate-oracle/rpc/runtime-api/Cargo.toml index ee64233f3a..7dc87e74f6 100644 --- a/crates/exchange-rate-oracle/rpc/runtime-api/Cargo.toml +++ b/crates/exchange-rate-oracle/rpc/runtime-api/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "module-exchange-rate-oracle-rpc-runtime-api" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" [dependencies] codec = { package = "parity-scale-codec", version = '1.3.4', default-features = false, features = ["derive"] } -sp-api = { version = "2.0.0-rc6", default-features = false } -frame-support = { version = "2.0.0-rc6", default-features = false } +sp-api = { version = "2.0.0", default-features = false } +frame-support = { version = "2.0.0", default-features = false } [features] default = ["std"] diff --git a/crates/exchange-rate-oracle/src/benchmarking.rs b/crates/exchange-rate-oracle/src/benchmarking.rs new file mode 100644 index 0000000000..d1e572c377 --- /dev/null +++ b/crates/exchange-rate-oracle/src/benchmarking.rs @@ -0,0 +1,51 @@ +use super::*; +use frame_benchmarking::{account, benchmarks}; +use frame_system::RawOrigin; +use sp_std::prelude::*; + +benchmarks! { + _ {} + + set_exchange_rate { + let u in 0 .. 1000; + let origin: T::AccountId = account("origin", 0, 0); + >::set(origin.clone()); + }: _(RawOrigin::Signed(origin), u.into()) + verify { + assert_eq!(ExchangeRate::get(), u.into()); + } + + set_btc_tx_fees_per_byte { + let u in 0 .. 1000u32; + let origin: T::AccountId = account("origin", 0, 0); + >::set(origin.clone()); + }: _(RawOrigin::Signed(origin), 1 * u, 2 * u, 3 * u) + verify { + let readback = SatoshiPerBytes::get(); + + assert_eq!(readback.fast, 1 * u); + assert_eq!(readback.half, 2 * u); + assert_eq!(readback.hour, 3 * u); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_set_exchange_rate() { + ExtBuilder::build().execute_with(|| { + assert_ok!(test_benchmark_set_exchange_rate::()); + }); + } + + #[test] + fn test_set_btc_tx_fees_per_byte() { + ExtBuilder::build().execute_with(|| { + assert_ok!(test_benchmark_set_btc_tx_fees_per_byte::()); + }); + } +} diff --git a/crates/exchange-rate-oracle/src/default_weights.rs b/crates/exchange-rate-oracle/src/default_weights.rs new file mode 100644 index 0000000000..f4ff57f684 --- /dev/null +++ b/crates/exchange-rate-oracle/src/default_weights.rs @@ -0,0 +1,20 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + // WARNING! Some components were not used: ["u"] + fn set_exchange_rate() -> Weight { + (42_788_000 as Weight) + .saturating_add(DbWeight::get().reads(5 as Weight)) + .saturating_add(DbWeight::get().writes(2 as Weight)) + } + fn set_btc_tx_fees_per_byte() -> Weight { + (30_015_705 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(1 as Weight)) + } +} diff --git a/crates/exchange-rate-oracle/src/lib.rs b/crates/exchange-rate-oracle/src/lib.rs index e02ae9dc8a..771f6aeb69 100644 --- a/crates/exchange-rate-oracle/src/lib.rs +++ b/crates/exchange-rate-oracle/src/lib.rs @@ -2,8 +2,16 @@ #![cfg_attr(test, feature(proc_macro_hygiene))] #![cfg_attr(not(feature = "std"), no_std)] +/// # Exchange Rate Oracle implementation +/// This is the implementation of the Exchange Rate Oracle following the spec at: +/// https://interlay.gitlab.io/polkabtc-spec/spec/oracle.html mod ext; +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] mod tests; @@ -16,12 +24,10 @@ extern crate mocktopus; #[cfg(test)] use mocktopus::macros::mockable; +use codec::{Decode, Encode}; use frame_support::dispatch::{DispatchError, DispatchResult}; use frame_support::traits::Currency; -/// # Exchange Rate Oracle implementation -/// This is the implementation of the Exchange Rate Oracle following the spec at: -/// https://interlay.gitlab.io/polkabtc-spec/spec/oracle.html -// Substrate +use frame_support::weights::Weight; use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure}; use frame_system::ensure_signed; use sp_std::convert::TryInto; @@ -33,6 +39,11 @@ pub(crate) type DOT = pub(crate) type PolkaBTC = <::PolkaBTC as Currency<::AccountId>>::Balance; +pub trait WeightInfo { + fn set_exchange_rate() -> Weight; + fn set_btc_tx_fees_per_byte() -> Weight; +} + /// ## Configuration and Constants /// The pallet's configuration trait. pub trait Trait: @@ -40,11 +51,24 @@ pub trait Trait: { /// The overarching event type. type Event: From> + Into<::Event>; + + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; } /// Granularity of exchange rate pub const GRANULARITY: u128 = 5; +#[derive(Encode, Decode, Default)] +pub struct BtcTxFeesPerByte { + /// The estimated Satoshis per bytes to get included in the next block (~10 min) + pub fast: u32, + /// The estimated Satoshis per bytes to get included in the next 3 blocks (~half hour) + pub half: u32, + /// The estimated Satoshis per bytes to get included in the next 6 blocks (~hour) + pub hour: u32, +} + // This pallet's storage items. decl_storage! { trait Store for Module as ExchangeRateOracle { @@ -55,6 +79,8 @@ decl_storage! { /// Last exchange rate time LastExchangeRateTime: T::Moment; + SatoshiPerBytes get(fn satoshi_per_bytes): BtcTxFeesPerByte; + /// Maximum delay (milliseconds) for the exchange rate to be used MaxDelay get(fn max_delay) config(): T::Moment; @@ -71,7 +97,10 @@ decl_module! { // Initializing events fn deposit_event() = default; - #[weight = 1000] + // Errors must be initialized if they are used by the pallet. + type Error = Error; + + #[weight = ::WeightInfo::set_exchange_rate()] pub fn set_exchange_rate(origin, rate: u128) -> DispatchResult { // Check that Parachain is not in SHUTDOWN ext::security::ensure_parachain_status_not_shutdown::()?; @@ -87,6 +116,25 @@ decl_module! { Ok(()) } + + #[weight = ::WeightInfo::set_btc_tx_fees_per_byte()] + pub fn set_btc_tx_fees_per_byte(origin, fast: u32, half: u32, hour: u32) -> DispatchResult { + // Check that Parachain is not in SHUTDOWN + ext::security::ensure_parachain_status_not_shutdown::()?; + + let sender = ensure_signed(origin)?; + + // fail if the sender is not the authorized oracle + ensure!(sender == Self::get_authorized_oracle(), Error::::InvalidOracleSource); + + // write the new values to storage + let fees = BtcTxFeesPerByte{fast, half, hour}; + ::put(fees); + + Self::deposit_event(Event::::SetBtcTxFeesPerByte(sender, fast, half, hour)); + + Ok(()) + } } } @@ -195,6 +243,8 @@ decl_event! { AccountId = ::AccountId { /// Event emitted when exchange rate is set SetExchangeRate(AccountId, u128), + /// Event emitted when the btc tx fees are set + SetBtcTxFeesPerByte(AccountId, u32, u32, u32), } } diff --git a/crates/exchange-rate-oracle/src/mock.rs b/crates/exchange-rate-oracle/src/mock.rs index 65f6a0d0e1..3418d5b64a 100644 --- a/crates/exchange-rate-oracle/src/mock.rs +++ b/crates/exchange-rate-oracle/src/mock.rs @@ -70,7 +70,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -83,11 +83,11 @@ pub type Balances = pallet_balances::Module; impl Trait for Test { type Event = TestEvent; + type WeightInfo = (); } parameter_types! { pub const MinimumPeriod: u64 = 5; - pub const ExistentialDeposit: u64 = 1; } impl timestamp::Trait for Test { @@ -97,7 +97,13 @@ impl timestamp::Trait for Test { type WeightInfo = (); } +parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; +} + impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); diff --git a/crates/issue/Cargo.toml b/crates/issue/Cargo.toml index 60fed0da98..03afd4a2e4 100644 --- a/crates/issue/Cargo.toml +++ b/crates/issue/Cargo.toml @@ -3,7 +3,7 @@ authors = ['Interlay'] description = 'Issue module' edition = '2018' name = 'issue' -version = '2.0.0-rc6' +version = '0.2.3' [dependencies.serde] version = '1.0.101' @@ -18,32 +18,32 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false package = 'pallet-balances' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.primitive-types] default-features = false @@ -77,19 +77,25 @@ path = '../security' [dependencies.timestamp] default-features = false package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sha2] default-features = false version = '0.8.0' -[dev-dependencies] -mocktopus = '0.7.0' - -[dev-dependencies.exchange-rate-oracle] +[dependencies.exchange-rate-oracle] default-features = false path = '../exchange-rate-oracle' +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true + +[dev-dependencies] +mocktopus = '0.7.0' +frame-benchmarking = { version = "2.0.0" } + [features] default = ['std'] std = [ @@ -106,9 +112,16 @@ std = [ 'vault-registry/std', 'collateral/std', 'btc-relay/std', + 'exchange-rate-oracle/std', 'treasury/std', 'bitcoin/std', 'sha2/std', 'security/std', 'timestamp/std', + 'frame-benchmarking/std', ] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] \ No newline at end of file diff --git a/crates/issue/rpc/Cargo.toml b/crates/issue/rpc/Cargo.toml new file mode 100644 index 0000000000..6d4c69db4d --- /dev/null +++ b/crates/issue/rpc/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "module-issue-rpc" +version = '0.2.3' +authors = ["Interlay Ltd"] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", features = ["derive"] } +codec = { package = "parity-scale-codec", version = '1.3.4' } +jsonrpc-core = "15.0.0" +jsonrpc-core-client = "15.0.0" +jsonrpc-derive = "15.0.0" +sp-runtime = { version = "2.0.0" } +sp-api = { version = "2.0.0" } +sp-blockchain = { version = "2.0.0" } +module-issue-rpc-runtime-api = { path = "runtime-api" } diff --git a/crates/issue/rpc/runtime-api/Cargo.toml b/crates/issue/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..5c085f9e37 --- /dev/null +++ b/crates/issue/rpc/runtime-api/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "module-issue-rpc-runtime-api" +version = '0.2.3' +authors = ["Interlay Ltd"] +edition = "2018" + +[dependencies] +codec = { package = "parity-scale-codec", version = '1.3.4', default-features = false, features = ["derive"] } +sp-api = { version = "2.0.0", default-features = false } +frame-support = { version = "2.0.0", default-features = false } +sp-std = { version = "2.0.0", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", + "sp-std/std", + "frame-support/std", +] \ No newline at end of file diff --git a/crates/issue/rpc/runtime-api/src/lib.rs b/crates/issue/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..9ee1fe841b --- /dev/null +++ b/crates/issue/rpc/runtime-api/src/lib.rs @@ -0,0 +1,20 @@ +//! Runtime API definition for the Issue Module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use sp_std::vec::Vec; + +sp_api::decl_runtime_apis! { + pub trait IssueApi where + AccountId: Codec, + H256: Codec, + IssueRequest: Codec, + { + /// Get all issue requests for a particular account + fn get_issue_requests(account_id: AccountId) -> Vec<(H256, IssueRequest)>; + + /// Get all issue requests for a particular vault + fn get_vault_issue_requests(account_id: AccountId) -> Vec<(H256, IssueRequest)>; + } +} diff --git a/crates/issue/rpc/src/lib.rs b/crates/issue/rpc/src/lib.rs new file mode 100644 index 0000000000..b7f7625895 --- /dev/null +++ b/crates/issue/rpc/src/lib.rs @@ -0,0 +1,100 @@ +//! RPC interface for the Issue Module. + +use codec::Codec; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use std::sync::Arc; + +pub use self::gen_client::Client as IssueClient; +pub use module_issue_rpc_runtime_api::IssueApi as IssueRuntimeApi; + +#[rpc] +pub trait IssueApi { + #[rpc(name = "issue_getIssueRequests")] + fn get_issue_requests( + &self, + account_id: AccountId, + at: Option, + ) -> Result>; + + #[rpc(name = "issue_getVaultIssueRequests")] + fn get_vault_issue_requests( + &self, + account_id: AccountId, + at: Option, + ) -> Result>; +} + +/// A struct that implements the [`IssueApi`]. +pub struct Issue { + client: Arc, + _marker: std::marker::PhantomData, +} + +impl Issue { + /// Create new `Issue` with the given reference to the client. + pub fn new(client: Arc) -> Self { + Issue { + client, + _marker: Default::default(), + } + } +} + +pub enum Error { + RuntimeError, +} + +impl From for i64 { + fn from(e: Error) -> i64 { + match e { + Error::RuntimeError => 1, + } + } +} + +impl + IssueApi<::Hash, AccountId, H256, IssueRequest> for Issue +where + Block: BlockT, + C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: IssueRuntimeApi, + AccountId: Codec, + H256: Codec, + IssueRequest: Codec, +{ + fn get_issue_requests( + &self, + account_id: AccountId, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + api.get_issue_requests(&at, account_id) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to fetch issue requests.".into(), + data: Some(format!("{:?}", e).into()), + }) + } + + fn get_vault_issue_requests( + &self, + account_id: AccountId, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + api.get_vault_issue_requests(&at, account_id) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to fetch issue requests.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/crates/issue/src/benchmarking.rs b/crates/issue/src/benchmarking.rs new file mode 100644 index 0000000000..52f578274d --- /dev/null +++ b/crates/issue/src/benchmarking.rs @@ -0,0 +1,150 @@ +use super::*; +use crate::Module as Issue; +use bitcoin::formatter::Formattable; +use bitcoin::types::{ + Address, BlockBuilder, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, + TransactionOutput, +}; +use btc_relay::Module as BtcRelay; +use collateral::Module as Collateral; +use exchange_rate_oracle::Module as ExchangeRateOracle; +use frame_benchmarking::{account, benchmarks}; +use frame_system::RawOrigin; +use sp_core::{H256, U256}; +use sp_std::prelude::*; +use vault_registry::types::{Vault, Wallet}; +use vault_registry::Module as VaultRegistry; + +benchmarks! { + _ {} + + request_issue { + let origin: T::AccountId = account("Origin", 0, 0); + let amount = 100; + let vault_id: T::AccountId = account("Vault", 0, 0); + let griefing = 100; + + Collateral::::lock_collateral(&vault_id, 100000000.into()).unwrap(); + ExchangeRateOracle::::_set_exchange_rate(1).unwrap(); + VaultRegistry::::_set_secure_collateral_threshold(1); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(origin), amount.into(), vault_id, griefing.into()) + + execute_issue { + let origin: T::AccountId = account("Origin", 0, 0); + let vault_id: T::AccountId = account("Vault", 0, 0); + + let issue_id = H256::zero(); + let mut issue_request = IssueRequest::default(); + issue_request.requester = origin.clone(); + issue_request.vault = vault_id.clone(); + Issue::::insert_issue_request(issue_id, issue_request); + + let address = Address::from([0; 20]); + let mut height = 0; + + let block = BlockBuilder::new() + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + + let block_hash = block.header.hash(); + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_initialize(block_header, height).unwrap(); + + height += 1; + + let value = 0; + let transaction = TransactionBuilder::new() + .with_version(2) + .add_input( + TransactionInputBuilder::new() + .with_coinbase(false) + .with_previous_hash(block.transactions[0].hash()) + .build(), + ) + .add_output(TransactionOutput::p2pkh(value.into(), &address)) + .add_output(TransactionOutput::op_return(0, H256::zero().as_bytes())) + .build(); + + let block = BlockBuilder::new() + .with_previous_hash(block_hash) + .with_version(2) + .with_coinbase(&address, 50, 4) + .with_timestamp(1588813835) + .add_transaction(transaction.clone()) + .mine(U256::from(2).pow(254.into())); + + let tx_id = transaction.tx_id(); + let tx_block_height = height; + let proof = block.merkle_proof(&vec![tx_id]).format(); + let raw_tx = transaction.format_with(true); + + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_store_block_header(block_header).unwrap(); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(origin), issue_id, tx_id, tx_block_height, proof, raw_tx) + + cancel_issue { + let origin: T::AccountId = account("Origin", 0, 0); + let vault_id: T::AccountId = account("Vault", 0, 0); + + let issue_id = H256::zero(); + let mut issue_request = IssueRequest::default(); + issue_request.requester = origin.clone(); + issue_request.vault = vault_id.clone(); + Issue::::insert_issue_request(issue_id, issue_request); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(origin), issue_id) + +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_benchmarks() { + ExtBuilder::build_with(pallet_balances::GenesisConfig:: { + balances: vec![ + (account("Origin", 0, 0), 1 << 32), + (account("Vault", 0, 0), 1 << 32), + ], + }) + .execute_with(|| { + assert_ok!(test_benchmark_request_issue::()); + assert_ok!(test_benchmark_execute_issue::()); + + // issue period is 10, we issued at block 1, so at block 15 the cancel should succeed + >::set_block_number(15); + assert_ok!(test_benchmark_cancel_issue::()); + }); + } +} diff --git a/crates/issue/src/default_weights.rs b/crates/issue/src/default_weights.rs new file mode 100644 index 0000000000..c417bd9eae --- /dev/null +++ b/crates/issue/src/default_weights.rs @@ -0,0 +1,24 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + fn request_issue() -> Weight { + (178_948_000 as Weight) + .saturating_add(DbWeight::get().reads(12 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } + fn execute_issue() -> Weight { + (178_285_000 as Weight) + .saturating_add(DbWeight::get().reads(11 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn cancel_issue() -> Weight { + (99_638_000 as Weight) + .saturating_add(DbWeight::get().reads(5 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } +} diff --git a/crates/issue/src/lib.rs b/crates/issue/src/lib.rs index fd2a1d3235..1a62a07dcd 100644 --- a/crates/issue/src/lib.rs +++ b/crates/issue/src/lib.rs @@ -1,6 +1,16 @@ +//! # PolkaBTC Issue implementation +//! The Issue module according to the specification at +//! https://interlay.gitlab.io/polkabtc-spec/spec/issue.html + #![deny(warnings)] #![cfg_attr(test, feature(proc_macro_hygiene))] #![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] mod mock; @@ -16,18 +26,15 @@ use mocktopus::macros::mockable; mod ext; pub mod types; +pub use crate::types::IssueRequest; + use crate::types::{PolkaBTC, DOT}; use bitcoin::types::H256Le; -use codec::{Decode, Encode}; -/// # PolkaBTC Issue implementation -/// The Issue module according to the specification at -/// https://interlay.gitlab.io/polkabtc-spec/spec/issue.html -// Substrate +use frame_support::weights::Weight; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::{DispatchError, DispatchResult}, ensure, - traits::Get, }; use frame_system::ensure_signed; use primitive_types::H256; @@ -39,6 +46,12 @@ use sp_std::vec::Vec; /// The issue module id, used for deriving its sovereign account ID. const _MODULE_ID: ModuleId = ModuleId(*b"issuemod"); +pub trait WeightInfo { + fn request_issue() -> Weight; + fn execute_issue() -> Weight; + fn cancel_issue() -> Weight; +} + /// The pallet's configuration trait. pub trait Trait: frame_system::Trait + vault_registry::Trait + collateral::Trait + btc_relay::Trait + treasury::Trait @@ -46,33 +59,24 @@ pub trait Trait: /// The overarching event type. type Event: From> + Into<::Event>; - /// The time difference in number of blocks between an issue request is created - /// and required completion time by a user. The issue period has an upper limit - /// to prevent griefing of vault collateral. - type IssuePeriod: Get; -} - -#[derive(Encode, Decode, Default, Clone, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct Issue { - vault: AccountId, - opentime: BlockNumber, - griefing_collateral: DOT, - amount: PolkaBTC, - requester: AccountId, - btc_address: H160, - completed: bool, + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; } // The pallet's storage items. decl_storage! { trait Store for Module as Issue { + /// Users create issue requests to issue PolkaBTC. This mapping provides access + /// from a unique hash `IssueId` to an `IssueRequest` struct. + IssueRequests: map hasher(blake2_128_concat) H256 => IssueRequest, DOT>; + /// The minimum collateral (DOT) a user needs to provide as griefing protection. - IssueGriefingCollateral: DOT; + IssueGriefingCollateral get(fn issue_griefing_collateral) config(): DOT; - /// Users create issue requests to issue PolkaBTC. This mapping provides access - /// from a unique hash `IssueId` to an `Issue` struct. - IssueRequests: map hasher(blake2_128_concat) H256 => Issue, DOT>; + /// The time difference in number of blocks between an issue request is created + /// and required completion time by a user. The issue period has an upper limit + /// to prevent griefing of vault collateral. + IssuePeriod get(fn issue_period) config(): T::BlockNumber; } } @@ -99,8 +103,6 @@ decl_module! { // this is needed only if you are using events in your pallet fn deposit_event() = default; - const IssuePeriod: T::BlockNumber = T::IssuePeriod::get(); - /// Request the issuance of PolkaBTC /// /// # Arguments @@ -109,7 +111,7 @@ decl_module! { /// * `amount` - amount of PolkaBTC /// * `vault` - address of the vault /// * `griefing_collateral` - amount of DOT - #[weight = 1000] + #[weight = ::WeightInfo::request_issue()] fn request_issue(origin, amount: PolkaBTC, vault_id: T::AccountId, griefing_collateral: DOT) -> DispatchResult { @@ -128,7 +130,7 @@ decl_module! { /// * `tx_block_height` - block number of backing chain /// * `merkle_proof` - raw bytes /// * `raw_tx` - raw bytes - #[weight = 1000] + #[weight = ::WeightInfo::execute_issue()] fn execute_issue(origin, issue_id: H256, tx_id: H256Le, _tx_block_height: u32, merkle_proof: Vec, raw_tx: Vec) -> DispatchResult { @@ -143,7 +145,7 @@ decl_module! { /// /// * `origin` - sender of the transaction /// * `issue_id` - identifier of issue request as output from request_issue - #[weight = 1000] + #[weight = ::WeightInfo::cancel_issue()] fn cancel_issue(origin, issue_id: H256) -> DispatchResult { @@ -173,7 +175,7 @@ impl Module { ext::vault_registry::ensure_not_banned::(&vault_id, height)?; ensure!( - griefing_collateral >= >::get(), + griefing_collateral >= Self::issue_griefing_collateral(), Error::::InsufficientCollateral ); @@ -186,7 +188,7 @@ impl Module { Self::insert_issue_request( key, - Issue { + IssueRequest { vault: vault_id.clone(), opentime: height, griefing_collateral: griefing_collateral, @@ -222,7 +224,7 @@ impl Module { ensure!(requester == issue.requester, Error::::UnauthorizedUser); let height = >::block_number(); - let period = T::IssuePeriod::get(); + let period = Self::issue_period(); ensure!( height <= issue.opentime + period, Error::::CommitPeriodExpired @@ -250,9 +252,9 @@ impl Module { fn _cancel_issue(requester: T::AccountId, issue_id: H256) -> Result<(), DispatchError> { let issue = Self::get_issue_request_from_id(&issue_id)?; let height = >::block_number(); - let period = T::IssuePeriod::get(); + let period = Self::issue_period(); - ensure!(issue.opentime + period > height, Error::::TimeNotExpired); + ensure!(height > issue.opentime + period, Error::::TimeNotExpired); ensure!(!issue.completed, Error::::IssueCompleted); ext::vault_registry::decrease_to_be_issued_tokens::(&issue.vault, issue.amount)?; @@ -269,9 +271,42 @@ impl Module { Ok(()) } + /// Fetch all issue requests for the specified account. + /// + /// # Arguments + /// + /// * `account_id` - user account id + pub fn get_issue_requests_for_account( + account_id: T::AccountId, + ) -> Vec<( + H256, + IssueRequest, DOT>, + )> { + >::iter() + .filter(|(_, request)| request.requester == account_id) + .collect::>() + } + + /// Fetch all issue requests for the specified vault. + /// + /// # Arguments + /// + /// * `account_id` - vault account id + pub fn get_issue_requests_for_vault( + account_id: T::AccountId, + ) -> Vec<( + H256, + IssueRequest, DOT>, + )> { + >::iter() + .filter(|(_, request)| request.vault == account_id) + .collect::>() + } + fn get_issue_request_from_id( issue_id: &H256, - ) -> Result, DOT>, DispatchError> { + ) -> Result, DOT>, DispatchError> + { ensure!( >::contains_key(*issue_id), Error::::IssueIdNotFound @@ -281,16 +316,11 @@ impl Module { fn insert_issue_request( key: H256, - value: Issue, DOT>, + value: IssueRequest, DOT>, ) { >::insert(key, value) } - #[allow(dead_code)] - fn set_issue_griefing_collateral(amount: DOT) { - >::set(amount); - } - fn remove_issue_request(id: H256) { >::remove(id); } diff --git a/crates/issue/src/mock.rs b/crates/issue/src/mock.rs index f8ceb44743..e55584b3b3 100644 --- a/crates/issue/src/mock.rs +++ b/crates/issue/src/mock.rs @@ -1,5 +1,5 @@ /// Mocking the test environment -use crate::{Error, Module, Trait}; +use crate::{Error, GenesisConfig, Module, Trait}; use frame_support::{ assert_ok, impl_outer_event, impl_outer_origin, parameter_types, weights::{ @@ -75,7 +75,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -86,9 +86,11 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); @@ -99,6 +101,7 @@ impl pallet_balances::Trait for Test { impl vault_registry::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl collateral::Trait for Test { @@ -108,6 +111,7 @@ impl collateral::Trait for Test { impl btc_relay::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl security::Trait for Test { @@ -122,6 +126,7 @@ impl treasury::Trait for Test { parameter_types! { pub const MinimumPeriod: u64 = 5; } + impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); @@ -131,14 +136,12 @@ impl timestamp::Trait for Test { impl exchange_rate_oracle::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } -parameter_types! { - pub const IssuePeriod: BlockNumber = 10; -} impl Trait for Test { type Event = TestEvent; - type IssuePeriod = IssuePeriod; + type WeightInfo = (); } pub type TestError = Error; @@ -160,23 +163,32 @@ pub const CAROL_BALANCE: u64 = 1_000_000; pub struct ExtBuilder; impl ExtBuilder { - pub fn build() -> sp_io::TestExternalities { + pub fn build_with(conf: pallet_balances::GenesisConfig) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, ALICE_BALANCE), - (BOB, BOB_BALANCE), - (CAROL, CAROL_BALANCE), - ], + conf.assimilate_storage(&mut storage).unwrap(); + + GenesisConfig:: { + issue_griefing_collateral: 10, + issue_period: 10, } .assimilate_storage(&mut storage) .unwrap(); storage.into() } + + pub fn build() -> sp_io::TestExternalities { + ExtBuilder::build_with(pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, ALICE_BALANCE), + (BOB, BOB_BALANCE), + (CAROL, CAROL_BALANCE), + ], + }) + } } pub fn run_test(test: T) -> () diff --git a/crates/issue/src/tests.rs b/crates/issue/src/tests.rs index fe830c6d7a..200442e3b9 100644 --- a/crates/issue/src/tests.rs +++ b/crates/issue/src/tests.rs @@ -7,7 +7,7 @@ use frame_support::{assert_noop, assert_ok, dispatch::DispatchError}; use mocktopus::mocking::*; use primitive_types::H256; use sp_core::H160; -use vault_registry::{Vault, VaultStatus}; +use vault_registry::{Vault, VaultStatus, Wallet}; fn request_issue( origin: AccountId, @@ -99,7 +99,7 @@ fn test_request_issue_banned_fails() { to_be_issued_tokens: 0, issued_tokens: 0, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: Some(1), status: VaultStatus::Active, }, @@ -114,7 +114,6 @@ fn test_request_issue_banned_fails() { #[test] fn test_request_issue_insufficient_collateral_fails() { run_test(|| { - Issue::set_issue_griefing_collateral(10); ext::vault_registry::get_vault_from_id:: .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); @@ -135,7 +134,7 @@ fn test_request_issue_succeeds() { ext::vault_registry::get_vault_from_id:: .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); - let issue_id = request_issue_ok(origin, amount, vault, 0); + let issue_id = request_issue_ok(origin, amount, vault, 20); let request_issue_event = TestEvent::test_events(RawEvent::RequestIssue( issue_id, @@ -167,7 +166,7 @@ fn test_execute_issue_unauthorized_fails() { run_test(|| { ext::vault_registry::get_vault_from_id:: .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); - let issue_id = request_issue_ok(ALICE, 3, BOB, 0); + let issue_id = request_issue_ok(ALICE, 3, BOB, 20); assert_noop!(execute_issue(CAROL, &issue_id), TestError::UnauthorizedUser); }) } @@ -178,7 +177,7 @@ fn test_execute_issue_commit_period_expired_fails() { ext::vault_registry::get_vault_from_id:: .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); - let issue_id = request_issue_ok(ALICE, 3, BOB, 0); + let issue_id = request_issue_ok(ALICE, 3, BOB, 20); >::set_block_number(20); assert_noop!( execute_issue(ALICE, &issue_id), @@ -194,7 +193,7 @@ fn test_execute_issue_succeeds() { .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); ext::vault_registry::issue_tokens::.mock_safe(|_, _| MockResult::Return(Ok(()))); - let issue_id = request_issue_ok(ALICE, 3, BOB, 0); + let issue_id = request_issue_ok(ALICE, 3, BOB, 20); >::set_block_number(5); execute_issue_ok(ALICE, &issue_id); @@ -221,11 +220,14 @@ fn test_cancel_issue_not_found_fails() { #[test] fn test_cancel_issue_not_expired_fails() { run_test(|| { + >::set_block_number(1); + ext::vault_registry::get_vault_from_id:: .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); - let issue_id = request_issue_ok(ALICE, 3, BOB, 0); - >::set_block_number(99); + let issue_id = request_issue_ok(ALICE, 3, BOB, 20); + // issue period is 10, we issued at block 1, so at block 5 the cancel should fail + >::set_block_number(5); assert_noop!(cancel_issue(ALICE, &issue_id), TestError::TimeNotExpired,); }) } @@ -233,13 +235,16 @@ fn test_cancel_issue_not_expired_fails() { #[test] fn test_cancel_issue_succeeds() { run_test(|| { - >::set_block_number(20); + >::set_block_number(1); + ext::vault_registry::get_vault_from_id:: .mock_safe(|_| MockResult::Return(Ok(init_zero_vault::(BOB)))); ext::vault_registry::decrease_to_be_issued_tokens:: .mock_safe(|_, _| MockResult::Return(Ok(()))); - let issue_id = request_issue_ok(ALICE, 3, BOB, 0); + let issue_id = request_issue_ok(ALICE, 3, BOB, 20); + // issue period is 10, we issued at block 1, so at block 15 the cancel should succeed + >::set_block_number(15); assert_ok!(cancel_issue(ALICE, &issue_id)); }) } diff --git a/crates/issue/src/types.rs b/crates/issue/src/types.rs index c62160caea..f01bbe5572 100644 --- a/crates/issue/src/types.rs +++ b/crates/issue/src/types.rs @@ -1,3 +1,8 @@ +use codec::{Decode, Encode}; +#[cfg(feature = "std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use sp_core::H160; + use frame_support::traits::Currency; pub(crate) type DOT = @@ -5,3 +10,48 @@ pub(crate) type DOT = pub(crate) type PolkaBTC = <::PolkaBTC as Currency<::AccountId>>::Balance; + +// Due to a known bug in serde we need to specify how u128 is (de)serialized. +// See https://github.com/paritytech/substrate/issues/4641 +#[derive(Encode, Decode, Default, Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct IssueRequest { + pub vault: AccountId, + pub opentime: BlockNumber, + #[cfg_attr(feature = "std", serde(bound(deserialize = "DOT: std::str::FromStr")))] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr(feature = "std", serde(bound(serialize = "DOT: std::fmt::Display")))] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] + pub griefing_collateral: DOT, + #[cfg_attr( + feature = "std", + serde(bound(deserialize = "PolkaBTC: std::str::FromStr")) + )] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr( + feature = "std", + serde(bound(serialize = "PolkaBTC: std::fmt::Display")) + )] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] + pub amount: PolkaBTC, + pub requester: AccountId, + pub btc_address: H160, + pub completed: bool, +} + +#[cfg(feature = "std")] +fn serialize_as_string( + t: &T, + serializer: S, +) -> Result { + serializer.serialize_str(&t.to_string()) +} + +#[cfg(feature = "std")] +fn deserialize_from_string<'de, D: Deserializer<'de>, T: std::str::FromStr>( + deserializer: D, +) -> Result { + let s = String::deserialize(deserializer)?; + s.parse::() + .map_err(|_| serde::de::Error::custom("Parse from string failed")) +} diff --git a/crates/priority-map/Cargo.toml b/crates/priority-map/Cargo.toml deleted file mode 100644 index 80e27d9e29..0000000000 --- a/crates/priority-map/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "priority-map" -version = "0.1.0" -authors = ["Dominik Harz "] -edition = "2018" - -[features] -default = ['std'] -std = [ - 'codec/std', - 'frame-support/std', - 'sp-std/std', -] - -[dependencies.codec] -default-features = false -features = ['derive'] -package = 'parity-scale-codec' -version = '1.3.4' - -[dependencies.frame-support] -default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' - -[dependencies.sp-std] -default-features = false -version = '2.0.0' -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' diff --git a/crates/priority-map/src/lib.rs b/crates/priority-map/src/lib.rs deleted file mode 100644 index cf132544ce..0000000000 --- a/crates/priority-map/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -/// Adds new functions to StorageLinkedMap -/// https://substrate.dev/rustdocs/master/src/frame_support/storage/generator/linked_map.rs.html -/// - -use codec::{FullCodec, Encode, Decode, EncodeLike, Ref}; -use frame_support::{storage::{self, unhashed, StorageLinkedMap}, hash::{StorageHasher, Twox128}, traits::Len}; -use sp_std::{prelude::*, marker::PhantomData}; - - -impl storage::StorageLinkedMap for G -where - K: FullCodec, - V: FullCodec, - G: StorageLinkedMap -{ - fn insert_sorted() -> u32 { - 0 - } -} - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/crates/redeem/Cargo.toml b/crates/redeem/Cargo.toml index 1d4a2ab6b4..7a1ccd51aa 100644 --- a/crates/redeem/Cargo.toml +++ b/crates/redeem/Cargo.toml @@ -3,7 +3,7 @@ authors = ['Interlay'] description = 'Issue module' edition = '2018' name = 'redeem' -version = '2.0.0-rc6' +version = '0.2.3' [dependencies.serde] version = '1.0.101' @@ -18,35 +18,32 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false package = 'pallet-balances' -version = '2.0.0-rc6' - -[dev-dependencies] -mocktopus = '0.7.0' +version = '2.0.0' [dependencies.primitive-types] default-features = false @@ -84,11 +81,20 @@ path = '../security' [dependencies.timestamp] default-features = false package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sha2] default-features = false -version = '0.8.0' +version = "0.8.2" + +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true + +[dev-dependencies] +mocktopus = '0.7.0' +frame-benchmarking = { version = "2.0.0" } [features] default = ['std'] @@ -112,4 +118,10 @@ std = [ 'sha2/std', 'security/std', 'timestamp/std', + 'frame-benchmarking/std', ] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] \ No newline at end of file diff --git a/crates/redeem/rpc/Cargo.toml b/crates/redeem/rpc/Cargo.toml new file mode 100644 index 0000000000..3abc7c99f5 --- /dev/null +++ b/crates/redeem/rpc/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "module-redeem-rpc" +version = '0.2.3' +authors = ["Interlay Ltd"] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", features = ["derive"] } +codec = { package = "parity-scale-codec", version = '1.3.4' } +jsonrpc-core = "15.0.0" +jsonrpc-core-client = "15.0.0" +jsonrpc-derive = "15.0.0" +sp-runtime = { version = "2.0.0" } +sp-api = { version = "2.0.0" } +sp-blockchain = { version = "2.0.0" } +module-redeem-rpc-runtime-api = { path = "runtime-api" } diff --git a/crates/redeem/rpc/runtime-api/Cargo.toml b/crates/redeem/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..9c597c625a --- /dev/null +++ b/crates/redeem/rpc/runtime-api/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "module-redeem-rpc-runtime-api" +version = '0.2.3' +authors = ["Interlay Ltd"] +edition = "2018" + +[dependencies] +codec = { package = "parity-scale-codec", version = '1.3.4', default-features = false, features = ["derive"] } +sp-api = { version = "2.0.0", default-features = false } +frame-support = { version = "2.0.0", default-features = false } +sp-std = { version = "2.0.0", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", + "sp-std/std", + "frame-support/std", +] \ No newline at end of file diff --git a/crates/redeem/rpc/runtime-api/src/lib.rs b/crates/redeem/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..d672d8b7e7 --- /dev/null +++ b/crates/redeem/rpc/runtime-api/src/lib.rs @@ -0,0 +1,20 @@ +//! Runtime API definition for the Redeem Module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use sp_std::vec::Vec; + +sp_api::decl_runtime_apis! { + pub trait RedeemApi where + AccountId: Codec, + H256: Codec, + RedeemRequest: Codec, + { + /// Get all redeem requests for a particular account + fn get_redeem_requests(account_id: AccountId) -> Vec<(H256, RedeemRequest)>; + + /// Get all redeem requests for a particular vault + fn get_vault_redeem_requests(account_id: AccountId) -> Vec<(H256, RedeemRequest)>; + } +} diff --git a/crates/redeem/rpc/src/lib.rs b/crates/redeem/rpc/src/lib.rs new file mode 100644 index 0000000000..d50027661d --- /dev/null +++ b/crates/redeem/rpc/src/lib.rs @@ -0,0 +1,100 @@ +//! RPC interface for the Redeem Module. + +use codec::Codec; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use std::sync::Arc; + +pub use self::gen_client::Client as RedeemClient; +pub use module_redeem_rpc_runtime_api::RedeemApi as RedeemRuntimeApi; + +#[rpc] +pub trait RedeemApi { + #[rpc(name = "redeem_getRedeemRequests")] + fn get_redeem_requests( + &self, + account_id: AccountId, + at: Option, + ) -> Result>; + + #[rpc(name = "redeem_getVaultRedeemRequests")] + fn get_vault_redeem_requests( + &self, + account_id: AccountId, + at: Option, + ) -> Result>; +} + +/// A struct that implements the [`RedeemApi`]. +pub struct Redeem { + client: Arc, + _marker: std::marker::PhantomData, +} + +impl Redeem { + /// Create new `Redeem` with the given reference to the client. + pub fn new(client: Arc) -> Self { + Redeem { + client, + _marker: Default::default(), + } + } +} + +pub enum Error { + RuntimeError, +} + +impl From for i64 { + fn from(e: Error) -> i64 { + match e { + Error::RuntimeError => 1, + } + } +} + +impl + RedeemApi<::Hash, AccountId, H256, RedeemRequest> for Redeem +where + Block: BlockT, + C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: RedeemRuntimeApi, + AccountId: Codec, + H256: Codec, + RedeemRequest: Codec, +{ + fn get_redeem_requests( + &self, + account_id: AccountId, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + api.get_redeem_requests(&at, account_id) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to fetch redeem requests.".into(), + data: Some(format!("{:?}", e).into()), + }) + } + + fn get_vault_redeem_requests( + &self, + account_id: AccountId, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + api.get_vault_redeem_requests(&at, account_id) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to fetch redeem requests.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/crates/redeem/src/benchmarking.rs b/crates/redeem/src/benchmarking.rs new file mode 100644 index 0000000000..806dcbcc5b --- /dev/null +++ b/crates/redeem/src/benchmarking.rs @@ -0,0 +1,142 @@ +use super::*; +use crate::Module as Redeem; +use bitcoin::formatter::Formattable; +use bitcoin::types::{ + Address, BlockBuilder, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, + TransactionOutput, +}; +use btc_relay::Module as BtcRelay; +use frame_benchmarking::{account, benchmarks}; +use frame_system::RawOrigin; +use sp_core::{H160, H256, U256}; +use sp_std::prelude::*; +use vault_registry::types::{Vault, Wallet}; +use vault_registry::Module as VaultRegistry; + +benchmarks! { + _ {} + + request_redeem { + let origin: T::AccountId = account("Origin", 0, 0); + let vault_id: T::AccountId = account("Vault", 0, 0); + let amount = 100; + let btc_address = H160::zero(); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + vault.issued_tokens = amount.into(); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(origin), amount.into(), btc_address, vault_id.clone()) + + execute_redeem { + let origin: T::AccountId = account("Origin", 0, 0); + let vault_id: T::AccountId = account("Vault", 0, 0); + + let redeem_id = H256::zero(); + let mut redeem_request = RedeemRequest::default(); + redeem_request.vault = vault_id.clone(); + Redeem::::insert_redeem_request(redeem_id, redeem_request); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + let address = Address::from([0; 20]); + let mut height = 0; + + let block = BlockBuilder::new() + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + + let block_hash = block.header.hash(); + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_initialize(block_header, height).unwrap(); + + height += 1; + + let value = 0; + let transaction = TransactionBuilder::new() + .with_version(2) + .add_input( + TransactionInputBuilder::new() + .with_coinbase(false) + .with_previous_hash(block.transactions[0].hash()) + .build(), + ) + .add_output(TransactionOutput::p2pkh(value.into(), &address)) + .add_output(TransactionOutput::op_return(0, H256::zero().as_bytes())) + .build(); + + let block = BlockBuilder::new() + .with_previous_hash(block_hash) + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .add_transaction(transaction.clone()) + .mine(U256::from(2).pow(254.into())); + + let tx_id = transaction.tx_id(); + let tx_block_height = height; + let proof = block.merkle_proof(&vec![tx_id]).format(); + let raw_tx = transaction.format_with(true); + + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_store_block_header(block_header).unwrap(); + + }: _(RawOrigin::Signed(vault_id), redeem_id, tx_id, tx_block_height, proof, raw_tx) + + cancel_redeem { + let origin: T::AccountId = account("Origin", 0, 0); + let vault_id: T::AccountId = account("Vault", 0, 0); + + let redeem_id = H256::zero(); + let mut redeem_request = RedeemRequest::default(); + redeem_request.vault = vault_id.clone(); + redeem_request.redeemer = origin.clone(); + redeem_request.opentime = 100.into(); + Redeem::::insert_redeem_request(redeem_id, redeem_request); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(origin), redeem_id, true) + +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_benchmarks() { + ExtBuilder::build_with(pallet_balances::GenesisConfig:: { + balances: vec![ + (account("Origin", 0, 0), 1 << 32), + (account("Vault", 0, 0), 1 << 32), + ], + }) + .execute_with(|| { + assert_ok!(test_benchmark_request_redeem::()); + assert_ok!(test_benchmark_execute_redeem::()); + assert_ok!(test_benchmark_cancel_redeem::()); + }); + } +} diff --git a/crates/redeem/src/default_weights.rs b/crates/redeem/src/default_weights.rs new file mode 100644 index 0000000000..8064d4d20d --- /dev/null +++ b/crates/redeem/src/default_weights.rs @@ -0,0 +1,24 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + fn request_redeem() -> Weight { + (179_175_000 as Weight) + .saturating_add(DbWeight::get().reads(12 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } + fn execute_redeem() -> Weight { + (188_681_000 as Weight) + .saturating_add(DbWeight::get().reads(14 as Weight)) + .saturating_add(DbWeight::get().writes(4 as Weight)) + } + fn cancel_redeem() -> Weight { + (168_952_000 as Weight) + .saturating_add(DbWeight::get().reads(14 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } +} diff --git a/crates/redeem/src/ext.rs b/crates/redeem/src/ext.rs index 7d8083b96a..fa388d6548 100644 --- a/crates/redeem/src/ext.rs +++ b/crates/redeem/src/ext.rs @@ -94,12 +94,12 @@ pub(crate) mod vault_registry { >::_get_total_liquidation_value() } - pub fn punishment_fee() -> Result, DispatchError> { - >::_punishment_fee() + pub fn punishment_fee() -> DOT { + >::punishment_fee() } - pub fn get_redeem_premium_fee() -> Result, DispatchError> { - >::_get_redeem_premium_fee() + pub fn get_redeem_premium_fee() -> DOT { + >::redeem_premium_fee() } pub fn is_vault_below_premium_threshold( diff --git a/crates/redeem/src/lib.rs b/crates/redeem/src/lib.rs index 94b513b928..1e6cb38472 100644 --- a/crates/redeem/src/lib.rs +++ b/crates/redeem/src/lib.rs @@ -1,6 +1,12 @@ #![deny(warnings)] #![cfg_attr(test, feature(proc_macro_hygiene))] #![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] mod mock; @@ -16,8 +22,10 @@ use mocktopus::macros::mockable; mod ext; pub mod types; -use crate::types::{PolkaBTC, Redeem, DOT}; +pub use crate::types::RedeemRequest; +use crate::types::{PolkaBTC, DOT}; use bitcoin::types::H256Le; +use frame_support::weights::Weight; /// # PolkaBTC Redeem implementation /// The Redeem module according to the specification at /// https://interlay.gitlab.io/polkabtc-spec/spec/redeem.html @@ -38,12 +46,21 @@ use sp_std::vec::Vec; /// The redeem module id, used for deriving its sovereign account ID. const _MODULE_ID: ModuleId = ModuleId(*b"i/redeem"); +pub trait WeightInfo { + fn request_redeem() -> Weight; + fn execute_redeem() -> Weight; + fn cancel_redeem() -> Weight; +} + /// The pallet's configuration trait. pub trait Trait: frame_system::Trait + vault_registry::Trait + collateral::Trait + btc_relay::Trait + treasury::Trait { /// The overarching event type. type Event: From> + Into<::Event>; + + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; } // The pallet's storage items. @@ -51,11 +68,15 @@ decl_storage! { trait Store for Module as Redeem { /// The time difference in number of blocks between a redeem request is created and required completion time by a vault. /// The redeem period has an upper limit to ensure the user gets their BTC in time and to potentially punish a vault for inactivity or stealing BTC. - RedeemPeriod get(fn redeem_period): T::BlockNumber; + RedeemPeriod get(fn redeem_period) config(): T::BlockNumber; /// Users create redeem requests to receive BTC in return for PolkaBTC. /// This mapping provides access from a unique hash redeemId to a Redeem struct. - RedeemRequests: map hasher(blake2_128_concat) H256 => Redeem, DOT>; + RedeemRequests: map hasher(blake2_128_concat) H256 => RedeemRequest, DOT>; + + /// The minimum amount of btc that is accepted for redeem requests; any lower values would + /// risk the bitcoin client to reject the payment + RedeemBtcDustValue get(fn redeem_btc_dust_value) config(): PolkaBTC; } } @@ -91,7 +112,7 @@ decl_module! { /// * `amount` - amount of PolkaBTC /// * `btc_address` - the address to receive BTC /// * `vault` - address of the vault - #[weight = 1000] + #[weight = ::WeightInfo::request_redeem()] fn request_redeem(origin, amount_polka_btc: PolkaBTC, btc_address: H160, vault_id: T::AccountId) -> DispatchResult { @@ -112,6 +133,13 @@ decl_module! { Error::::AmountExceedsVaultBalance ); + // only allow requests of amount above above the minimum + let dust_value = >::get(); + ensure!( + amount_polka_btc >= dust_value, + Error::::AmountBelowDustAmount + ); + let (amount_btc, amount_dot): (u128, u128) = if ext::security::is_parachain_error_liquidation::() { let raw_amount_polka_btc = Self::btc_to_u128(amount_polka_btc)?; @@ -140,14 +168,14 @@ decl_module! { let below_premium_redeem = ext::vault_registry::is_vault_below_premium_threshold::(&vault_id)?; let premium_dot = if below_premium_redeem { - ext::vault_registry::get_redeem_premium_fee::()? + ext::vault_registry::get_redeem_premium_fee::() } else { Self::u128_to_dot(0u128)? }; Self::insert_redeem_request( redeem_id, - Redeem { + RedeemRequest { vault: vault_id.clone(), opentime: height, amount_polka_btc, @@ -181,7 +209,7 @@ decl_module! { /// * `tx_block_height` - block number of backing chain /// * `merkle_proof` - raw bytes /// * `raw_tx` - raw bytes - #[weight = 1000] + #[weight = ::WeightInfo::execute_redeem()] fn execute_redeem(origin, redeem_id: H256, tx_id: H256Le, _tx_block_height: u32, merkle_proof: Vec, raw_tx: Vec) -> DispatchResult { @@ -194,7 +222,7 @@ decl_module! { let height = >::block_number(); let period = Self::redeem_period(); ensure!( - redeem.opentime + period < height, + height <= redeem.opentime + period, Error::::CommitPeriodExpired ); let amount: usize = redeem @@ -239,7 +267,7 @@ decl_module! { /// * `reimburse` - specifying if the user wishes to be reimbursed in DOT /// and slash the Vault, or wishes to keep the PolkaBTC (and retry /// Redeem with another Vault) - #[weight = 1000] + #[weight = ::WeightInfo::cancel_redeem()] fn cancel_redeem(origin, redeem_id: H256, reimburse: bool) -> DispatchResult { @@ -251,7 +279,7 @@ decl_module! { let period = Self::redeem_period(); ensure!(redeem.opentime + period > height, Error::::TimeNotExpired); - let punishment_fee = ext::vault_registry::punishment_fee::()?; + let punishment_fee = ext::vault_registry::punishment_fee::(); let raw_punishment_fee = Self::dot_to_u128(punishment_fee)?; let raw_amount_polka_btc = Self::btc_to_u128(redeem.amount_polka_btc)?; let raw_amount_in_dot = Self::rawbtc_to_rawdot(raw_amount_polka_btc)?; @@ -300,11 +328,43 @@ impl Module { /// * `value` - the redeem request fn insert_redeem_request( key: H256, - value: Redeem, DOT>, + value: RedeemRequest, DOT>, ) { >::insert(key, value) } + /// Fetch all redeem requests for the specified account. + /// + /// # Arguments + /// + /// * `account_id` - user account id + pub fn get_redeem_requests_for_account( + account_id: T::AccountId, + ) -> Vec<( + H256, + RedeemRequest, DOT>, + )> { + >::iter() + .filter(|(_, request)| request.redeemer == account_id) + .collect::>() + } + + /// Fetch all redeem requests for the specified vault. + /// + /// # Arguments + /// + /// * `account_id` - vault account id + pub fn get_redeem_requests_for_vault( + account_id: T::AccountId, + ) -> Vec<( + H256, + RedeemRequest, DOT>, + )> { + >::iter() + .filter(|(_, request)| request.vault == account_id) + .collect::>() + } + /// Fetch a pre-existing redeem request or throw. /// /// # Arguments @@ -312,7 +372,8 @@ impl Module { /// * `key` - 256-bit identifier of the redeem request pub fn get_redeem_request_from_id( key: &H256, - ) -> Result, DOT>, DispatchError> { + ) -> Result, DOT>, DispatchError> + { ensure!( >::contains_key(*key), Error::::RedeemIdNotFound @@ -376,5 +437,6 @@ decl_error! { TimeNotExpired, RedeemIdNotFound, ConversionError, + AmountBelowDustAmount, } } diff --git a/crates/redeem/src/mock.rs b/crates/redeem/src/mock.rs index 1590d466c0..36bf7b589c 100644 --- a/crates/redeem/src/mock.rs +++ b/crates/redeem/src/mock.rs @@ -1,5 +1,5 @@ /// Mocking the test environment -use crate::{Error, Module, Trait}; +use crate::{Error, GenesisConfig, Module, Trait}; use frame_support::{ assert_ok, impl_outer_event, impl_outer_origin, parameter_types, weights::{ @@ -75,7 +75,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -86,9 +86,11 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); @@ -99,6 +101,7 @@ impl pallet_balances::Trait for Test { impl vault_registry::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl collateral::Trait for Test { @@ -108,6 +111,7 @@ impl collateral::Trait for Test { impl btc_relay::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl security::Trait for Test { @@ -131,10 +135,12 @@ impl timestamp::Trait for Test { impl exchange_rate_oracle::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl Trait for Test { type Event = TestEvent; + type WeightInfo = (); } pub type TestError = Error; @@ -156,23 +162,32 @@ pub const CAROL_BALANCE: u64 = 1_000_000; pub struct ExtBuilder; impl ExtBuilder { - pub fn build() -> sp_io::TestExternalities { + pub fn build_with(conf: pallet_balances::GenesisConfig) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, ALICE_BALANCE), - (BOB, BOB_BALANCE), - (CAROL, CAROL_BALANCE), - ], + conf.assimilate_storage(&mut storage).unwrap(); + + GenesisConfig:: { + redeem_period: 10, + redeem_btc_dust_value: 2, } .assimilate_storage(&mut storage) .unwrap(); storage.into() } + + pub fn build() -> sp_io::TestExternalities { + ExtBuilder::build_with(pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, ALICE_BALANCE), + (BOB, BOB_BALANCE), + (CAROL, CAROL_BALANCE), + ], + }) + } } pub fn run_test(test: T) -> () diff --git a/crates/redeem/src/tests.rs b/crates/redeem/src/tests.rs index 339592931e..faced7a6e8 100644 --- a/crates/redeem/src/tests.rs +++ b/crates/redeem/src/tests.rs @@ -1,14 +1,14 @@ use crate::ext; use crate::mock::*; -use crate::types::{PolkaBTC, Redeem as RedeemRequest, DOT}; +use crate::types::{PolkaBTC, RedeemRequest, DOT}; use bitcoin::types::H256Le; use frame_support::{assert_err, assert_noop, assert_ok, dispatch::DispatchError}; use mocktopus::mocking::*; use primitive_types::H256; use sp_core::H160; use sp_std::convert::TryInto; -use vault_registry::{Vault, VaultStatus}; +use vault_registry::{Vault, VaultStatus, Wallet}; type Event = crate::Event; @@ -94,7 +94,7 @@ fn test_request_redeem_fails_with_amount_exceeds_user_balance() { to_be_issued_tokens: 0, issued_tokens: 10, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: None, status: VaultStatus::Active, })) @@ -113,6 +113,42 @@ fn test_request_redeem_fails_with_amount_exceeds_user_balance() { }) } +#[test] +fn test_request_redeem_fails_with_amount_below_minimum() { + run_test(|| { + ext::oracle::btc_to_dots::.mock_safe(|x| MockResult::Return(btcdot_parity(x))); + >::_insert_vault( + &BOB, + vault_registry::Vault { + id: BOB, + to_be_issued_tokens: 0, + issued_tokens: 10, + to_be_redeemed_tokens: 0, + wallet: Wallet::new(H160::random()), + banned_until: None, + status: VaultStatus::Active, + }, + ); + + let redeemer = ALICE; + let amount = 9; + + ext::vault_registry::increase_to_be_redeemed_tokens::.mock_safe( + move |vault_id, amount_btc| { + assert_eq!(vault_id, &BOB); + assert_eq!(amount_btc, amount); + + MockResult::Return(Ok(())) + }, + ); + + assert_err!( + Redeem::request_redeem(Origin::signed(redeemer.clone()), 1, H160([0; 20]), BOB), + TestError::AmountBelowDustAmount + ); + }) +} + #[test] fn test_request_redeem_fails_with_vault_not_found() { run_test(|| { @@ -132,7 +168,7 @@ fn test_request_redeem_fails_with_vault_banned() { to_be_issued_tokens: 0, issued_tokens: 0, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: Some(1), status: VaultStatus::Active, })) @@ -154,9 +190,9 @@ fn test_request_redeem_fails_with_vault_liquidated() { MockResult::Return(Ok(Vault { id: BOB, to_be_issued_tokens: 0, - issued_tokens: 0, + issued_tokens: 5, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: Some(1), status: VaultStatus::Liquidated, })) @@ -164,7 +200,7 @@ fn test_request_redeem_fails_with_vault_liquidated() { ext::vault_registry::ensure_not_banned::.mock_safe(|_, _| MockResult::Return(Ok(()))); assert_err!( - Redeem::request_redeem(Origin::signed(ALICE), 0, H160::from_slice(&[0; 20]), BOB), + Redeem::request_redeem(Origin::signed(ALICE), 3, H160::from_slice(&[0; 20]), BOB), VaultRegistryError::VaultNotFound ); }) @@ -180,7 +216,7 @@ fn test_request_redeem_fails_with_amount_exceeds_vault_balance() { to_be_issued_tokens: 0, issued_tokens: 10, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: None, status: VaultStatus::Active, })) @@ -212,7 +248,7 @@ fn test_request_redeem_succeeds_in_running_state() { to_be_issued_tokens: 0, issued_tokens: 10, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: None, status: VaultStatus::Active, }, @@ -304,7 +340,7 @@ fn test_request_redeem_succeeds_in_error_state() { to_be_issued_tokens: 0, issued_tokens: amount, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: None, status: VaultStatus::Active, }, @@ -417,12 +453,12 @@ fn test_execute_redeem_fails_with_unauthorized_vault() { #[test] fn test_execute_redeem_fails_with_commit_period_expired() { run_test(|| { - >::set_block_number(20); + >::set_block_number(40); Redeem::get_redeem_request_from_id.mock_safe(|_| { MockResult::Return(Ok(RedeemRequest { vault: BOB, - opentime: 30, + opentime: 20, amount_polka_btc: 0, amount_btc: 0, amount_dot: 0, @@ -458,7 +494,7 @@ fn test_execute_redeem_succeeds() { to_be_issued_tokens: 0, issued_tokens: 200, to_be_redeemed_tokens: 200, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160::random()), banned_until: None, status: VaultStatus::Active, }, @@ -472,7 +508,7 @@ fn test_execute_redeem_succeeds() { H256([0u8; 32]), RedeemRequest { vault: BOB, - opentime: 20, + opentime: 40, amount_polka_btc: 100, amount_btc: 0, amount_dot: 0, diff --git a/crates/redeem/src/types.rs b/crates/redeem/src/types.rs index 2313d3e90f..c28026dbb4 100644 --- a/crates/redeem/src/types.rs +++ b/crates/redeem/src/types.rs @@ -2,21 +2,71 @@ use codec::{Decode, Encode}; use frame_support::traits::Currency; use sp_core::H160; +#[cfg(feature = "std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + pub(crate) type DOT = <::DOT as Currency<::AccountId>>::Balance; pub(crate) type PolkaBTC = <::PolkaBTC as Currency<::AccountId>>::Balance; +// Due to a known bug in serde we need to specify how u128 is (de)serialized. +// See https://github.com/paritytech/substrate/issues/4641 #[derive(Encode, Decode, Default, Clone, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct Redeem { +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct RedeemRequest { pub vault: AccountId, pub opentime: BlockNumber, + #[cfg_attr( + feature = "std", + serde(bound(deserialize = "PolkaBTC: std::str::FromStr")) + )] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr( + feature = "std", + serde(bound(serialize = "PolkaBTC: std::fmt::Display")) + )] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub amount_polka_btc: PolkaBTC, + #[cfg_attr( + feature = "std", + serde(bound(deserialize = "PolkaBTC: std::str::FromStr")) + )] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr( + feature = "std", + serde(bound(serialize = "PolkaBTC: std::fmt::Display")) + )] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub amount_btc: PolkaBTC, + #[cfg_attr(feature = "std", serde(bound(deserialize = "DOT: std::str::FromStr")))] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr(feature = "std", serde(bound(serialize = "DOT: std::fmt::Display")))] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub amount_dot: DOT, + #[cfg_attr(feature = "std", serde(bound(deserialize = "DOT: std::str::FromStr")))] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr(feature = "std", serde(bound(serialize = "DOT: std::fmt::Display")))] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub premium_dot: DOT, pub redeemer: AccountId, pub btc_address: H160, } + +#[cfg(feature = "std")] +fn serialize_as_string( + t: &T, + serializer: S, +) -> Result { + serializer.serialize_str(&t.to_string()) +} + +#[cfg(feature = "std")] +fn deserialize_from_string<'de, D: Deserializer<'de>, T: std::str::FromStr>( + deserializer: D, +) -> Result { + let s = String::deserialize(deserializer)?; + s.parse::() + .map_err(|_| serde::de::Error::custom("Parse from string failed")) +} diff --git a/crates/replace/Cargo.toml b/crates/replace/Cargo.toml index 2974286d2a..9370387d2f 100644 --- a/crates/replace/Cargo.toml +++ b/crates/replace/Cargo.toml @@ -3,7 +3,7 @@ authors = ['Interlay'] description = 'Replace module' edition = '2018' name = 'replace' -version = '2.0.0-rc6' +version = '0.2.3' [dependencies.serde] version = '1.0.101' @@ -18,32 +18,31 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false -package = 'pallet-balances' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.primitive-types] default-features = false @@ -54,6 +53,10 @@ features= ['codec'] default-features = false path = '../vault-registry' +[dependencies.exchange-rate-oracle] +default-features = false +path = '../exchange-rate-oracle' + [dependencies.collateral] default-features = false path = '../collateral' @@ -72,7 +75,7 @@ path = '../bitcoin' [dependencies.sha2] default-features = false -version = '0.8.0' +version = "0.8.2" [dependencies.security] default-features = false @@ -81,14 +84,16 @@ path = '../security' [dependencies.timestamp] default-features = false package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' + +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true [dev-dependencies] mocktopus = '0.7.0' - -[dev-dependencies.exchange-rate-oracle] -default-features = false -path = '../exchange-rate-oracle' +frame-benchmarking = { version = "2.0.0" } [features] default = ['std'] @@ -104,6 +109,7 @@ std = [ 'sp-std/std', 'primitive-types/std', 'vault-registry/std', + 'exchange-rate-oracle/std', 'collateral/std', 'btc-relay/std', 'treasury/std', @@ -111,4 +117,10 @@ std = [ 'sha2/std', 'security/std', 'timestamp/std', + 'frame-benchmarking/std', ] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] \ No newline at end of file diff --git a/crates/replace/rpc/Cargo.toml b/crates/replace/rpc/Cargo.toml new file mode 100644 index 0000000000..5ca5632608 --- /dev/null +++ b/crates/replace/rpc/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "module-replace-rpc" +version = '0.2.3' +authors = ["Interlay Ltd"] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", features = ["derive"] } +codec = { package = "parity-scale-codec", version = '1.3.4' } +jsonrpc-core = "15.0.0" +jsonrpc-core-client = "15.0.0" +jsonrpc-derive = "15.0.0" +sp-runtime = { version = "2.0.0" } +sp-api = { version = "2.0.0" } +sp-blockchain = { version = "2.0.0" } +module-replace-rpc-runtime-api = { path = "runtime-api" } diff --git a/crates/replace/rpc/runtime-api/Cargo.toml b/crates/replace/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..16cba62fe8 --- /dev/null +++ b/crates/replace/rpc/runtime-api/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "module-replace-rpc-runtime-api" +version = '0.2.3' +authors = ["Interlay Ltd"] +edition = "2018" + +[dependencies] +codec = { package = "parity-scale-codec", version = '1.3.4', default-features = false, features = ["derive"] } +sp-api = { version = "2.0.0", default-features = false } +frame-support = { version = "2.0.0", default-features = false } +sp-std = { version = "2.0.0", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", + "sp-std/std", + "frame-support/std", +] \ No newline at end of file diff --git a/crates/replace/rpc/runtime-api/src/lib.rs b/crates/replace/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..a93346259c --- /dev/null +++ b/crates/replace/rpc/runtime-api/src/lib.rs @@ -0,0 +1,20 @@ +//! Runtime API definition for the Replace Module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use sp_std::vec::Vec; + +sp_api::decl_runtime_apis! { + pub trait ReplaceApi where + AccountId: Codec, + H256: Codec, + ReplaceRequest: Codec, + { + /// Get all replace requests from a particular vault + fn get_old_vault_replace_requests(account_id: AccountId) -> Vec<(H256, ReplaceRequest)>; + + /// Get all replace requests to a particular vault + fn get_new_vault_replace_requests(account_id: AccountId) -> Vec<(H256, ReplaceRequest)>; + } +} diff --git a/crates/replace/rpc/src/lib.rs b/crates/replace/rpc/src/lib.rs new file mode 100644 index 0000000000..6232ba3451 --- /dev/null +++ b/crates/replace/rpc/src/lib.rs @@ -0,0 +1,100 @@ +//! RPC interface for the Replace Module. + +use codec::Codec; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use std::sync::Arc; + +pub use self::gen_client::Client as ReplaceClient; +pub use module_replace_rpc_runtime_api::ReplaceApi as ReplaceRuntimeApi; + +#[rpc] +pub trait ReplaceApi { + #[rpc(name = "replace_getOldVaultReplaceRequests")] + fn get_old_vault_replace_requests( + &self, + account_id: AccountId, + at: Option, + ) -> Result>; + + #[rpc(name = "replace_getNewVaultReplaceRequests")] + fn get_new_vault_replace_requests( + &self, + account_id: AccountId, + at: Option, + ) -> Result>; +} + +/// A struct that implements the [`ReplaceApi`]. +pub struct Replace { + client: Arc, + _marker: std::marker::PhantomData, +} + +impl Replace { + /// Create new `Replace` with the given reference to the client. + pub fn new(client: Arc) -> Self { + Replace { + client, + _marker: Default::default(), + } + } +} + +pub enum Error { + RuntimeError, +} + +impl From for i64 { + fn from(e: Error) -> i64 { + match e { + Error::RuntimeError => 1, + } + } +} + +impl + ReplaceApi<::Hash, AccountId, H256, ReplaceRequest> for Replace +where + Block: BlockT, + C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: ReplaceRuntimeApi, + AccountId: Codec, + H256: Codec, + ReplaceRequest: Codec, +{ + fn get_old_vault_replace_requests( + &self, + account_id: AccountId, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + api.get_old_vault_replace_requests(&at, account_id) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to fetch replace requests.".into(), + data: Some(format!("{:?}", e).into()), + }) + } + + fn get_new_vault_replace_requests( + &self, + account_id: AccountId, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + api.get_new_vault_replace_requests(&at, account_id) + .map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to fetch replace requests.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/crates/replace/src/benchmarking.rs b/crates/replace/src/benchmarking.rs new file mode 100644 index 0000000000..c9fa8055f2 --- /dev/null +++ b/crates/replace/src/benchmarking.rs @@ -0,0 +1,230 @@ +use super::*; +use crate::types::ReplaceRequest; +use crate::Module as Replace; +use bitcoin::formatter::Formattable; +use bitcoin::types::{ + Address, BlockBuilder, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, + TransactionOutput, +}; +use btc_relay::Module as BtcRelay; +use collateral::Module as Collateral; +use exchange_rate_oracle::Module as ExchangeRateOracle; +use frame_benchmarking::{account, benchmarks}; +use frame_system::Module as System; +use frame_system::RawOrigin; +use sp_core::{H160, H256, U256}; +use sp_std::prelude::*; +use vault_registry::types::{Vault, Wallet}; +use vault_registry::Module as VaultRegistry; + +benchmarks! { + _ {} + + request_replace { + let vault_id: T::AccountId = account("Vault", 0, 0); + let amount = 100; + let griefing = 100; + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + vault.issued_tokens = 100.into(); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(vault_id), amount.into(), griefing.into()) + + withdraw_replace { + let vault_id: T::AccountId = account("Vault", 0, 0); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + let replace_id = H256::zero(); + let mut replace_request = ReplaceRequest::default(); + replace_request.old_vault = vault_id.clone(); + Replace::::insert_replace_request(replace_id, replace_request); + + }: _(RawOrigin::Signed(vault_id), replace_id) + + accept_replace { + let vault_id: T::AccountId = account("Vault", 0, 0); + let amount = 100; + let collateral = 1000; + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + Collateral::::lock_collateral(&vault_id, 100000000.into()).unwrap(); + ExchangeRateOracle::::_set_exchange_rate(1).unwrap(); + VaultRegistry::::_set_secure_collateral_threshold(1); + + let replace_id = H256::zero(); + let mut replace_request = ReplaceRequest::default(); + replace_request.old_vault = vault_id.clone(); + replace_request.amount = amount.into(); + Replace::::insert_replace_request(replace_id, replace_request); + + }: _(RawOrigin::Signed(vault_id), replace_id, collateral.into()) + + auction_replace { + let old_vault_id: T::AccountId = account("Origin", 0, 0); + let new_vault_id: T::AccountId = account("Vault", 0, 0); + let btc_amount = 100; + let collateral = 1000; + + let mut old_vault = Vault::default(); + old_vault.id = old_vault_id.clone(); + old_vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + old_vault.issued_tokens = 123897.into(); + VaultRegistry::::_insert_vault( + &old_vault_id, + old_vault + ); + + let mut new_vault = Vault::default(); + new_vault.id = new_vault_id.clone(); + new_vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &new_vault_id, + new_vault + ); + + ExchangeRateOracle::::_set_exchange_rate(1).unwrap(); + VaultRegistry::::_set_auction_collateral_threshold(1); + VaultRegistry::::_set_secure_collateral_threshold(1); + + }: _(RawOrigin::Signed(new_vault_id), old_vault_id, btc_amount.into(), collateral.into()) + + execute_replace { + let new_vault_id: T::AccountId = account("Origin", 0, 0); + let old_vault_id: T::AccountId = account("Vault", 0, 0); + + let replace_id = H256::zero(); + let mut replace_request = ReplaceRequest::default(); + replace_request.old_vault = old_vault_id.clone(); + replace_request.new_vault = Some(new_vault_id.clone()); + Replace::::insert_replace_request(replace_id, replace_request); + + let mut old_vault = Vault::default(); + old_vault.id = old_vault_id.clone(); + old_vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &old_vault_id, + old_vault + ); + + let mut new_vault = Vault::default(); + new_vault.id = new_vault_id.clone(); + new_vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &new_vault_id, + new_vault + ); + + + let address = Address::from([0; 20]); + let mut height = 0; + + let block = BlockBuilder::new() + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + + let block_hash = block.header.hash(); + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_initialize(block_header, height).unwrap(); + + height += 1; + + let value = 0; + let transaction = TransactionBuilder::new() + .with_version(2) + .add_input( + TransactionInputBuilder::new() + .with_coinbase(false) + .with_previous_hash(block.transactions[0].hash()) + .build(), + ) + .add_output(TransactionOutput::p2pkh(value.into(), &address)) + .add_output(TransactionOutput::op_return(0, H256::zero().as_bytes())) + .build(); + + let block = BlockBuilder::new() + .with_previous_hash(block_hash) + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .add_transaction(transaction.clone()) + .mine(U256::from(2).pow(254.into())); + + let tx_id = transaction.tx_id(); + let tx_block_height = height; + let proof = block.merkle_proof(&vec![tx_id]).format(); + let raw_tx = transaction.format_with(true); + + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_store_block_header(block_header).unwrap(); + + }: _(RawOrigin::Signed(old_vault_id), replace_id, tx_id, tx_block_height, proof, raw_tx) + + cancel_replace { + let origin: T::AccountId = account("Origin", 0, 0); + let vault_id: T::AccountId = account("Vault", 0, 0); + + let replace_id = H256::zero(); + let mut replace_request = ReplaceRequest::default(); + replace_request.old_vault = vault_id.clone(); + Replace::::insert_replace_request(replace_id, replace_request); + + System::::set_block_number(100.into()); + + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + }: _(RawOrigin::Signed(origin), replace_id) + +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_benchmarks() { + ExtBuilder::build_with(pallet_balances::GenesisConfig:: { + balances: vec![ + (account("Origin", 0, 0), 1 << 32), + (account("Vault", 0, 0), 1 << 32), + ], + }) + .execute_with(|| { + assert_ok!(test_benchmark_request_replace::()); + assert_ok!(test_benchmark_withdraw_replace::()); + assert_ok!(test_benchmark_accept_replace::()); + assert_ok!(test_benchmark_auction_replace::()); + assert_ok!(test_benchmark_execute_replace::()); + assert_ok!(test_benchmark_cancel_replace::()); + }); + } +} diff --git a/crates/replace/src/default_weights.rs b/crates/replace/src/default_weights.rs new file mode 100644 index 0000000000..3bbd013071 --- /dev/null +++ b/crates/replace/src/default_weights.rs @@ -0,0 +1,39 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + fn request_replace() -> Weight { + (142_819_000 as Weight) + .saturating_add(DbWeight::get().reads(6 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } + fn withdraw_replace() -> Weight { + (132_256_000 as Weight) + .saturating_add(DbWeight::get().reads(10 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn accept_replace() -> Weight { + (124_104_000 as Weight) + .saturating_add(DbWeight::get().reads(10 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn auction_replace() -> Weight { + (188_428_000 as Weight) + .saturating_add(DbWeight::get().reads(13 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } + fn execute_replace() -> Weight { + (218_546_000 as Weight) + .saturating_add(DbWeight::get().reads(12 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn cancel_replace() -> Weight { + (97_129_000 as Weight) + .saturating_add(DbWeight::get().reads(5 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } +} diff --git a/crates/replace/src/ext.rs b/crates/replace/src/ext.rs index 11bdf266f4..cc2bcbfdf5 100644 --- a/crates/replace/src/ext.rs +++ b/crates/replace/src/ext.rs @@ -73,7 +73,7 @@ pub(crate) mod vault_registry { pub fn is_vault_below_auction_threshold( vault_id: T::AccountId, ) -> Result { - >::_is_vault_below_auction_threshold(&vault_id) + >::is_vault_below_auction_threshold(&vault_id) } pub fn is_collateral_below_secure_threshold( diff --git a/crates/replace/src/lib.rs b/crates/replace/src/lib.rs index d0f220d203..4002bb12cc 100644 --- a/crates/replace/src/lib.rs +++ b/crates/replace/src/lib.rs @@ -2,15 +2,20 @@ #![cfg_attr(test, feature(proc_macro_hygiene))] #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] extern crate mocktopus; // Substrate +use frame_support::weights::Weight; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::{DispatchError, DispatchResult}, ensure, - traits::Get, }; use frame_system::ensure_signed; #[cfg(test)] @@ -22,7 +27,8 @@ use sp_std::vec::Vec; use bitcoin::types::H256Le; -use crate::types::{PolkaBTC, Replace, DOT}; +pub use crate::types::ReplaceRequest; +use crate::types::{PolkaBTC, DOT}; /// # PolkaBTC Replace implementation /// The Replace module according to the specification at @@ -39,6 +45,15 @@ mod tests; /// The replace module id, used for deriving its sovereign account ID. const _MODULE_ID: ModuleId = ModuleId(*b"replacem"); +pub trait WeightInfo { + fn request_replace() -> Weight; + fn withdraw_replace() -> Weight; + fn accept_replace() -> Weight; + fn auction_replace() -> Weight; + fn execute_replace() -> Weight; + fn cancel_replace() -> Weight; +} + /// The pallet's configuration trait. pub trait Trait: frame_system::Trait + vault_registry::Trait + collateral::Trait + btc_relay::Trait + treasury::Trait @@ -46,17 +61,28 @@ pub trait Trait: /// The overarching event type. type Event: From> + Into<::Event>; - /// The time difference in number of blocks between an issue request is created - /// and required completion time by a user. The issue period has an upper limit - /// to prevent griefing of vault collateral. - type ReplacePeriod: Get; + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; } // The pallet's storage items. decl_storage! { trait Store for Module as Replace { - ReplaceGriefingCollateral: DOT; - ReplaceRequests: map hasher(blake2_128_concat) H256 => Option, DOT>>; + /// Vaults create replace requests to transfer locked collateral. + /// This mapping provides access from a unique hash to a `ReplaceRequest`. + ReplaceRequests: map hasher(blake2_128_concat) H256 => Option, DOT>>; + + /// The minimum collateral (DOT) a user needs to provide as griefing protection. + ReplaceGriefingCollateral get(fn replace_griefing_collateral) config(): DOT; + + /// The time difference in number of blocks between when a replace request is created + /// and required completion time by a vault. The replace period has an upper limit + /// to prevent griefing of vault collateral. + ReplacePeriod get(fn replace_period) config(): T::BlockNumber; + + /// The minimum amount of btc that is accepted for replace requests; any lower values would + /// risk the bitcoin client to reject the payment + ReplaceBtcDustValue get(fn replace_btc_dust_value) config(): PolkaBTC; } } @@ -71,7 +97,7 @@ decl_event!( { RequestReplace(AccountId, PolkaBTC, H256), WithdrawReplace(AccountId, H256), - AcceptReplace(AccountId, H256, DOT), + AcceptReplace(AccountId, AccountId, H256, DOT, PolkaBTC), ExecuteReplace(AccountId, AccountId, H256), AuctionReplace(AccountId, AccountId, H256, PolkaBTC, DOT, BlockNumber), CancelReplace(AccountId, AccountId, H256), @@ -86,7 +112,8 @@ decl_module! { // this is needed only if you are using events in your pallet fn deposit_event() = default; - const ReplacePeriod: T::BlockNumber = T::ReplacePeriod::get(); + // Errors must be initialized if they are used by the pallet. + type Error = Error; /// Request the replacement of a new vault ownership /// @@ -95,7 +122,7 @@ decl_module! { /// * `origin` - sender of the transaction /// * `amount` - amount of PolkaBTC /// * `griefing_collateral` - amount of DOT - #[weight = 1000] + #[weight = ::WeightInfo::request_replace()] fn request_replace(origin, amount: PolkaBTC, griefing_collateral: DOT) -> DispatchResult { @@ -110,7 +137,7 @@ decl_module! { /// /// * `origin` - sender of the transaction: the old vault /// * `replace_id` - the unique identifier of the replace request - #[weight = 1000] + #[weight = ::WeightInfo::withdraw_replace()] fn withdraw_replace(origin, replace_id: H256) -> DispatchResult { @@ -126,7 +153,7 @@ decl_module! { /// * `origin` - the initiator of the transaction: the new vault /// * `replace_id` - the unique identifier for the specific request /// * `collateral` - the collateral for replacement - #[weight = 1000] + #[weight = ::WeightInfo::accept_replace()] fn accept_replace(origin, replace_id: H256, collateral: DOT) -> DispatchResult { @@ -143,7 +170,7 @@ decl_module! { /// * `old_vault` - the old vault of the replacement request /// * `btc_amount` - the btc amount to be transferred over from old to new /// * `collateral` - the collateral to be transferred over from old to new - #[weight = 1000] + #[weight = ::WeightInfo::auction_replace()] fn auction_replace(origin, old_vault: T::AccountId, btc_amount: PolkaBTC, collateral: DOT) -> DispatchResult { @@ -162,10 +189,10 @@ decl_module! { /// * `tx_block_height` - the blocked height of the backing transaction /// * 'merkle_proof' - the merkle root of the block /// * `raw_tx` - the transaction id in bytes - #[weight = 1000] + #[weight = ::WeightInfo::execute_replace()] fn execute_replace(origin, replace_id: H256, tx_id: H256Le, _tx_block_height: u32, merkle_proof: Vec, raw_tx: Vec) -> DispatchResult { - let new_vault = ensure_signed(origin)?; - Self::_execute_replace(new_vault, replace_id, tx_id, merkle_proof, raw_tx)?; + let old_vault = ensure_signed(origin)?; + Self::_execute_replace(old_vault, replace_id, tx_id, merkle_proof, raw_tx)?; Ok(()) } @@ -175,7 +202,7 @@ decl_module! { /// /// * `origin` - sender of the transaction: the new vault /// * `replace_id` - the ID of the replacement request - #[weight = 1000] + #[weight = ::WeightInfo::cancel_replace()] fn cancel_replace(origin, replace_id: H256) -> DispatchResult { let new_vault = ensure_signed(origin)?; Self::_cancel_replace(new_vault, replace_id)?; @@ -192,23 +219,24 @@ impl Module { mut amount: PolkaBTC, griefing_collateral: DOT, ) -> DispatchResult { - // Check that Parachain status is RUNNING + // step 1: Check that Parachain status is RUNNING ext::security::ensure_parachain_status_running::()?; - // check amount is non zero - let zero: PolkaBTC = 0u32.into(); - if amount == zero { - return Err(Error::::InvalidAmount.into()); - } // check vault exists let vault = ext::vault_registry::get_vault_from_id::(&vault_id)?; + // step 3: check vault is not banned let height = Self::current_height(); ext::vault_registry::ensure_not_banned::(&vault_id, height)?; + // step 4: check that the amount doesn't exceed the remaining available tokens if amount > vault.issued_tokens { amount = vault.issued_tokens; } + // check amount is above the minimum + let dust_value = >::get(); + ensure!(amount >= dust_value, Error::::AmountBelowDustAmount); + // step 5: If the request is not for the entire BTC holdings, check that the remaining DOT collateral of the Vault is higher than MinimumCollateralVault let vault_collateral = ext::collateral::get_collateral_from_account::(vault_id.clone()); if amount != vault.issued_tokens { @@ -216,19 +244,24 @@ impl Module { ext::vault_registry::is_over_minimum_collateral::(vault_collateral); ensure!(over_threshold, Error::::InsufficientCollateral); } + // step 6: Check that the griefingCollateral is greater or equal ReplaceGriefingCollateral ensure!( griefing_collateral >= >::get(), Error::::InsufficientCollateral ); + // step 7: Lock the oldVault’s griefing collateral ext::collateral::lock_collateral::(vault_id.clone(), griefing_collateral)?; + // step 8: Call the increaseToBeRedeemedTokens function with the oldVault and the btcAmount to ensure that the oldVault’s tokens cannot be redeemed when a replace procedure is happening. ext::vault_registry::increase_to_be_redeemed_tokens::(&vault_id, amount.clone())?; + // step 9: Generate a replaceId by hashing a random seed, a nonce, and the address of the Requester. let replace_id = ext::security::get_secure_id::(&vault_id); + // step 10: Create new ReplaceRequest entry: - let replace = Replace { + let replace = ReplaceRequest { old_vault: vault_id.clone(), open_time: height, amount, @@ -236,12 +269,12 @@ impl Module { new_vault: None, collateral: vault_collateral, accept_time: None, - btc_address: vault.btc_address, + btc_address: vault.wallet.get_btc_address(), }; Self::insert_replace_request(replace_id, replace); + // step 11: Emit RequestReplace event Self::deposit_event(>::RequestReplace(vault_id, amount, replace_id)); - // step 12 Ok(()) } @@ -252,30 +285,37 @@ impl Module { // check vault exists // step 1: Retrieve the ReplaceRequest as per the replaceId parameter from Vaults in the VaultRegistry let replace = Self::get_replace_request(&request_id)?; + // step 2: Check that caller of the function is indeed the to-be-replaced Vault as specified in the ReplaceRequest. Return ERR_UNAUTHORIZED error if this check fails. let _vault = ext::vault_registry::get_vault_from_id::(&vault_id)?; ensure!(vault_id == replace.old_vault, Error::::UnauthorizedVault); + // step 3: Check that the collateral rate of the vault is not under the AuctionCollateralThreshold as defined in the VaultRegistry. If it is under the AuctionCollateralThreshold return ERR_UNAUTHORIZED ensure!( !ext::vault_registry::is_vault_below_auction_threshold::(vault_id.clone())?, Error::::VaultOverAuctionThreshold ); + // step 4: Check that the ReplaceRequest was not yet accepted by another Vault if replace.has_new_owner() { return Err(Error::::CancelAcceptedRequest.into()); } + // step 5: Release the oldVault’s griefing collateral associated with this ReplaceRequests ext::collateral::release_collateral::( replace.old_vault.clone(), replace.griefing_collateral.clone(), )?; + // step 6: Call the decreaseToBeRedeemedTokens function in the VaultRegistry to allow the vault to be part of other redeem or replace requests again ext::vault_registry::decrease_to_be_redeemed_tokens::( replace.old_vault, replace.amount.clone(), )?; + // step 7: Remove the ReplaceRequest from ReplaceRequests Self::remove_replace_request(request_id); + // step 8: Emit a WithdrawReplaceRequest(oldVault, replaceId) event. Self::deposit_event(>::WithdrawReplace(vault_id, request_id)); Ok(()) @@ -288,29 +328,44 @@ impl Module { ) -> Result<(), DispatchError> { // Check that Parachain status is RUNNING ext::security::ensure_parachain_status_running::()?; - // step 1: Retrieve the ReplaceRequest as per the replaceId parameter from ReplaceRequests. Return ERR_REPLACE_ID_NOT_FOUND error if no such ReplaceRequest was found. + + // step 1: Retrieve the ReplaceRequest as per the replaceId parameter from ReplaceRequests. + // Return ERR_REPLACE_ID_NOT_FOUND error if no such ReplaceRequest was found. let mut replace = Self::get_replace_request(&replace_id)?; + // step 2: Retrieve the Vault as per the newVault parameter from Vaults in the VaultRegistry let vault = ext::vault_registry::get_vault_from_id::(&new_vault_id)?; + // step 3: Check that the newVault is currently not banned let height = Self::current_height(); ext::vault_registry::ensure_not_banned::(&new_vault_id, height)?; + // step 4: Check that the provided collateral exceeds the necessary amount let is_below = ext::vault_registry::is_collateral_below_secure_threshold::( collateral, replace.amount, )?; ensure!(!is_below, Error::::InsufficientCollateral); + // step 5: Lock the newVault’s collateral by calling lockCollateral ext::collateral::lock_collateral::(new_vault_id.clone(), collateral)?; + // step 6: Update the ReplaceRequest entry - replace.add_new_vault(new_vault_id.clone(), height, collateral, vault.btc_address); - Self::insert_replace_request(replace_id, replace); + replace.add_new_vault( + new_vault_id.clone(), + height, + collateral, + vault.wallet.get_btc_address(), + ); + Self::insert_replace_request(replace_id, replace.clone()); + // step 7: Emit a AcceptReplace(newVault, replaceId, collateral) event Self::deposit_event(>::AcceptReplace( + replace.old_vault, new_vault_id, replace_id, collateral, + replace.amount, )); Ok(()) } @@ -348,14 +403,14 @@ impl Module { let current_height = Self::current_height(); Self::insert_replace_request( replace_id, - Replace { + ReplaceRequest { new_vault: Some(new_vault_id.clone()), old_vault: old_vault_id.clone(), open_time: current_height, accept_time: Some(current_height), amount: btc_amount, griefing_collateral: 0.into(), - btc_address: new_vault.btc_address, + btc_address: new_vault.wallet.get_btc_address(), collateral: collateral, }, ); @@ -372,7 +427,7 @@ impl Module { } fn _execute_replace( - new_vault_id: T::AccountId, + old_vault_id: T::AccountId, replace_id: H256, tx_id: H256Le, merkle_proof: Vec, @@ -380,8 +435,21 @@ impl Module { ) -> Result<(), DispatchError> { // Check that Parachain status is RUNNING ext::security::ensure_parachain_status_running::()?; + // step 1: Retrieve the ReplaceRequest as per the replaceId parameter from Vaults in the VaultRegistry let replace = Self::get_replace_request(&replace_id)?; + // since the old vault makes the transfer they should also be responsible for execution + ensure!( + replace.old_vault == old_vault_id, + Error::::UnauthorizedVault + ); + + if replace.new_vault.is_none() { + // cannot execute without a replacement + return Err(Error::::NoReplacement.into()); + } + let new_vault_id = replace.new_vault.unwrap(); + // step 2: Check that the current Parachain block height minus the ReplacePeriod is smaller than the opentime of the ReplaceRequest let replace_period = Self::replace_period(); let current_height = Self::current_height(); @@ -389,10 +457,13 @@ impl Module { current_height <= replace.open_time + replace_period, Error::::ReplacePeriodExpired ); + // step 3: Retrieve the Vault as per the newVault parameter from Vaults in the VaultRegistry let _new_vault = ext::vault_registry::get_vault_from_id::(&new_vault_id)?; + // step 4: Call verifyTransactionInclusion in BTC-Relay, providing txid, txBlockHeight, txIndex, and merkleProof as parameters ext::btc_relay::verify_transaction_inclusion::(tx_id, merkle_proof)?; + // step 5: Call validateTransaction in BTC-Relay let amount = TryInto::::try_into(replace.amount) .map_err(|_e| Error::::ConversionError)? as i64; @@ -403,24 +474,28 @@ impl Module { replace.btc_address.as_bytes().to_vec(), replace_id.clone().as_bytes().to_vec(), )?; + // step 6: Call the replaceTokens ext::vault_registry::replace_tokens::( - replace.old_vault.clone(), + old_vault_id.clone(), new_vault_id.clone(), replace.amount.clone(), replace.collateral.clone(), )?; + // step 7: Call the releaseCollateral function to release the oldVaults griefing collateral griefingCollateral ext::collateral::release_collateral::( - replace.old_vault.clone(), + old_vault_id.clone(), replace.griefing_collateral, )?; + // step 8: Emit the ExecuteReplace(oldVault, newVault, replaceId) event. Self::deposit_event(>::ExecuteReplace( - replace.old_vault, + old_vault_id, new_vault_id, replace_id, )); + // step 9: Remove replace request Self::remove_replace_request(replace_id.clone()); Ok(()) @@ -461,23 +536,58 @@ impl Module { Ok(()) } + /// Fetch all replace requests from the specified vault. + /// + /// # Arguments + /// + /// * `account_id` - user account id + pub fn get_replace_requests_for_old_vault( + account_id: T::AccountId, + ) -> Vec<( + H256, + ReplaceRequest, DOT>, + )> { + >::iter() + .filter(|(_, request)| request.old_vault == account_id) + .collect::>() + } + + /// Fetch all replace requests to the specified vault. + /// + /// # Arguments + /// + /// * `account_id` - user account id + pub fn get_replace_requests_for_new_vault( + account_id: T::AccountId, + ) -> Vec<( + H256, + ReplaceRequest, DOT>, + )> { + >::iter() + .filter(|(_, request)| { + if let Some(vault_id) = &request.new_vault { + vault_id == &account_id + } else { + false + } + }) + .collect::>() + } + pub fn get_replace_request( id: &H256, - ) -> Result, DOT>, DispatchError> { + ) -> Result, DOT>, DispatchError> + { >::get(id).ok_or(Error::::InvalidReplaceID.into()) } fn insert_replace_request( key: H256, - value: Replace, DOT>, + value: ReplaceRequest, DOT>, ) { >::insert(key, value) } - fn replace_period() -> T::BlockNumber { - T::ReplacePeriod::get() - } - fn remove_replace_request(key: H256) { >::remove(key) } @@ -494,7 +604,8 @@ impl Module { decl_error! { pub enum Error for Module { - InvalidAmount, + AmountBelowDustAmount, + NoReplacement, InsufficientCollateral, UnauthorizedVault, VaultOverAuctionThreshold, diff --git a/crates/replace/src/mock.rs b/crates/replace/src/mock.rs index bfb475af21..110d330f5e 100644 --- a/crates/replace/src/mock.rs +++ b/crates/replace/src/mock.rs @@ -1,5 +1,5 @@ /// Mocking the test environment -use crate::{Error, Module, Trait}; +use crate::{Error, GenesisConfig, Module, Trait}; use frame_support::{ assert_ok, impl_outer_event, impl_outer_origin, parameter_types, weights::{ @@ -75,7 +75,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -86,9 +86,11 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); @@ -99,6 +101,7 @@ impl pallet_balances::Trait for Test { impl vault_registry::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl collateral::Trait for Test { @@ -108,6 +111,7 @@ impl collateral::Trait for Test { impl btc_relay::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl security::Trait for Test { @@ -122,6 +126,7 @@ impl treasury::Trait for Test { parameter_types! { pub const MinimumPeriod: u64 = 5; } + impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); @@ -131,15 +136,12 @@ impl timestamp::Trait for Test { impl exchange_rate_oracle::Trait for Test { type Event = TestEvent; -} - -parameter_types! { - pub const ReplacePeriod: BlockNumber = 10; + type WeightInfo = (); } impl Trait for Test { type Event = TestEvent; - type ReplacePeriod = ReplacePeriod; + type WeightInfo = (); } pub type TestError = Error; @@ -161,23 +163,33 @@ pub const CAROL_BALANCE: u64 = 1_000_000; pub struct ExtBuilder; impl ExtBuilder { - pub fn build() -> sp_io::TestExternalities { + pub fn build_with(conf: pallet_balances::GenesisConfig) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, ALICE_BALANCE), - (BOB, BOB_BALANCE), - (CAROL, CAROL_BALANCE), - ], + conf.assimilate_storage(&mut storage).unwrap(); + + GenesisConfig:: { + replace_griefing_collateral: 10, + replace_period: 10, + replace_btc_dust_value: 2, } .assimilate_storage(&mut storage) .unwrap(); storage.into() } + + pub fn build() -> sp_io::TestExternalities { + ExtBuilder::build_with(pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, ALICE_BALANCE), + (BOB, BOB_BALANCE), + (CAROL, CAROL_BALANCE), + ], + }) + } } pub fn run_test(test: T) -> () diff --git a/crates/replace/src/tests.rs b/crates/replace/src/tests.rs index 405cf4872c..58bb192dc9 100644 --- a/crates/replace/src/tests.rs +++ b/crates/replace/src/tests.rs @@ -1,7 +1,7 @@ use crate::ext; use crate::mock::*; use crate::PolkaBTC; -use crate::Replace as R; +use crate::ReplaceRequest as R; use crate::DOT; use bitcoin::types::H256Le; use frame_support::{ @@ -11,7 +11,7 @@ use frame_support::{ use mocktopus::mocking::*; use primitive_types::H256; use sp_core::H160; -use vault_registry::{Vault, VaultStatus}; +use vault_registry::{Vault, VaultStatus, Wallet}; type Event = crate::Event; @@ -51,7 +51,7 @@ fn test_vault() -> Vault { id: BOB, banned_until: None, issued_tokens: 5, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160([0; 20])), to_be_issued_tokens: 0, to_be_redeemed_tokens: 0, status: VaultStatus::Active, @@ -104,7 +104,19 @@ fn cancel_replace(new_vault_id: AccountId, replace_id: H256) -> Result<(), Dispa #[test] fn test_request_replace_transfer_zero_fails() { run_test(|| { - assert_noop!(request_replace(BOB, 0, 0), TestError::InvalidAmount); + ext::vault_registry::ensure_not_banned::.mock_safe(|_, _| MockResult::Return(Ok(()))); + ext::vault_registry::get_vault_from_id::.mock_safe(|_| { + MockResult::Return(Ok(Vault { + id: BOB, + to_be_issued_tokens: 0, + issued_tokens: 100, + to_be_redeemed_tokens: 0, + wallet: Wallet::new(H160([0; 20])), + banned_until: None, + status: VaultStatus::Active, + })) + }); + assert_noop!(request_replace(BOB, 0, 0), TestError::AmountBelowDustAmount); }) } @@ -112,7 +124,7 @@ fn test_request_replace_transfer_zero_fails() { fn test_request_replace_vault_not_found_fails() { run_test(|| { assert_noop!( - request_replace(10_000, 1, 0), + request_replace(10_000, 5, 0), VaultRegistryError::VaultNotFound ); }) @@ -129,17 +141,50 @@ fn test_request_replace_vault_banned_fails() { to_be_issued_tokens: 0, issued_tokens: 0, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160([0; 20])), banned_until: Some(1), status: VaultStatus::Active, })) }); assert_noop!( - Replace::_request_replace(BOB, 1, 0), + Replace::_request_replace(BOB, 5, 0), VaultRegistryError::VaultBanned ); }) } +#[test] +fn test_request_replace_amount_below_dust_value_fails() { + run_test(|| { + let old_vault = BOB; + let griefing_collateral = 0; + let desired_griefing_collateral = 2; + + let amount = 1; + + ext::vault_registry::ensure_not_banned::.mock_safe(|_, _| MockResult::Return(Ok(()))); + + ext::vault_registry::get_vault_from_id::.mock_safe(|_| { + MockResult::Return(Ok(Vault { + id: BOB, + to_be_issued_tokens: 0, + issued_tokens: 10, + to_be_redeemed_tokens: 0, + wallet: Wallet::new(H160([0; 20])), + banned_until: None, + status: VaultStatus::Active, + })) + }); + ext::vault_registry::is_over_minimum_collateral:: + .mock_safe(|_| MockResult::Return(true)); + ext::collateral::get_collateral_from_account::.mock_safe(|_| MockResult::Return(1)); + + Replace::set_replace_griefing_collateral(desired_griefing_collateral); + assert_noop!( + Replace::_request_replace(old_vault, amount, griefing_collateral), + TestError::AmountBelowDustAmount + ); + }) +} #[test] fn test_request_replace_insufficient_griefing_collateral_fails() { @@ -148,7 +193,7 @@ fn test_request_replace_insufficient_griefing_collateral_fails() { let griefing_collateral = 0; let desired_griefing_collateral = 2; - let amount = 1; + let amount = 3; ext::vault_registry::ensure_not_banned::.mock_safe(|_, _| MockResult::Return(Ok(()))); @@ -158,7 +203,7 @@ fn test_request_replace_insufficient_griefing_collateral_fails() { to_be_issued_tokens: 0, issued_tokens: 10, to_be_redeemed_tokens: 0, - btc_address: H160([0; 20]), + wallet: Wallet::new(H160([0; 20])), banned_until: None, status: VaultStatus::Active, })) @@ -456,22 +501,24 @@ fn test_execute_replace_bad_replace_id_fails() { #[test] fn test_execute_replace_replace_period_expired_fails() { run_test(|| { - Replace::get_replace_request.mock_safe(|_| { - let mut req = test_request(); - req.open_time = 100_000; - MockResult::Return(Ok(req)) - }); - - let new_vault_id = ALICE; + let old_vault_id = ALICE; + let new_vault_id = BOB; let replace_id = H256::zero(); let tx_id = H256Le::zero(); let merkle_proof = Vec::new(); let raw_tx = Vec::new(); + Replace::get_replace_request.mock_safe(move |_| { + let mut req = test_request(); + req.open_time = 100_000; + req.new_vault = Some(new_vault_id); + MockResult::Return(Ok(req)) + }); + Replace::current_height.mock_safe(|| MockResult::Return(110_000)); Replace::replace_period.mock_safe(|| MockResult::Return(2)); assert_err!( - execute_replace(new_vault_id, replace_id, tx_id, merkle_proof, raw_tx), + execute_replace(old_vault_id, replace_id, tx_id, merkle_proof, raw_tx), TestError::ReplacePeriodExpired ); }) @@ -624,13 +671,16 @@ fn test_withdraw_replace_succeeds() { #[test] fn test_accept_replace_succeeds() { run_test(|| { - let vault_id = BOB; + let old_vault_id = ALICE; + let new_vault_id = BOB; let replace_id = H256::zero(); let collateral = 20_000; + let btc_amount = 100; - Replace::get_replace_request.mock_safe(|_| { + Replace::get_replace_request.mock_safe(move |_| { let mut replace = test_request(); - replace.old_vault = BOB; + replace.old_vault = old_vault_id; + replace.amount = btc_amount; MockResult::Return(Ok(replace)) }); @@ -644,9 +694,15 @@ fn test_accept_replace_succeeds() { ext::collateral::lock_collateral::.mock_safe(|_, _| MockResult::Return(Ok(()))); - assert_eq!(accept_replace(vault_id, replace_id, collateral), Ok(())); + assert_eq!(accept_replace(new_vault_id, replace_id, collateral), Ok(())); - let event = Event::AcceptReplace(vault_id, replace_id, collateral); + let event = Event::AcceptReplace( + old_vault_id, + new_vault_id, + replace_id, + collateral, + btc_amount, + ); assert_emitted!(event); }) } @@ -726,13 +782,16 @@ fn test_execute_replace_succeeds() { .mock_safe(|_, _| MockResult::Return(Ok(()))); ext::btc_relay::validate_transaction:: .mock_safe(|_, _, _, _| MockResult::Return(Ok(()))); + ext::vault_registry::replace_tokens:: .mock_safe(|_, _, _, _| MockResult::Return(Ok(()))); + ext::collateral::release_collateral::.mock_safe(|_, _| MockResult::Return(Ok(()))); + Replace::remove_replace_request.mock_safe(|_| MockResult::Return(())); assert_eq!( - execute_replace(new_vault_id, replace_id, tx_id, merkle_proof, raw_tx), + execute_replace(old_vault_id, replace_id, tx_id, merkle_proof, raw_tx), Ok(()) ); @@ -755,7 +814,7 @@ fn test_cancel_replace_succeeds() { replace.open_time = 2; MockResult::Return(Ok(replace)) }); - Replace::current_height.mock_safe(|| MockResult::Return(10)); + Replace::current_height.mock_safe(|| MockResult::Return(15)); Replace::replace_period.mock_safe(|| MockResult::Return(2)); ext::vault_registry::decrease_to_be_redeemed_tokens:: .mock_safe(|_, _| MockResult::Return(Ok(()))); diff --git a/crates/replace/src/types.rs b/crates/replace/src/types.rs index 5b519bbc37..9eaec8ff74 100644 --- a/crates/replace/src/types.rs +++ b/crates/replace/src/types.rs @@ -2,25 +2,69 @@ use codec::{Decode, Encode}; use frame_support::traits::Currency; use sp_core::H160; +#[cfg(feature = "std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + pub(crate) type DOT = <::DOT as Currency<::AccountId>>::Balance; pub(crate) type PolkaBTC = <::PolkaBTC as Currency<::AccountId>>::Balance; +// Due to a known bug in serde we need to specify how u128 is (de)serialized. +// See https://github.com/paritytech/substrate/issues/4641 #[derive(Encode, Decode, Default, Clone, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct Replace { +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct ReplaceRequest { pub old_vault: AccountId, pub open_time: BlockNumber, + #[cfg_attr( + feature = "std", + serde(bound(deserialize = "PolkaBTC: std::str::FromStr")) + )] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr( + feature = "std", + serde(bound(serialize = "PolkaBTC: std::fmt::Display")) + )] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub amount: PolkaBTC, + #[cfg_attr(feature = "std", serde(bound(deserialize = "DOT: std::str::FromStr")))] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr(feature = "std", serde(bound(serialize = "DOT: std::fmt::Display")))] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub griefing_collateral: DOT, pub new_vault: Option, + #[cfg_attr(feature = "std", serde(bound(deserialize = "DOT: std::str::FromStr")))] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + #[cfg_attr(feature = "std", serde(bound(serialize = "DOT: std::fmt::Display")))] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] pub collateral: DOT, pub accept_time: Option, pub btc_address: H160, } -impl Replace { +// todo: serialize_as_string deserialize_from_string are defined multiple times +// throughout the code; Maybe this should be merged.. Although it should only +// be only a temporary workaround) + +#[cfg(feature = "std")] +fn serialize_as_string( + t: &T, + serializer: S, +) -> Result { + serializer.serialize_str(&t.to_string()) +} + +#[cfg(feature = "std")] +fn deserialize_from_string<'de, D: Deserializer<'de>, T: std::str::FromStr>( + deserializer: D, +) -> Result { + let s = String::deserialize(deserializer)?; + s.parse::() + .map_err(|_| serde::de::Error::custom("Parse from string failed")) +} + +impl ReplaceRequest { pub fn add_new_vault( &mut self, new_vault_id: AccountId, diff --git a/crates/security/Cargo.toml b/crates/security/Cargo.toml index 2a0dfcd12c..9ef0973078 100644 --- a/crates/security/Cargo.toml +++ b/crates/security/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "security" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" @@ -17,19 +17,19 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.primitive-types] default-features = false @@ -38,15 +38,15 @@ features= ['codec'] [dependencies.sha2] default-features = false -version = '0.8.0' +version = "0.8.2" [dev-dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dev-dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dev-dependencies] mocktopus = '0.7.0' diff --git a/crates/security/src/lib.rs b/crates/security/src/lib.rs index e46dd806ed..c92687d009 100644 --- a/crates/security/src/lib.rs +++ b/crates/security/src/lib.rs @@ -275,6 +275,7 @@ impl Module { let mut hasher = Sha256::default(); hasher.input(id.encode()); hasher.input(Self::get_nonce().encode()); + hasher.input(frame_system::Module::::parent_hash()); let mut result = [0; 32]; result.copy_from_slice(&hasher.result()[..]); H256(result) diff --git a/crates/security/src/mock.rs b/crates/security/src/mock.rs index 2115f6f142..3b0c936e56 100644 --- a/crates/security/src/mock.rs +++ b/crates/security/src/mock.rs @@ -67,7 +67,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = (); diff --git a/crates/security/src/tests.rs b/crates/security/src/tests.rs index 37ed5ec3eb..6272ecb887 100644 --- a/crates/security/src/tests.rs +++ b/crates/security/src/tests.rs @@ -2,6 +2,7 @@ use crate::mock::*; use crate::ErrorCode; use crate::StatusCode; use frame_support::{assert_noop, assert_ok, dispatch::DispatchResult}; +use sp_core::H256; type Event = crate::Event; @@ -184,6 +185,20 @@ fn test_get_nonce() { #[test] fn test_get_secure_id() { + run_test(|| { + frame_system::Module::::set_parent_hash(H256::zero()); + assert_eq!( + Security::_get_secure_id(&1), + H256::from_slice(&[ + 71, 121, 67, 63, 246, 65, 71, 242, 66, 184, 148, 234, 23, 56, 62, 52, 108, 82, 213, + 33, 160, 200, 214, 1, 13, 46, 37, 138, 95, 245, 117, 109 + ]) + ); + }) +} + +#[test] +fn test_get_secure_ids_not_equal() { run_test(|| { let left = Security::_get_secure_id(&1); let right = Security::_get_secure_id(&1); diff --git a/crates/staked-relayers/Cargo.toml b/crates/staked-relayers/Cargo.toml index eb799b5638..5625f5751d 100644 --- a/crates/staked-relayers/Cargo.toml +++ b/crates/staked-relayers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "staked-relayers" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" @@ -17,32 +17,31 @@ version = '1.3.4' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' -[dependencies.timestamp] +[dependencies.pallet-timestamp] default-features = false -package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.primitive-types] default-features = false @@ -87,20 +86,24 @@ path = '../replace' [dependencies.sha2] default-features = false -version = '0.8.0' +version = "0.8.2" [dependencies.hex] default-features = false version = '0.4.2' -[dev-dependencies.balances] +[dev-dependencies.pallet-balances] default-features = false -package = 'pallet-balances' -version = '2.0.0-rc6' +version = '2.0.0' + +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true [dev-dependencies] -mocktopus = '0.7.0' -hex = '0.4.2' +mocktopus = "0.7.0" +frame-benchmarking = { version = "2.0.0" } [features] default = ['std'] @@ -111,7 +114,7 @@ std = [ 'sp-runtime/std', 'sp-io/std', 'frame-system/std', - 'timestamp/std', + 'pallet-timestamp/std', 'sp-core/std', 'sp-std/std', 'primitive-types/std', @@ -125,4 +128,11 @@ std = [ 'redeem/std', 'replace/std', 'sha2/std', -] \ No newline at end of file + 'hex/std', + 'frame-benchmarking/std', +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] diff --git a/crates/staked-relayers/rpc/Cargo.toml b/crates/staked-relayers/rpc/Cargo.toml index 09cd65e1f3..77e4303441 100644 --- a/crates/staked-relayers/rpc/Cargo.toml +++ b/crates/staked-relayers/rpc/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "module-staked-relayers-rpc" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" [dependencies] serde = { version = "1.0.101", features = ["derive"] } codec = { package = "parity-scale-codec", version = '1.3.4' } -jsonrpc-core = "14.0.5" -jsonrpc-core-client = "14.0.5" -jsonrpc-derive = "14.0.5" -sp-runtime = { version = "2.0.0-rc6" } -sp-api = { version = "2.0.0-rc6" } -sp-blockchain = { version = "2.0.0-rc6" } +jsonrpc-core = "15.0.0" +jsonrpc-core-client = "15.0.0" +jsonrpc-derive = "15.0.0" +sp-runtime = { version = "2.0.0" } +sp-api = { version = "2.0.0" } +sp-blockchain = { version = "2.0.0" } module-staked-relayers-rpc-runtime-api = { path = "runtime-api" } diff --git a/crates/staked-relayers/rpc/runtime-api/Cargo.toml b/crates/staked-relayers/rpc/runtime-api/Cargo.toml index d57d9e3fa5..f44afb096b 100644 --- a/crates/staked-relayers/rpc/runtime-api/Cargo.toml +++ b/crates/staked-relayers/rpc/runtime-api/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "module-staked-relayers-rpc-runtime-api" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" [dependencies] codec = { package = "parity-scale-codec", version = '1.3.4', default-features = false, features = ["derive"] } -sp-api = { version = "2.0.0-rc6", default-features = false } -sp-std = { version = "2.0.0-rc6", default-features = false } -frame-support = { version = "2.0.0-rc6", default-features = false } +sp-api = { version = "2.0.0", default-features = false } +sp-std = { version = "2.0.0", default-features = false } +frame-support = { version = "2.0.0", default-features = false } [features] default = ["std"] diff --git a/crates/staked-relayers/src/benchmarking.rs b/crates/staked-relayers/src/benchmarking.rs new file mode 100644 index 0000000000..4eb2325441 --- /dev/null +++ b/crates/staked-relayers/src/benchmarking.rs @@ -0,0 +1,235 @@ +use super::*; +use crate::Module as StakedRelayers; +use bitcoin::formatter::Formattable; +use bitcoin::types::{ + Address, BlockBuilder, H256Le, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, + TransactionOutput, +}; +use btc_relay::Module as BtcRelay; +use collateral::Module as Collateral; +use exchange_rate_oracle::Module as ExchangeRateOracle; +use frame_benchmarking::{account, benchmarks}; +use frame_system::RawOrigin; +// use pallet_timestamp::Now; +use sp_core::U256; +use sp_std::prelude::*; +use vault_registry::types::{Vault, Wallet}; +use vault_registry::Module as VaultRegistry; + +benchmarks! { + _ {} + + register_staked_relayer { + let origin: T::AccountId = account("Origin", 0, 0); + let u in 100 .. 1000; + }: _(RawOrigin::Signed(origin.clone()), u.into()) + verify { + assert_eq!(>::get(origin).stake, u.into()); + } + + deregister_staked_relayer { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + >::insert(&origin, ActiveStakedRelayer{stake: stake.into()}); + ::set(1); + Collateral::::lock_collateral(&origin, stake.into()).unwrap(); + }: _(RawOrigin::Signed(origin)) + + activate_staked_relayer { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + let height = 0; + StakedRelayers::::add_inactive_staked_relayer(&origin, stake.into(), StakedRelayerStatus::Bonding(height.into())); + }: _(RawOrigin::Signed(origin)) + + deactivate_staked_relayer { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + StakedRelayers::::add_active_staked_relayer(&origin, stake.into()); + }: _(RawOrigin::Signed(origin)) + + suggest_status_update { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + let deposit = 1000; + let status_code = StatusCode::Error; + StakedRelayers::::add_active_staked_relayer(&origin, stake.into()); + }: _(RawOrigin::Signed(origin), deposit.into(), status_code, None, None, None, vec![]) + + vote_on_status_update { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + StakedRelayers::::add_active_staked_relayer(&origin, stake.into()); + let status_update = StatusUpdate::default(); + let status_update_id = StakedRelayers::::insert_active_status_update(status_update); + }: _(RawOrigin::Signed(origin), status_update_id, true) + + force_status_update { + let origin: T::AccountId = account("Origin", 0, 0); + let status_code = StatusCode::Error; + }: _(RawOrigin::Signed(origin), status_code, None, None) + + slash_staked_relayer { + let origin: T::AccountId = account("Origin", 0, 0); + let staked_relayer: T::AccountId = account("Vault", 0, 0); + let stake = 100; + StakedRelayers::::add_active_staked_relayer(&staked_relayer, stake.into()); + Collateral::::lock_collateral(&staked_relayer, stake.into()).unwrap(); + + }: _(RawOrigin::Signed(origin), staked_relayer) + + report_vault_theft { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + StakedRelayers::::add_active_staked_relayer(&origin, stake.into()); + + let vault_address = Address::from([ + 126, 125, 148, 208, 221, 194, 29, 131, 191, 188, 252, 119, 152, 228, 84, 126, 223, 8, + 50, 170, + ]); + + let address = Address::from([0; 20]); + + let vault_id: T::AccountId = account("Vault", 0, 0); + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.wallet = Wallet::new(H160::from_slice(vault_address.as_bytes())); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + + VaultRegistry::::_set_liquidation_vault(vault_id.clone()); + + let mut height = 0; + + let block = BlockBuilder::new() + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .mine(U256::from(2).pow(254.into())); + + let block_hash = block.header.hash(); + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_initialize(block_header, height).unwrap(); + + height += 1; + + let value = 0; + let transaction = TransactionBuilder::new() + .with_version(2) + .add_input( + TransactionInputBuilder::new() + .with_coinbase(false) + .with_sequence(4294967295) + .with_previous_index(1) + .with_previous_hash(H256Le::from_bytes_le(&[ + 193, 80, 65, 160, 109, 235, 107, 56, 24, 176, 34, 250, 197, 88, 218, 76, + 226, 9, 127, 8, 96, 200, 246, 66, 16, 91, 186, 217, 210, 155, 224, 42, + ])) + .with_script(&[ + 73, 48, 70, 2, 33, 0, 207, 210, 162, 211, 50, 178, 154, 220, 225, 25, 197, + 90, 159, 173, 211, 192, 115, 51, 32, 36, 183, 226, 114, 81, 62, 81, 98, 60, + 161, 89, 147, 72, 2, 33, 0, 155, 72, 45, 127, 123, 77, 71, 154, 255, 98, + 189, 205, 174, 165, 70, 103, 115, 125, 86, 248, 212, 214, 61, 208, 62, 195, + 239, 101, 30, 217, 162, 84, 1, 33, 3, 37, 248, 176, 57, 161, 24, 97, 101, + 156, 155, 240, 63, 67, 252, 78, 160, 85, 243, 167, 28, 214, 12, 123, 31, + 212, 116, 171, 87, 143, 153, 119, 250, + ]) + .build(), + ) + .add_output(TransactionOutput::p2pkh(value.into(), &address)) + .build(); + + let block = BlockBuilder::new() + .with_previous_hash(block_hash) + .with_version(2) + .with_coinbase(&address, 50, 3) + .with_timestamp(1588813835) + .add_transaction(transaction.clone()) + .mine(U256::from(2).pow(254.into())); + + let tx_id = transaction.tx_id(); + let tx_block_height = height; + let proof = block.merkle_proof(&vec![tx_id]).format(); + let raw_tx = transaction.format_with(true); + + let block_header = RawBlockHeader::from_bytes(&block.header.format()).unwrap(); + BtcRelay::::_store_block_header(block_header).unwrap(); + + }: _(RawOrigin::Signed(origin), vault_id, tx_id, tx_block_height, proof, raw_tx) + + report_vault_under_liquidation_threshold { + let origin: T::AccountId = account("Origin", 0, 0); + let stake = 100; + StakedRelayers::::add_active_staked_relayer(&origin, stake.into()); + + let vault_id: T::AccountId = account("Vault", 0, 0); + let mut vault = Vault::default(); + vault.id = vault_id.clone(); + vault.issued_tokens = 100_000.into(); + vault.wallet = Wallet::new(H160::zero()); + VaultRegistry::::_insert_vault( + &vault_id, + vault + ); + VaultRegistry::::_set_liquidation_vault(vault_id.clone()); + + ExchangeRateOracle::::_set_exchange_rate(1).unwrap(); + + let threshold: u128 = 200_000; + VaultRegistry::::_set_liquidation_collateral_threshold(threshold.into()); + + }: _(RawOrigin::Signed(origin), vault_id) + + // FIXME: broken on no_std + // report_oracle_offline { + // let origin: T::AccountId = account("Origin", 0, 0); + // let stake = 100; + // StakedRelayers::::add_active_staked_relayer(&origin, stake.into()); + // >::set(>::get() + 10000.into()); + // }: _(RawOrigin::Signed(origin)) + +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_benchmarks() { + ExtBuilder::build_with(|storage| { + pallet_balances::GenesisConfig:: { + balances: vec![ + (account("Origin", 0, 0), 1 << 32), + (account("Vault", 0, 0), 1 << 32), + ], + } + .assimilate_storage(storage) + .unwrap(); + + GenesisConfig:: { + gov_id: account("Origin", 0, 0), + } + .assimilate_storage(storage) + .unwrap(); + }) + .execute_with(|| { + assert_ok!(test_benchmark_register_staked_relayer::()); + assert_ok!(test_benchmark_deregister_staked_relayer::()); + assert_ok!(test_benchmark_activate_staked_relayer::()); + assert_ok!(test_benchmark_deactivate_staked_relayer::()); + assert_ok!(test_benchmark_suggest_status_update::()); + assert_ok!(test_benchmark_vote_on_status_update::()); + assert_ok!(test_benchmark_force_status_update::()); + assert_ok!(test_benchmark_slash_staked_relayer::()); + assert_ok!(test_benchmark_report_vault_theft::()); + assert_ok!(test_benchmark_report_vault_under_liquidation_threshold::< + Test, + >()); + // assert_ok!(test_benchmark_report_oracle_offline::()); + }); + } +} diff --git a/crates/staked-relayers/src/default_weights.rs b/crates/staked-relayers/src/default_weights.rs new file mode 100644 index 0000000000..f1bb687361 --- /dev/null +++ b/crates/staked-relayers/src/default_weights.rs @@ -0,0 +1,60 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + // WARNING! Some components were not used: ["u"] + fn register_staked_relayer() -> Weight { + (79_014_000 as Weight) + .saturating_add(DbWeight::get().reads(4 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn deregister_staked_relayer() -> Weight { + (92_483_000 as Weight) + .saturating_add(DbWeight::get().reads(5 as Weight)) + .saturating_add(DbWeight::get().writes(4 as Weight)) + } + fn activate_staked_relayer() -> Weight { + (47_405_000 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn deactivate_staked_relayer() -> Weight { + (46_291_000 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn suggest_status_update() -> Weight { + (85_830_000 as Weight) + .saturating_add(DbWeight::get().reads(5 as Weight)) + .saturating_add(DbWeight::get().writes(4 as Weight)) + } + fn vote_on_status_update() -> Weight { + (45_439_000 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(1 as Weight)) + } + fn force_status_update() -> Weight { + (29_766_000 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(2 as Weight)) + } + fn slash_staked_relayer() -> Weight { + (108_008_000 as Weight) + .saturating_add(DbWeight::get().reads(6 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } + fn report_vault_theft() -> Weight { + (233_253_000 as Weight) + .saturating_add(DbWeight::get().reads(15 as Weight)) + .saturating_add(DbWeight::get().writes(5 as Weight)) + } + fn report_vault_under_liquidation_threshold() -> Weight { + (164_537_000 as Weight) + .saturating_add(DbWeight::get().reads(12 as Weight)) + .saturating_add(DbWeight::get().writes(4 as Weight)) + } +} diff --git a/crates/staked-relayers/src/ext.rs b/crates/staked-relayers/src/ext.rs index dac543e6dd..763d70e6ab 100644 --- a/crates/staked-relayers/src/ext.rs +++ b/crates/staked-relayers/src/ext.rs @@ -67,7 +67,7 @@ pub(crate) mod vault_registry { } pub fn get_liquidation_collateral_threshold() -> u128 { - >::_get_liquidation_collateral_threshold() + >::liquidation_collateral_threshold() } pub fn liquidate_vault(vault_id: &T::AccountId) -> DispatchResult { @@ -106,7 +106,6 @@ pub(crate) mod security { >::mutate_errors(f) } - #[cfg(test)] pub(crate) fn get_errors() -> BTreeSet { >::get_errors() } @@ -150,11 +149,12 @@ pub(crate) mod redeem { use crate::types::{PolkaBTC, DOT}; use frame_support::dispatch::DispatchError; use primitive_types::H256; - use redeem::types::Redeem; + use redeem::types::RedeemRequest; pub(crate) fn get_redeem_request_from_id( id: &H256, - ) -> Result, DOT>, DispatchError> { + ) -> Result, DOT>, DispatchError> + { >::get_redeem_request_from_id(id) } } @@ -164,11 +164,12 @@ pub(crate) mod replace { use crate::types::{PolkaBTC, DOT}; use frame_support::dispatch::DispatchError; use primitive_types::H256; - use replace::types::Replace; + use replace::types::ReplaceRequest; pub(crate) fn get_replace_request( id: &H256, - ) -> Result, DOT>, DispatchError> { + ) -> Result, DOT>, DispatchError> + { >::get_replace_request(id) } } diff --git a/crates/staked-relayers/src/lib.rs b/crates/staked-relayers/src/lib.rs index 4b0e2ab00f..f14b61a61f 100644 --- a/crates/staked-relayers/src/lib.rs +++ b/crates/staked-relayers/src/lib.rs @@ -5,6 +5,11 @@ mod ext; pub mod types; +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] mod mock; @@ -40,10 +45,24 @@ use frame_support::{ use frame_system::ensure_signed; use primitive_types::H256; use security::types::{ErrorCode, StatusCode}; -use sp_core::{H160, U256}; +use sp_core::H160; use sp_std::collections::btree_set::BTreeSet; use sp_std::convert::TryInto; use sp_std::vec::Vec; +use vault_registry::Wallet; + +pub trait WeightInfo { + fn register_staked_relayer() -> Weight; + fn deregister_staked_relayer() -> Weight; + fn activate_staked_relayer() -> Weight; + fn deactivate_staked_relayer() -> Weight; + fn suggest_status_update() -> Weight; + fn vote_on_status_update() -> Weight; + fn force_status_update() -> Weight; + fn slash_staked_relayer() -> Weight; + fn report_vault_theft() -> Weight; + fn report_vault_under_liquidation_threshold() -> Weight; +} /// ## Configuration /// The pallet's configuration trait. @@ -59,6 +78,9 @@ pub trait Trait: /// The overarching event type. type Event: From> + Into<::Event>; + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; + /// Number of blocks to wait until eligible to vote. type MaturityPeriod: Get; @@ -76,6 +98,9 @@ pub trait Trait: /// How often (in blocks) to check for new votes. type VotingPeriod: Get; + + /// Maximum message size in bytes + type MaximumMessageSize: Get; } // This pallet's storage items. @@ -91,18 +116,21 @@ decl_storage! { InactiveStakedRelayers: map hasher(blake2_128_concat) T::AccountId => InactiveStakedRelayer>; /// Map of active StatusUpdates, identified by an integer key. - ActiveStatusUpdates get(fn active_status_update): map hasher(blake2_128_concat) U256 => StatusUpdate>; + ActiveStatusUpdates get(fn active_status_update): map hasher(blake2_128_concat) u64 => StatusUpdate>; /// Map of expired, executed or rejected StatusUpdates, identified by an integer key. - InactiveStatusUpdates get(fn inactive_status_update): map hasher(blake2_128_concat) U256 => StatusUpdate>; + InactiveStatusUpdates get(fn inactive_status_update): map hasher(blake2_128_concat) u64 => StatusUpdate>; /// Integer increment-only counter used to track status updates. - StatusCounter get(fn status_counter): U256; + StatusCounter get(fn status_counter): u64; /// Mapping of Bitcoin transaction identifiers (SHA256 hashes) to account /// identifiers of Vaults accused of theft. TheftReports get(fn theft_report): map hasher(blake2_128_concat) H256Le => BTreeSet; + /// Mapping of Bitcoin block hashes to status update ids. + BlockReports get(fn block_report): map hasher(blake2_128_concat) H256Le => u64; + /// AccountId of the governance mechanism, as specified in the genesis. GovernanceId get(fn gov_id) config(): T::AccountId; } @@ -125,6 +153,8 @@ decl_module! { const VotingPeriod: T::BlockNumber = T::VotingPeriod::get(); + const MaximumMessageSize: u32 = T::MaximumMessageSize::get(); + fn deposit_event() = default; /// Registers a new Staked Relayer, locking the provided collateral, which must exceed `STAKED_RELAYER_STAKE`. @@ -133,7 +163,7 @@ decl_module! { /// /// * `origin`: The account of the Staked Relayer to be registered /// * `stake`: to-be-locked collateral/stake in DOT - #[weight = 1000] + #[weight = ::WeightInfo::register_staked_relayer()] fn register_staked_relayer(origin, stake: DOT) -> DispatchResult { let signer = ensure_signed(origin)?; @@ -165,7 +195,7 @@ decl_module! { /// # Arguments /// /// * `origin`: The account of the Staked Relayer to be deregistered - #[weight = 1000] + #[weight = ::WeightInfo::deregister_staked_relayer()] fn deregister_staked_relayer(origin) -> DispatchResult { let signer = ensure_signed(origin)?; let staked_relayer = Self::get_active_staked_relayer(&signer)?; @@ -181,7 +211,7 @@ decl_module! { /// # Arguments /// /// * `origin`: The account of the Staked Relayer to be activated - #[weight = 1000] + #[weight = ::WeightInfo::activate_staked_relayer()] fn activate_staked_relayer(origin) -> DispatchResult { let signer = ensure_signed(origin)?; let staked_relayer = Self::get_inactive_staked_relayer(&signer)?; @@ -205,7 +235,7 @@ decl_module! { /// # Arguments /// /// * `origin`: The account of the Staked Relayer to be deactivated - #[weight = 1000] + #[weight = ::WeightInfo::deactivate_staked_relayer()] fn deactivate_staked_relayer(origin) -> DispatchResult { let signer = ensure_signed(origin)?; let staked_relayer = Self::get_active_staked_relayer(&signer)?; @@ -224,7 +254,7 @@ decl_module! { /// * `remove_error`: [Optional] ErrorCode to be removed from the Errors list. /// * `block_hash`: [Optional] When reporting an error related to BTC-Relay, this field indicates the affected Bitcoin block (header). /// * `message`: Message detailing reason for status update - #[weight = 1000] + #[weight = ::WeightInfo::suggest_status_update()] fn suggest_status_update(origin, deposit: DOT, status_code: StatusCode, add_error: Option, remove_error: Option, block_hash: Option, message: Vec) -> DispatchResult { let signer = ensure_signed(origin)?; @@ -232,6 +262,11 @@ decl_module! { Self::only_governance(&signer)?; } + ensure!( + message.len() as u32 <= T::MaximumMessageSize::get(), + Error::::MessageTooBig, + ); + ensure!( >::contains_key(&signer), Error::::StakedRelayersOnly, @@ -246,16 +281,30 @@ decl_module! { if let Some(ref add_error) = add_error { match add_error { ErrorCode::NoDataBTCRelay => { - ensure!( - block_hash.is_some(), - Error::::ExpectedBlockHash - ); + match block_hash { + Some(block_hash) => { + ensure!( + !::contains_key(block_hash), + Error::::BlockAlreadyReported + ); + } + None => { + return Err(Error::::ExpectedBlockHash.into()); + } + }; }, ErrorCode::InvalidBTCRelay => { - ensure!( - block_hash.is_some(), - Error::::ExpectedBlockHash - ); + match block_hash { + Some(block_hash) => { + ensure!( + !::contains_key(block_hash), + Error::::BlockAlreadyReported + ); + } + None => { + return Err(Error::::ExpectedBlockHash.into()); + } + }; } _ => { ensure!( @@ -270,7 +319,7 @@ decl_module! { if let Some(block_hash) = block_hash { ensure!( ext::btc_relay::block_header_exists::(block_hash), - Error::::ExpectedBlockHash, + Error::::BlockNotFound, ); } @@ -291,7 +340,6 @@ decl_module! { proposer: signer.clone(), deposit: deposit, tally: tally, - // TODO: bound message size? message: message, }); @@ -307,8 +355,8 @@ decl_module! { /// * `origin`: The AccountId of the Staked Relayer casting the vote. /// * `status_update_id`: Identifier of the `StatusUpdate` voted upon in `ActiveStatusUpdates`. /// * `approve`: `True` or `False`, depending on whether the Staked Relayer agrees or disagrees with the suggested `StatusUpdate`. - #[weight = 1000] - fn vote_on_status_update(origin, status_update_id: U256, approve: bool) -> DispatchResult { + #[weight = ::WeightInfo::vote_on_status_update()] + fn vote_on_status_update(origin, status_update_id: u64, approve: bool) -> DispatchResult { let signer = ensure_signed(origin)?; ensure!( @@ -335,7 +383,7 @@ decl_module! { /// * `origin`: The AccountId of the Governance Mechanism. /// * `status_code`: Suggested BTC Parachain status (`StatusCode` enum). /// * `errors`: If the suggested status is `Error`, this set of `ErrorCode` entries provides details on the occurred errors. - #[weight = 1000] + #[weight = ::WeightInfo::force_status_update()] fn force_status_update(origin, status_code: StatusCode, add_error: Option, remove_error: Option) -> DispatchResult { let signer = ensure_signed(origin)?; Self::only_governance(&signer)?; @@ -367,7 +415,7 @@ decl_module! { /// /// * `origin`: The AccountId of the Governance Mechanism. /// * `staked_relayer_id`: The account of the Staked Relayer to be slashed. - #[weight = 1000] + #[weight = ::WeightInfo::slash_staked_relayer()] fn slash_staked_relayer(origin, staked_relayer_id: T::AccountId) -> DispatchResult { let signer = ensure_signed(origin)?; Self::only_governance(&signer)?; @@ -393,7 +441,7 @@ decl_module! { /// * `tx_block_height`: Height rogue tx was included. /// * `merkle_proof`: The proof of tx inclusion. /// * `raw_tx`: The raw Bitcoin transaction. - #[weight = 1000] + #[weight = ::WeightInfo::report_vault_theft()] fn report_vault_theft(origin, vault_id: T::AccountId, tx_id: H256Le, _tx_block_height: u32, merkle_proof: Vec, raw_tx: Vec) -> DispatchResult { let signer = ensure_signed(origin)?; ensure!( @@ -429,6 +477,7 @@ decl_module! { StatusCode::Error, Some(ErrorCode::Liquidation), None, + Some(tx_id), )); Ok(()) @@ -436,7 +485,7 @@ decl_module! { /// A Staked Relayer reports that a Vault is undercollateralized (i.e. below the LiquidationCollateralThreshold as defined in Vault Registry). /// If the collateral falls below this rate, we flag the Vault for liquidation and update the ParachainStatus to ERROR - adding LIQUIDATION to Errors. - #[weight = 1000] + #[weight = ::WeightInfo::report_vault_under_liquidation_threshold()] fn report_vault_under_liquidation_threshold(origin, vault_id: T::AccountId) -> DispatchResult { let signer = ensure_signed(origin)?; ensure!( @@ -487,6 +536,7 @@ decl_module! { StatusCode::Error, Some(ErrorCode::Liquidation), None, + None, )); Ok(()) @@ -502,6 +552,11 @@ decl_module! { Error::::StakedRelayersOnly, ); + ensure!( + !ext::security::get_errors::().contains(&ErrorCode::OracleOffline), + Error::::OracleAlreadyReported, + ); + ensure!( ext::oracle::is_max_delay_passed::(), Error::::OracleOnline, @@ -517,6 +572,7 @@ decl_module! { StatusCode::Error, Some(ErrorCode::OracleOffline), None, + None, )); Ok(()) @@ -550,46 +606,63 @@ impl Module { fn end_block(height: T::BlockNumber) { >::translate( |id, mut status_update: StatusUpdate>| { - if status_update - .tally - .is_approved(::get(), T::VoteThreshold::get()) - { - match Self::execute_status_update(&mut status_update) { - Ok(_) => { - Self::insert_inactive_status_update(id, status_update); - None - } - Err(e) => { - sp_runtime::print(e); - Some(status_update) - } - } - } else if status_update - .tally - .is_rejected(::get(), T::VoteThreshold::get()) - { - match Self::reject_status_update(&mut status_update) { - Ok(_) => { - Self::insert_inactive_status_update(id, status_update); - None - } - Err(e) => { - sp_runtime::print(e); - Some(status_update) - } + match Self::evaluate_status_update_at_height(id, &mut status_update, height) { + // remove proposal + Ok(true) => None, + // proposal is not accepted, rejected or expired + Ok(false) => Some(status_update), + // something went wrong, keep the proposal + Err(err) => { + sp_runtime::print(err); + Some(status_update) } - } else if height >= status_update.end { - status_update.proposal_status = ProposalStatus::Expired; - Self::insert_inactive_status_update(id, status_update); - Self::deposit_event(>::ExpireStatusUpdate(id)); - None - } else { - Some(status_update) } }, ); } + /// Evaluates whether the `StatusUpdate` has been accepted, rejected or expired. + /// Returns true if the `StatusUpdate` should be garbage collected. + /// + /// # Arguments + /// + /// * `id` - id of the `StatusUpdate` + /// * `status_update` - `StatusUpdate` to evaluate + /// * `height` - current height of the chain. + fn evaluate_status_update_at_height( + id: u64, + mut status_update: &mut StatusUpdate>, + height: T::BlockNumber, + ) -> Result { + if status_update + .tally + .is_approved(::get(), T::VoteThreshold::get()) + { + Self::execute_status_update(&mut status_update)?; + Self::insert_inactive_status_update(id, status_update); + Ok(true) + } else if status_update + .tally + .is_rejected(::get(), T::VoteThreshold::get()) + { + Self::reject_status_update(&mut status_update)?; + Self::insert_inactive_status_update(id, status_update); + Ok(true) + } else if height >= status_update.end { + // return the proposer's collateral + ext::collateral::release_collateral::( + &status_update.proposer, + status_update.deposit, + )?; + status_update.proposal_status = ProposalStatus::Expired; + Self::insert_inactive_status_update(id, status_update); + Self::deposit_event(>::ExpireStatusUpdate(id)); + Ok(true) + } else { + Ok(false) + } + } + /// Activate the staked relayer if mature. /// /// # Arguments @@ -755,8 +828,12 @@ impl Module { /// * `status_update` - `StatusUpdate` with the proposed changes. pub(crate) fn insert_active_status_update( status_update: StatusUpdate>, - ) -> U256 { + ) -> u64 { let status_id = Self::get_status_counter(); + if let Some(block_hash) = status_update.btc_block_hash { + // prevent duplicate blocks from being reported + ::insert(block_hash, status_id); + } >::insert(&status_id, status_update); status_id } @@ -767,8 +844,8 @@ impl Module { /// /// * `status_update` - `StatusUpdate` with the proposed changes. pub(crate) fn insert_inactive_status_update( - status_id: U256, - status_update: StatusUpdate>, + status_id: u64, + status_update: &StatusUpdate>, ) { >::insert(&status_id, status_update); } @@ -779,7 +856,7 @@ impl Module { /// /// * `status_update_id` - id of the `StatusUpdate` to fetch. pub(crate) fn get_status_update( - status_update_id: &U256, + status_update_id: &u64, ) -> Result>, DispatchError> { ensure!( >::contains_key(status_update_id), @@ -876,6 +953,7 @@ impl Module { status_code.clone(), status_update.add_error.clone(), status_update.remove_error.clone(), + status_update.btc_block_hash.clone(), )); Ok(()) } @@ -912,14 +990,14 @@ impl Module { /// Checks if the vault is doing a valid merge transaction to move funds between /// addresses. - pub(crate) fn is_valid_merge_transaction(tx: &Transaction, vault_addr: H160) -> bool { + pub(crate) fn is_valid_merge_transaction(tx: &Transaction, wallet: &Wallet) -> bool { for out in &tx.outputs { // return if address not extractable (i.e. op_return) let out_addr = match out.extract_address() { Ok(addr) => addr, Err(_) => return false, }; - if H160::from_slice(&out_addr) != vault_addr { + if !wallet.has_btc_address(&H160::from_slice(&out_addr)) { return false; } } @@ -933,7 +1011,7 @@ impl Module { exp_val: PolkaBTC, out_addr: H160, req_addr: H160, - vault_addr: H160, + wallet: &Wallet, ) -> Result { let value = TryInto::::try_into(exp_val).map_err(|_e| Error::::ConversionError)? as i64; @@ -941,9 +1019,10 @@ impl Module { // tx here should only have at most three outputs if out_val >= value && out_addr == req_addr { if tx.outputs.len() == 3 { + // TODO: tx can have more than three outputs let out = &tx.outputs[2]; if let Ok(vault_out_addr) = out.extract_address() { - return Ok(H160::from_slice(&vault_out_addr) == vault_addr); + return Ok(wallet.has_btc_address(&H160::from_slice(&vault_out_addr))); } return Ok(false); } @@ -977,7 +1056,7 @@ impl Module { ensure!( input_addresses.into_iter().any(|address_result| { match address_result { - Ok(address) => H160::from_slice(&address) == vault.btc_address, + Ok(address) => vault.wallet.has_btc_address(&H160::from_slice(&address)), _ => false, } }), @@ -986,7 +1065,7 @@ impl Module { // check if the transaction is a "migration" ensure!( - !Self::is_valid_merge_transaction(&tx, vault.btc_address), + !Self::is_valid_merge_transaction(&tx, &vault.wallet), Error::::ValidMergeTransaction ); @@ -1001,6 +1080,7 @@ impl Module { // 2) op_return: the second output is the associated ID encoded in the OP_RETURN // 3) vault: the third output is any "spare change" the vault is transferring + // TODO: we no longer this explicit ordering in btc-relay let out = &tx.outputs[0]; if let Ok(out_addr) = out.extract_address() { let out_val = out.value; @@ -1019,7 +1099,7 @@ impl Module { req.amount_btc, addr, req.btc_address, - vault.btc_address, + &vault.wallet, )?, Error::::ValidRedeemTransaction ); @@ -1035,7 +1115,7 @@ impl Module { req.amount, addr, req.btc_address, - vault.btc_address, + &vault.wallet, )?, Error::::ValidReplaceTransaction ); @@ -1049,9 +1129,9 @@ impl Module { } /// Increments the current `StatusCounter` and returns the new value. - pub fn get_status_counter() -> U256 { + pub fn get_status_counter() -> u64 { ::mutate(|c| { - *c += U256::one(); + *c += 1; *c }) } @@ -1069,17 +1149,22 @@ decl_event!( ActivateStakedRelayer(AccountId, DOT), DeactivateStakedRelayer(AccountId), StatusUpdateSuggested( - U256, + u64, AccountId, StatusCode, Option, Option, Option, ), - VoteOnStatusUpdate(U256, AccountId, bool), - ExecuteStatusUpdate(StatusCode, Option, Option), + VoteOnStatusUpdate(u64, AccountId, bool), + ExecuteStatusUpdate( + StatusCode, + Option, + Option, + Option, + ), RejectStatusUpdate(StatusCode, Option, Option), - ExpireStatusUpdate(U256), + ExpireStatusUpdate(u64), ForceStatusUpdate(StatusCode, Option, Option), SlashStakedRelayer(AccountId), } @@ -1095,6 +1180,8 @@ decl_error! { InsufficientDeposit, /// Insufficient participants InsufficientParticipants, + /// Status update message is too big + MessageTooBig, /// Staked relayer is not registered NotRegistered, /// Staked relayer has not bonded @@ -1125,8 +1212,14 @@ decl_error! { ValidReplaceTransaction, /// Valid merge transaction ValidMergeTransaction, + /// Oracle already reported + OracleAlreadyReported, /// Oracle is online OracleOnline, + /// Block not included by the relay + BlockNotFound, + /// Block already reported + BlockAlreadyReported, /// Cannot report vault theft without block hash ExpectedBlockHash, /// Status update should not contain block hash diff --git a/crates/staked-relayers/src/mock.rs b/crates/staked-relayers/src/mock.rs index ff6c293472..f1bacfb293 100644 --- a/crates/staked-relayers/src/mock.rs +++ b/crates/staked-relayers/src/mock.rs @@ -7,6 +7,7 @@ use frame_support::{ Weight, }, }; +use pallet_balances as balances; use sp_core::H256; use sp_io; use sp_runtime::{ @@ -78,7 +79,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = balances::AccountData; @@ -89,8 +90,11 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } -impl balances::Trait for Test { + +impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); @@ -102,7 +106,8 @@ impl balances::Trait for Test { parameter_types! { pub const MinimumPeriod: u64 = 5; } -impl timestamp::Trait for Test { + +impl pallet_timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); type MinimumPeriod = MinimumPeriod; @@ -115,6 +120,7 @@ impl security::Trait for Test { impl vault_registry::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl treasury::Trait for Test { @@ -124,6 +130,7 @@ impl treasury::Trait for Test { impl exchange_rate_oracle::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl collateral::Trait for Test { @@ -133,19 +140,17 @@ impl collateral::Trait for Test { impl btc_relay::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl redeem::Trait for Test { type Event = TestEvent; -} - -parameter_types! { - pub const ReplacePeriod: BlockNumber = 10; + type WeightInfo = (); } impl replace::Trait for Test { type Event = TestEvent; - type ReplacePeriod = ReplacePeriod; + type WeightInfo = (); } parameter_types! { @@ -155,16 +160,19 @@ parameter_types! { pub const MinimumParticipants: u64 = 3; pub const VoteThreshold: u64 = 50; pub const VotingPeriod: u64 = 100; + pub const MaximumMessageSize: u32 = 32; } impl Trait for Test { type Event = TestEvent; + type WeightInfo = (); type MaturityPeriod = MaturityPeriod; type MinimumDeposit = MinimumDeposit; type MinimumStake = MinimumStake; type MinimumParticipants = MinimumParticipants; type VoteThreshold = VoteThreshold; type VotingPeriod = VotingPeriod; + type MaximumMessageSize = MaximumMessageSize; } pub type System = frame_system::Module; @@ -189,29 +197,38 @@ pub const EVE_BALANCE: u64 = 1_000_000; pub struct ExtBuilder; impl ExtBuilder { - pub fn build() -> sp_io::TestExternalities { + pub fn build_with(conf: F) -> sp_io::TestExternalities + where + F: FnOnce(&mut sp_core::storage::Storage), + { let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); - balances::GenesisConfig:: { - balances: vec![ - (ALICE, ALICE_BALANCE), - (BOB, BOB_BALANCE), - (CAROL, CAROL_BALANCE), - (DAVE, DAVE_BALANCE), - (EVE, EVE_BALANCE), - ], - } - .assimilate_storage(&mut storage) - .unwrap(); - - GenesisConfig:: { gov_id: CAROL } - .assimilate_storage(&mut storage) - .unwrap(); + conf(&mut storage); storage.into() } + + pub fn build() -> sp_io::TestExternalities { + ExtBuilder::build_with(|storage| { + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, ALICE_BALANCE), + (BOB, BOB_BALANCE), + (CAROL, CAROL_BALANCE), + (DAVE, DAVE_BALANCE), + (EVE, EVE_BALANCE), + ], + } + .assimilate_storage(storage) + .unwrap(); + + GenesisConfig:: { gov_id: CAROL } + .assimilate_storage(storage) + .unwrap(); + }) + } } pub fn run_test(test: T) -> () diff --git a/crates/staked-relayers/src/tests.rs b/crates/staked-relayers/src/tests.rs index 3059994178..18d121eb50 100644 --- a/crates/staked-relayers/src/tests.rs +++ b/crates/staked-relayers/src/tests.rs @@ -10,13 +10,13 @@ use bitcoin::types::{ }; use frame_support::{assert_err, assert_ok}; use mocktopus::mocking::*; -use redeem::types::Redeem; -use replace::types::Replace; +use redeem::types::RedeemRequest; +use replace::types::ReplaceRequest; use security::types::{ErrorCode, StatusCode}; -use sp_core::{H160, H256, U256}; +use sp_core::{H160, H256}; use sp_std::collections::btree_set::BTreeSet; use std::convert::TryInto; -use vault_registry::{Vault, VaultStatus}; +use vault_registry::{Vault, VaultStatus, Wallet}; type Event = crate::Event; @@ -55,7 +55,7 @@ fn init_zero_vault( let mut vault = Vault::default(); vault.id = id; match btc_address { - Some(btc_address) => vault.btc_address = btc_address, + Some(btc_address) => vault.wallet = Wallet::new(btc_address), None => {} } vault @@ -142,7 +142,7 @@ fn inject_active_staked_relayer(id: &AccountId, amount: Balance) { ); } -fn inject_status_update(proposer: AccountId) -> U256 { +fn inject_status_update(proposer: AccountId) -> u64 { let mut tally = Tally::default(); tally.aye.insert(proposer.clone()); @@ -309,6 +309,27 @@ fn test_suggest_status_update_fails_with_insufficient_deposit() { }) } +#[test] +fn test_suggest_status_update_fails_with_message_too_big() { + run_test(|| { + Staking::only_governance.mock_safe(|_| MockResult::Return(Ok(()))); + inject_active_staked_relayer(&ALICE, 20); + + assert_err!( + Staking::suggest_status_update( + Origin::signed(ALICE), + 20, + StatusCode::Error, + None, + None, + None, + Vec::from([0; 64]), + ), + TestError::MessageTooBig, + ); + }) +} + #[test] fn test_suggest_status_update_fails_with_no_block_hash_found() { run_test(|| { @@ -325,7 +346,34 @@ fn test_suggest_status_update_fails_with_no_block_hash_found() { Some(H256Le::zero()), vec![], ), - TestError::ExpectedBlockHash, + TestError::BlockNotFound, + ); + }) +} + +#[test] +fn test_suggest_suggest_invalid_block_already_reported() { + run_test(|| { + Staking::only_governance.mock_safe(|_| MockResult::Return(Ok(()))); + ext::btc_relay::block_header_exists::.mock_safe(move |_| MockResult::Return(true)); + inject_active_staked_relayer(&ALICE, 20); + + let mut status_update = StatusUpdate::default(); + status_update.add_error = Some(ErrorCode::InvalidBTCRelay); + status_update.btc_block_hash = Some(H256Le::zero()); + Staking::insert_active_status_update(status_update); + + assert_err!( + Staking::suggest_status_update( + Origin::signed(ALICE), + 20, + StatusCode::Error, + Some(ErrorCode::InvalidBTCRelay), + None, + Some(H256Le::zero()), + vec![], + ), + TestError::BlockAlreadyReported, ); }) } @@ -346,7 +394,7 @@ fn test_suggest_status_update_succeeds() { vec![], )); assert_emitted!(Event::StatusUpdateSuggested( - U256::from(1), + 1, ALICE, StatusCode::Error, None, @@ -419,7 +467,7 @@ fn test_tally_vote() { fn test_vote_on_status_update_fails_with_staked_relayers_only() { run_test(|| { assert_err!( - Staking::vote_on_status_update(Origin::signed(ALICE), U256::from(0), false), + Staking::vote_on_status_update(Origin::signed(ALICE), 0, false), TestError::StakedRelayersOnly, ); }) @@ -443,7 +491,12 @@ fn test_vote_on_status_update_succeeds() { TestError::VoteAlreadyCast ); Staking::end_block(3); - assert_not_emitted!(Event::ExecuteStatusUpdate(StatusCode::Error, None, None)); + assert_not_emitted!(Event::ExecuteStatusUpdate( + StatusCode::Error, + None, + None, + None + )); assert_not_emitted!(Event::RejectStatusUpdate(StatusCode::Error, None, None)); assert_ok!(Staking::vote_on_status_update( @@ -452,7 +505,12 @@ fn test_vote_on_status_update_succeeds() { true )); Staking::end_block(3); - assert_not_emitted!(Event::ExecuteStatusUpdate(StatusCode::Error, None, None)); + assert_not_emitted!(Event::ExecuteStatusUpdate( + StatusCode::Error, + None, + None, + None + )); assert_not_emitted!(Event::RejectStatusUpdate(StatusCode::Error, None, None)); assert_ok!(Staking::vote_on_status_update( @@ -461,7 +519,12 @@ fn test_vote_on_status_update_succeeds() { true )); Staking::end_block(3); - assert_emitted!(Event::ExecuteStatusUpdate(StatusCode::Error, None, None)); + assert_emitted!(Event::ExecuteStatusUpdate( + StatusCode::Error, + None, + None, + None + )); let status_update = Staking::inactive_status_update(status_update_id); assert_eq!(status_update.proposal_status, ProposalStatus::Accepted); @@ -470,11 +533,17 @@ fn test_vote_on_status_update_succeeds() { #[test] fn test_end_block_status_update_expired() { run_test(|| { + ext::collateral::release_collateral::.mock_safe(|_, _| MockResult::Return(Ok(()))); let status_update_id = inject_status_update(ALICE); Staking::end_block(DEFAULT_END_HEIGHT + 100); let status_update = Staking::inactive_status_update(&status_update_id); assert_eq!(status_update.proposal_status, ProposalStatus::Expired); - assert_not_emitted!(Event::ExecuteStatusUpdate(StatusCode::Error, None, None)); + assert_not_emitted!(Event::ExecuteStatusUpdate( + StatusCode::Error, + None, + None, + None + )); assert_not_emitted!(Event::RejectStatusUpdate(StatusCode::Error, None, None)); assert_emitted!(Event::ExpireStatusUpdate(status_update_id)); }) @@ -530,6 +599,7 @@ fn test_execute_status_update_fails_with_insufficient_yes_votes() { assert_not_emitted!(Event::ExecuteStatusUpdate( StatusCode::default(), None, + None, None )); }) @@ -607,7 +677,8 @@ fn test_execute_status_update_succeeds() { assert_emitted!(Event::ExecuteStatusUpdate( StatusCode::Error, Some(ErrorCode::OracleOffline), - None + None, + Some(H256Le::zero()) )); }) } @@ -892,6 +963,7 @@ fn test_report_vault_theft_succeeds() { StatusCode::Error, Some(ErrorCode::Liquidation), None, + Some(H256Le::zero()), )); }) } @@ -931,6 +1003,7 @@ fn test_report_vault_under_liquidation_threshold_succeeds() { StatusCode::Error, Some(ErrorCode::Liquidation), None, + None, )); let parachain_status = ext::security::get_parachain_status::(); @@ -959,6 +1032,22 @@ fn test_report_oracle_offline_fails_with_staked_relayers_only() { }) } +#[test] +fn test_report_oracle_offline_fails_with_already_reported() { + run_test(|| { + let relayer = Origin::signed(ALICE); + let amount: Balance = 3; + inject_active_staked_relayer(&ALICE, amount); + + ext::security::get_errors:: + .mock_safe(|| MockResult::Return([ErrorCode::OracleOffline].iter().cloned().collect())); + assert_err!( + Staking::report_oracle_offline(relayer), + TestError::OracleAlreadyReported, + ); + }) +} + #[test] fn test_report_oracle_offline_fails_with_oracle_online() { run_test(|| { @@ -988,6 +1077,7 @@ fn test_report_oracle_offline_succeeds() { StatusCode::Error, Some(ErrorCode::OracleOffline), None, + None, )); }) } @@ -1023,7 +1113,7 @@ fn test_is_valid_merge_transaction_fails() { assert_eq!( Staking::is_valid_merge_transaction( &transaction, - H160::from_slice(address2.as_bytes()) + &Wallet::new(H160::from_slice(address2.as_bytes())) ), false ); @@ -1055,7 +1145,10 @@ fn test_is_valid_merge_transaction_succeeds() { .build(); assert_eq!( - Staking::is_valid_merge_transaction(&transaction, H160::from_slice(address.as_bytes())), + Staking::is_valid_merge_transaction( + &transaction, + &Wallet::new(H160::from_slice(address.as_bytes())) + ), true ); }) @@ -1095,7 +1188,7 @@ fn test_is_valid_request_transaction_fails() { 100, H160::from_slice(address1.as_bytes()), H160::from_slice(address1.as_bytes()), - H160::from_slice(address2.as_bytes()), + &Wallet::new(H160::from_slice(address2.as_bytes())), ), Ok(false) ); @@ -1136,7 +1229,7 @@ fn test_is_valid_request_transaction_succeeds() { 100, H160::from_slice(address1.as_bytes()), H160::from_slice(address1.as_bytes()), - H160::from_slice(address2.as_bytes()), + &Wallet::new(H160::from_slice(address2.as_bytes())), ), Ok(true) ); @@ -1157,7 +1250,7 @@ fn test_is_transaction_invalid_fails_with_valid_merge_transaction() { to_be_issued_tokens: 0, issued_tokens: 0, to_be_redeemed_tokens: 0, - btc_address: H160::from_slice(address.as_bytes()), + wallet: Wallet::new(H160::from_slice(address.as_bytes())), banned_until: None, status: VaultStatus::Active, })) @@ -1213,14 +1306,14 @@ fn test_is_transaction_invalid_fails_with_valid_request_or_redeem() { to_be_issued_tokens: 0, issued_tokens: 0, to_be_redeemed_tokens: 0, - btc_address: H160::from_slice(address1.as_bytes()), + wallet: Wallet::new(H160::from_slice(address1.as_bytes())), banned_until: None, status: VaultStatus::Active, })) }); ext::redeem::get_redeem_request_from_id::.mock_safe(move |_| { - MockResult::Return(Ok(Redeem { + MockResult::Return(Ok(RedeemRequest { vault: BOB, opentime: 0, amount_polka_btc: 0, @@ -1275,7 +1368,7 @@ fn test_is_transaction_invalid_fails_with_valid_request_or_redeem() { .mock_safe(move |_| MockResult::Return(Err(RedeemError::RedeemIdNotFound.into()))); ext::replace::get_replace_request::.mock_safe(move |_| { - MockResult::Return(Ok(Replace { + MockResult::Return(Ok(ReplaceRequest { old_vault: BOB, open_time: 0, amount: 100, @@ -1345,7 +1438,7 @@ fn test_is_transaction_invalid_succeeds() { #[test] fn test_get_status_counter_success() { run_test(|| { - assert_eq!(Staking::get_status_counter().as_u64(), 1); - assert_eq!(Staking::get_status_counter().as_u64(), 2); + assert_eq!(Staking::get_status_counter(), 1); + assert_eq!(Staking::get_status_counter(), 2); }) } diff --git a/crates/treasury/Cargo.toml b/crates/treasury/Cargo.toml index f47b56d9a1..a5bcc3d735 100644 --- a/crates/treasury/Cargo.toml +++ b/crates/treasury/Cargo.toml @@ -3,7 +3,7 @@ authors = ['Interlay'] description = 'Treasury module' edition = '2018' name = 'treasury' -version = '2.0.0-rc6' +version = '0.2.3' [features] default = ['std'] @@ -27,7 +27,7 @@ version = '1.3.4' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.safe-mix] default-features = false @@ -35,28 +35,28 @@ version = '1.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false package = 'pallet-balances' -version = '2.0.0-rc6' +version = '2.0.0' [dev-dependencies] mocktopus = "0.7.0" diff --git a/crates/treasury/src/mock.rs b/crates/treasury/src/mock.rs index 34a2d7f39d..e49d50a12a 100644 --- a/crates/treasury/src/mock.rs +++ b/crates/treasury/src/mock.rs @@ -70,7 +70,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -81,8 +81,11 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } + impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = TestEvent; type DustRemoval = (); diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml index 77a4be8ecb..6a990861dc 100644 --- a/crates/vault-registry/Cargo.toml +++ b/crates/vault-registry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vault-registry" -version = "2.0.0-rc6" +version = '0.2.3' authors = ["Interlay Ltd"] edition = "2018" @@ -23,6 +23,12 @@ std = [ 'treasury/std', 'security/std', 'exchange-rate-oracle/std', + 'frame-benchmarking/std', +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] [dependencies.serde] @@ -43,41 +49,41 @@ features= ['codec'] [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-arithmetic] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.timestamp] default-features = false package = 'pallet-timestamp' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false package = 'pallet-balances' -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.security] default-features = false @@ -95,5 +101,11 @@ path = '../treasury' default-features = false path = '../exchange-rate-oracle' +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true + [dev-dependencies] mocktopus = "0.7.0" +frame-benchmarking = { version = "2.0.0" } diff --git a/crates/vault-registry/rpc/Cargo.toml b/crates/vault-registry/rpc/Cargo.toml index 6623e08aa1..cab105318c 100644 --- a/crates/vault-registry/rpc/Cargo.toml +++ b/crates/vault-registry/rpc/Cargo.toml @@ -2,15 +2,15 @@ authors = ["Interlay Ltd"] edition = "2018" name = "module-vault-registry-rpc" -version = "2.0.0-rc6" +version = '0.2.3' [dependencies] codec = {package = "parity-scale-codec", version = '1.3.4'} -jsonrpc-core = "14.0.5" -jsonrpc-core-client = "14.0.5" -jsonrpc-derive = "14.0.5" +jsonrpc-core = "15.0.0" +jsonrpc-core-client = "15.0.0" +jsonrpc-derive = "15.0.0" module-vault-registry-rpc-runtime-api = {path = "runtime-api"} serde = {version = "1.0.101", features = ["derive"]} -sp-api = {version = "2.0.0-rc6"} -sp-blockchain = {version = "2.0.0-rc6"} -sp-runtime = {version = "2.0.0-rc6"} +sp-api = {version = "2.0.0"} +sp-blockchain = {version = "2.0.0"} +sp-runtime = {version = "2.0.0"} diff --git a/crates/vault-registry/rpc/runtime-api/Cargo.toml b/crates/vault-registry/rpc/runtime-api/Cargo.toml index 140b6b9ca7..bbb2df136c 100644 --- a/crates/vault-registry/rpc/runtime-api/Cargo.toml +++ b/crates/vault-registry/rpc/runtime-api/Cargo.toml @@ -2,13 +2,14 @@ authors = ["Interlay Ltd"] edition = "2018" name = "module-vault-registry-rpc-runtime-api" -version = "2.0.0-rc6" +version = '0.2.3' [dependencies] codec = {package = "parity-scale-codec", version = '1.3.4', default-features = false, features = ["derive"]} -frame-support = {version = "2.0.0-rc6", default-features = false} -sp-api = {version = "2.0.0-rc6", default-features = false} -sp-std = {version = "2.0.0-rc6", default-features = false} +frame-support = {version = "2.0.0", default-features = false} +sp-api = {version = "2.0.0", default-features = false} +sp-std = {version = "2.0.0", default-features = false} +serde = {version = "1.0.101", features = ["derive"]} [features] default = ["std"] diff --git a/crates/vault-registry/rpc/runtime-api/src/lib.rs b/crates/vault-registry/rpc/runtime-api/src/lib.rs index e5a955961e..50f6aa1acf 100644 --- a/crates/vault-registry/rpc/runtime-api/src/lib.rs +++ b/crates/vault-registry/rpc/runtime-api/src/lib.rs @@ -2,25 +2,75 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::Codec; +use codec::{Codec, Decode, Encode}; use frame_support::dispatch::DispatchError; +#[cfg(feature = "std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Eq, PartialEq, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] +/// a wrapper around a balance, used in RPC to workaround a bug where using u128 +/// in runtime-apis fails. See https://github.com/paritytech/substrate/issues/4641 +pub struct BalanceWrapper { + #[cfg_attr(feature = "std", serde(bound(serialize = "T: std::fmt::Display")))] + #[cfg_attr(feature = "std", serde(serialize_with = "serialize_as_string"))] + #[cfg_attr(feature = "std", serde(bound(deserialize = "T: std::str::FromStr")))] + #[cfg_attr(feature = "std", serde(deserialize_with = "deserialize_from_string"))] + pub amount: T, +} + +#[cfg(feature = "std")] +fn serialize_as_string( + t: &T, + serializer: S, +) -> Result { + serializer.serialize_str(&t.to_string()) +} + +#[cfg(feature = "std")] +fn deserialize_from_string<'de, D: Deserializer<'de>, T: std::str::FromStr>( + deserializer: D, +) -> Result { + let s = String::deserialize(deserializer)?; + s.parse::() + .map_err(|_| serde::de::Error::custom("Parse from string failed")) +} sp_api::decl_runtime_apis! { - pub trait VaultRegistryApi where + pub trait VaultRegistryApi where AccountId: Codec, PolkaBTC: Codec, + DOT: Codec { + /// Get the total collateralization of the system scaled by the GRANULARITY + fn get_total_collateralization() -> Result; + /// Get the first available vault with sufficient collateral to fulfil an issue request /// with the specified amount of PolkaBTC. - fn get_first_vault_with_sufficient_collateral(amount: PolkaBTC) -> Result; + fn get_first_vault_with_sufficient_collateral(amount: BalanceWrapper) -> Result; /// Get the first available vault with sufficient tokens to fulfil a redeem request - fn get_first_vault_with_sufficient_tokens(amount: PolkaBTC) -> Result; + fn get_first_vault_with_sufficient_tokens(amount: BalanceWrapper) -> Result; /// Get the amount of tokens a vault can issue - fn get_issuable_tokens_from_vault(vault: AccountId) -> Result; + fn get_issuable_tokens_from_vault(vault: AccountId) -> Result, DispatchError>; /// Get the collateralization rate of a vault scaled by GRANULARITY fn get_collateralization_from_vault(vault: AccountId) -> Result; + + /// Get the collateralization rate of a vault and collateral scaled by GRANULARITY + fn get_collateralization_from_vault_and_collateral(vault: AccountId, collateral: BalanceWrapper) -> Result; + + /// Get the minimum amount of collateral required for the given amount of btc + /// with the current threshold and exchange rate + fn get_required_collateral_for_polkabtc(amount_btc: BalanceWrapper) -> Result, DispatchError>; + + /// Get the amount of collateral required for the given vault to be at the + /// current SecureCollateralThreshold with the current exchange rate + fn get_required_collateral_for_vault(vault_id: AccountId) -> Result, DispatchError>; + + /// Simple check to validate whether a vault is below the `AuctionThreshold` + fn is_vault_below_auction_threshold(vault: AccountId) -> Result; } } diff --git a/crates/vault-registry/rpc/src/lib.rs b/crates/vault-registry/rpc/src/lib.rs index fff19a994d..81393f1bc2 100644 --- a/crates/vault-registry/rpc/src/lib.rs +++ b/crates/vault-registry/rpc/src/lib.rs @@ -1,45 +1,83 @@ //! RPC interface for the Vault Registry. +pub use self::gen_client::Client as VaultRegistryClient; use codec::Codec; -use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result as JsonRpcResult}; use jsonrpc_derive::rpc; +pub use module_vault_registry_rpc_runtime_api::{ + BalanceWrapper, VaultRegistryApi as VaultRegistryRuntimeApi, +}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::{MaybeDisplay, MaybeFromStr}; +use sp_runtime::{generic::BlockId, traits::Block as BlockT, DispatchError}; use std::sync::Arc; -pub use self::gen_client::Client as VaultRegistryClient; -pub use module_vault_registry_rpc_runtime_api::VaultRegistryApi as VaultRegistryRuntimeApi; - #[rpc] -pub trait VaultRegistryApi { +pub trait VaultRegistryApi +where + PolkaBTC: Codec + MaybeDisplay + MaybeFromStr, + DOT: Codec + MaybeDisplay + MaybeFromStr, +{ + #[rpc(name = "vaultRegistry_getTotalCollateralization")] + fn get_total_collateralization(&self, at: Option) -> JsonRpcResult; + #[rpc(name = "vaultRegistry_getFirstVaultWithSufficientCollateral")] fn get_first_vault_with_sufficient_collateral( &self, - amount: PolkaBTC, + amount: BalanceWrapper, at: Option, - ) -> Result; + ) -> JsonRpcResult; #[rpc(name = "vaultRegistry_getFirstVaultWithSufficientTokens")] fn get_first_vault_with_sufficient_tokens( &self, - amount: PolkaBTC, + amount: BalanceWrapper, at: Option, - ) -> Result; + ) -> JsonRpcResult; #[rpc(name = "vaultRegistry_getIssueableTokensFromVault")] fn get_issuable_tokens_from_vault( &self, vault: AccountId, at: Option, - ) -> Result; + ) -> JsonRpcResult>; #[rpc(name = "vaultRegistry_getCollateralizationFromVault")] fn get_collateralization_from_vault( &self, vault: AccountId, at: Option, - ) -> Result; + ) -> JsonRpcResult; + + #[rpc(name = "vaultRegistry_getCollateralizationFromVaultAndCollateral")] + fn get_collateralization_from_vault_and_collateral( + &self, + vault: AccountId, + collateral: BalanceWrapper, + at: Option, + ) -> JsonRpcResult; + + #[rpc(name = "vaultRegistry_getRequiredCollateralForPolkabtc")] + fn get_required_collateral_for_polkabtc( + &self, + amount_btc: BalanceWrapper, + at: Option, + ) -> JsonRpcResult>; + + #[rpc(name = "vaultRegistry_getRequiredCollateralForVault")] + fn get_required_collateral_for_vault( + &self, + vault_id: AccountId, + at: Option, + ) -> JsonRpcResult>; + + #[rpc(name = "vaultRegistry_isVaultBelowAuctionThreshold")] + fn is_vault_below_auction_threshold( + &self, + vault: AccountId, + at: Option, + ) -> JsonRpcResult; } /// A struct that implements the [`VaultRegistryApi`]. @@ -70,116 +108,173 @@ impl From for i64 { } } -impl VaultRegistryApi<::Hash, AccountId, PolkaBTC> - for VaultRegistry +fn handle_response( + result: Result, E>, + msg: String, +) -> JsonRpcResult { + result.map_or_else( + |e| { + Err(RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: msg.clone(), + data: Some(format!("{:?}", e).into()), + }) + }, + |result| { + result.map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: msg.clone(), + data: Some(format!("{:?}", e).into()), + }) + }, + ) +} + +impl + VaultRegistryApi<::Hash, AccountId, PolkaBTC, DOT> for VaultRegistry where Block: BlockT, C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - C::Api: VaultRegistryRuntimeApi, + C::Api: VaultRegistryRuntimeApi, AccountId: Codec, - PolkaBTC: Codec, + PolkaBTC: Codec + MaybeDisplay + MaybeFromStr, + DOT: Codec + MaybeDisplay + MaybeFromStr, { + fn get_total_collateralization( + &self, + at: Option<::Hash>, + ) -> JsonRpcResult { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + handle_response( + api.get_total_collateralization(&at), + "Unable to get total collateralization.".into(), + ) + } + fn get_first_vault_with_sufficient_collateral( &self, - amount: PolkaBTC, + amount: BalanceWrapper, at: Option<::Hash>, - ) -> Result { + ) -> JsonRpcResult { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - api.get_first_vault_with_sufficient_collateral(&at, amount) - .map_or_else( - |e| { - Err(RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to find a vault with sufficient collateral.".into(), - data: Some(format!("{:?}", e).into()), - }) - }, - |result| { - result.map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to find a vault with sufficient collateral.".into(), - data: Some(format!("{:?}", e).into()), - }) - }, - ) + handle_response( + api.get_first_vault_with_sufficient_collateral(&at, amount), + "Unable to find a vault with sufficient collateral.".into(), + ) } + fn get_first_vault_with_sufficient_tokens( &self, - amount: PolkaBTC, + amount: BalanceWrapper, at: Option<::Hash>, - ) -> Result { + ) -> JsonRpcResult { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - api.get_first_vault_with_sufficient_tokens(&at, amount) - .map_or_else( - |e| { - Err(RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to find a vault with sufficient tokens.".into(), - data: Some(format!("{:?}", e).into()), - }) - }, - |result| { - result.map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to find a vault with sufficient tokens.".into(), - data: Some(format!("{:?}", e).into()), - }) - }, - ) + handle_response( + api.get_first_vault_with_sufficient_tokens(&at, amount), + "Unable to find a vault with sufficient tokens.".into(), + ) } + fn get_issuable_tokens_from_vault( &self, vault: AccountId, at: Option<::Hash>, - ) -> Result { + ) -> JsonRpcResult> { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - api.get_issuable_tokens_from_vault(&at, vault).map_or_else( - |e| { - Err(RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to get issuable tokens from vault.".into(), - data: Some(format!("{:?}", e).into()), - }) - }, - |result| { - result.map_err(|e| RpcError { - code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to get issuable tokens from vault.".into(), - data: Some(format!("{:?}", e).into()), - }) - }, + handle_response( + api.get_issuable_tokens_from_vault(&at, vault), + "Unable to get issuable tokens from vault.".into(), ) } + fn get_collateralization_from_vault( &self, vault: AccountId, at: Option<::Hash>, - ) -> Result { + ) -> JsonRpcResult { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + handle_response( + api.get_collateralization_from_vault(&at, vault), + "Unable to get collateralization from vault.".into(), + ) + } + + fn get_collateralization_from_vault_and_collateral( + &self, + vault: AccountId, + collateral: BalanceWrapper, + at: Option<::Hash>, + ) -> JsonRpcResult { let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - api.get_collateralization_from_vault(&at, vault) + handle_response( + api.get_collateralization_from_vault_and_collateral(&at, vault, collateral), + "Unable to get collateralization from vault.".into(), + ) + } + + fn get_required_collateral_for_polkabtc( + &self, + amount_btc: BalanceWrapper, + at: Option<::Hash>, + ) -> JsonRpcResult> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + handle_response( + api.get_required_collateral_for_polkabtc(&at, amount_btc), + "Unable to get required collateral for amount.".into(), + ) + } + + fn get_required_collateral_for_vault( + &self, + vault_id: AccountId, + at: Option<::Hash>, + ) -> JsonRpcResult> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + api.get_required_collateral_for_vault(&at, vault_id) .map_or_else( |e| { Err(RpcError { code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to get collateralization from vault.".into(), + message: "Unable to get required collateral for vault.".into(), data: Some(format!("{:?}", e).into()), }) }, |result| { result.map_err(|e| RpcError { code: ErrorCode::ServerError(Error::RuntimeError.into()), - message: "Unable to get collateralization from vault.".into(), + message: "Unable to get required collateral for vault.".into(), data: Some(format!("{:?}", e).into()), }) }, ) } + + fn is_vault_below_auction_threshold( + &self, + vault: AccountId, + at: Option<::Hash>, + ) -> JsonRpcResult { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + + handle_response( + api.is_vault_below_auction_threshold(&at, vault), + "Unable to check if vault is below auction threshold.".into(), + ) + } } diff --git a/crates/vault-registry/src/benchmarking.rs b/crates/vault-registry/src/benchmarking.rs new file mode 100644 index 0000000000..5fcd24caaf --- /dev/null +++ b/crates/vault-registry/src/benchmarking.rs @@ -0,0 +1,73 @@ +use super::*; +use crate::Module as VaultRegistry; +use frame_benchmarking::{account, benchmarks}; +use frame_system::RawOrigin; +use sp_core::H160; +use sp_std::prelude::*; + +benchmarks! { + _ {} + + register_vault { + let origin: T::AccountId = account("Origin", 0, 0); + let amount = 100; + let btc_address = H160::from_slice(&[0; 20]); + }: _(RawOrigin::Signed(origin.clone()), amount.into(), btc_address) + verify { + assert_eq!(Vaults::::get(origin).wallet.get_btc_address(), btc_address); + } + + lock_additional_collateral { + let origin: T::AccountId = account("Origin", 0, 0); + let u in 0 .. 100; + let mut vault = Vault::default(); + vault.id = origin.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault(&origin, vault); + }: _(RawOrigin::Signed(origin), u.into()) + verify { + } + + withdraw_collateral { + let origin: T::AccountId = account("Origin", 0, 0); + let u in 0 .. 100; + let mut vault = Vault::default(); + vault.id = origin.clone(); + vault.wallet = Wallet::new(H160::from_slice(&[0; 20])); + VaultRegistry::::_insert_vault(&origin, vault); + collateral::Module::::lock_collateral(&origin, u.into()).unwrap(); + }: _(RawOrigin::Signed(origin), u.into()) + verify { + } + + update_btc_address { + let origin: T::AccountId = account("Origin", 0, 0); + let mut vault = Vault::default(); + vault.id = origin.clone(); + vault.wallet = Wallet::new(H160::zero()); + VaultRegistry::::_insert_vault(&origin, vault); + }: _(RawOrigin::Signed(origin), H160::from_slice(&[1; 20])) + +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ExtBuilder, Test}; + use frame_support::assert_ok; + + #[test] + fn test_benchmarks() { + ExtBuilder::build_with( + pallet_balances::GenesisConfig:: { + balances: vec![(account("Origin", 0, 0), 1 << 64)], + }, + ) + .execute_with(|| { + assert_ok!(test_benchmark_register_vault::()); + assert_ok!(test_benchmark_lock_additional_collateral::()); + assert_ok!(test_benchmark_withdraw_collateral::()); + assert_ok!(test_benchmark_update_btc_address::()); + }); + } +} diff --git a/crates/vault-registry/src/default_weights.rs b/crates/vault-registry/src/default_weights.rs new file mode 100644 index 0000000000..41a37fc80b --- /dev/null +++ b/crates/vault-registry/src/default_weights.rs @@ -0,0 +1,29 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + fn register_vault() -> Weight { + (91_914_000 as Weight) + .saturating_add(DbWeight::get().reads(6 as Weight)) + .saturating_add(DbWeight::get().writes(4 as Weight)) + } + fn lock_additional_collateral() -> Weight { + (109_095_000 as Weight) + .saturating_add(DbWeight::get().reads(9 as Weight)) + .saturating_add(DbWeight::get().writes(2 as Weight)) + } + fn withdraw_collateral() -> Weight { + (107_035_000 as Weight) + .saturating_add(DbWeight::get().reads(9 as Weight)) + .saturating_add(DbWeight::get().writes(2 as Weight)) + } + fn update_btc_address() -> Weight { + (48_413_000 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(2 as Weight)) + } +} diff --git a/crates/vault-registry/src/ext.rs b/crates/vault-registry/src/ext.rs index 3353526e3a..01eea8248e 100644 --- a/crates/vault-registry/src/ext.rs +++ b/crates/vault-registry/src/ext.rs @@ -6,6 +6,10 @@ pub(crate) mod collateral { use crate::types::DOT; use frame_support::dispatch::DispatchResult; + pub fn total_locked() -> DOT { + >::get_total_collateral() + } + pub fn lock(sender: &T::AccountId, amount: DOT) -> DispatchResult { >::lock_collateral(sender, amount) } @@ -28,8 +32,16 @@ pub(crate) mod collateral { } #[cfg_attr(test, mockable)] -pub(crate) mod oracle { +pub(crate) mod treasury { + use crate::types::PolkaBTC; + + pub fn total_issued() -> PolkaBTC { + >::get_total_supply() + } +} +#[cfg_attr(test, mockable)] +pub(crate) mod oracle { use crate::types::{PolkaBTC, DOT}; use frame_support::dispatch::DispatchError; diff --git a/crates/vault-registry/src/lib.rs b/crates/vault-registry/src/lib.rs index 91f871a281..8f22b72914 100644 --- a/crates/vault-registry/src/lib.rs +++ b/crates/vault-registry/src/lib.rs @@ -8,6 +8,11 @@ mod ext; pub mod types; +#[cfg(any(feature = "runtime-benchmarks", test))] +mod benchmarking; + +mod default_weights; + #[cfg(test)] mod tests; @@ -22,6 +27,7 @@ use mocktopus::macros::mockable; use codec::{Decode, Encode}; use frame_support::dispatch::{DispatchError, DispatchResult}; +use frame_support::weights::Weight; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, ensure, IterableStorageMap, }; @@ -33,7 +39,7 @@ use sp_std::vec::Vec; use security::ErrorCode; use crate::types::{DefaultVault, PolkaBTC, RichVault, DOT}; -pub use crate::types::{Vault, VaultStatus}; +pub use crate::types::{Vault, VaultStatus, Wallet}; /// Granularity of `SecureCollateralThreshold`, `AuctionCollateralThreshold`, /// `LiquidationCollateralThreshold`, and `PunishmentFee` @@ -47,6 +53,13 @@ pub struct RegisterRequest { timeout: DateTime, } +pub trait WeightInfo { + fn register_vault() -> Weight; + fn lock_additional_collateral() -> Weight; + fn withdraw_collateral() -> Weight; + fn update_btc_address() -> Weight; +} + /// ## Configuration and Constants /// The pallet's configuration trait. pub trait Trait: @@ -58,6 +71,9 @@ pub trait Trait: { /// The overarching event type. type Event: From> + Into<::Event>; + + /// Weight information for the extrinsics in this module. + type WeightInfo: WeightInfo; } // This pallet's storage items. @@ -66,7 +82,7 @@ decl_storage! { /// ## Storage /// The minimum collateral (DOT) a Vault needs to provide /// to participate in the issue process. - MinimumCollateralVault: DOT; + MinimumCollateralVault get(fn minimum_collateral_vault) config(): DOT; /// If a Vault misbehaves in either the redeem or replace protocol by /// failing to prove that it sent the correct amount of BTC to the @@ -77,17 +93,17 @@ decl_storage! { /// to compensate the damaged party for its loss. /// For example, if the `PunishmentFee` is set to 50000, /// it is equivalent to 50%. - PunishmentFee: u128; + PunishmentFee get(fn punishment_fee) config(): DOT; /// If a Vault fails to execute a correct redeem or replace, /// it is temporarily banned from further issue, redeem or replace requests. - PunishmentDelay: T::BlockNumber; + PunishmentDelay get(fn punishment_delay) config(): T::BlockNumber; /// If a Vault is running low on collateral and falls below /// `PremiumRedeemThreshold`, users are allocated a premium in DOT /// when redeeming with the Vault - as defined by this parameter. /// For example, if the RedeemPremiumFee is set to 5000, it is equivalent to 5%. - RedeemPremiumFee: u128; + RedeemPremiumFee get(fn redeem_premium_fee) config(): DOT; /// Determines the over-collateralization rate for DOT collateral locked /// by Vaults, necessary for issuing PolkaBTC. Must to be strictly @@ -96,27 +112,30 @@ decl_storage! { /// Determines the rate for the collateral rate of Vaults, at which the /// BTC backed by the Vault are opened up for auction to other Vaults - AuctionCollateralThreshold: u128; + AuctionCollateralThreshold get(fn auction_collateral_threshold) config(): u128; /// Determines the rate for the collateral rate of Vaults, /// at which users receive a premium in DOT, allocated from the /// Vault’s collateral, when performing a redeem with this Vault. /// Must to be strictly greater than 100000 and LiquidationCollateralThreshold. - PremiumRedeemThreshold: u128; + PremiumRedeemThreshold get(fn premium_redeem_threshold) config(): u128; /// Determines the lower bound for the collateral rate in PolkaBTC. /// Must be strictly greater than 100000. If a Vault’s collateral rate /// drops below this, automatic liquidation (forced Redeem) is triggered. - LiquidationCollateralThreshold: u128; + LiquidationCollateralThreshold get(fn liquidation_collateral_threshold) config(): u128; /// Account identifier of an artificial Vault maintained by the VaultRegistry /// to handle polkaBTC balances and DOT collateral of liquidated Vaults. /// That is, when a Vault is liquidated, its balances are transferred to /// LiquidationVault and claims are later handled via the LiquidationVault. - LiquidationVault: T::AccountId; + LiquidationVault get(fn liquidation_vault) config(): T::AccountId; /// Mapping of Vaults, using the respective Vault account identifier as key. Vaults: map hasher(blake2_128_concat) T::AccountId => Vault>; + + /// Mapping of BTC addresses to Vault Ids + VaultsBtcAddress: map hasher(blake2_128_concat) H160 => T::AccountId; } } @@ -140,15 +159,15 @@ decl_module! { /// * `InsufficientVaultCollateralAmount` - if the collateral is below the minimum threshold /// * `VaultAlreadyRegistered` - if a vault is already registered for the origin account /// * `InsufficientCollateralAvailable` - if the vault does not own enough collateral - #[weight = 1000] + #[weight = ::WeightInfo::register_vault()] fn register_vault(origin, collateral: DOT, btc_address: H160) -> DispatchResult { let sender = ensure_signed(origin)?; ext::security::ensure_parachain_status_running::()?; - ext::security::ensure_parachain_status_running::()?; ensure!(collateral >= Self::get_minimum_collateral_vault(), Error::::InsufficientVaultCollateralAmount); ensure!(!Self::vault_exists(&sender), Error::::VaultAlreadyRegistered); + ensure!(!>::contains_key(btc_address), Error::::BtcAddressTaken); ext::collateral::lock::(&sender, collateral)?; let vault = RichVault::::new(sender.clone(), btc_address); @@ -168,7 +187,7 @@ decl_module! { /// # Errors /// * `VaultNotFound` - if no vault exists for the origin account /// * `InsufficientCollateralAvailable` - if the vault does not own enough collateral - #[weight = 1000] + #[weight = ::WeightInfo::lock_additional_collateral()] fn lock_additional_collateral(origin, amount: DOT) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -199,7 +218,7 @@ decl_module! { /// # Errors /// * `VaultNotFound` - if no vault exists for the origin account /// * `InsufficientCollateralAvailable` - if the vault does not own enough collateral - #[weight = 1000] + #[weight = ::WeightInfo::withdraw_collateral()] fn withdraw_collateral(origin, amount: DOT) -> DispatchResult { let sender = ensure_signed(origin)?; ext::security::ensure_parachain_status_running::()?; @@ -212,19 +231,34 @@ decl_module! { )); Ok(()) } + + /// Registers a new Bitcoin address for the vault. + /// + /// # Arguments + /// * `btc_address` - the BTC address of the vault to update + #[weight = ::WeightInfo::update_btc_address()] + fn update_btc_address(origin, btc_address: H160) -> DispatchResult { + let account_id = ensure_signed(origin)?; + ext::security::ensure_parachain_status_running::()?; + + ensure!( + !>::contains_key(btc_address), + Error::::BtcAddressTaken, + ); + + let mut vault = Self::rich_vault_from_id(&account_id)?; + vault.update_btc_address(btc_address); + >::insert(btc_address, account_id.clone()); + + Self::deposit_event(Event::::UpdateBtcAddress(account_id, btc_address)); + Ok(()) + } } } #[cfg_attr(test, mockable)] impl Module { /// Public functions - pub fn _punishment_fee() -> Result, DispatchError> { - Self::u128_to_dot(PunishmentFee::get()) - } - - pub fn _get_redeem_premium_fee() -> Result, DispatchError> { - Self::u128_to_dot(RedeemPremiumFee::get()) - } pub fn _get_vault_from_id(vault_id: &T::AccountId) -> Result, DispatchError> { ensure!(Self::vault_exists(&vault_id), Error::::VaultNotFound); @@ -253,7 +287,7 @@ impl Module { let mut vault = Self::rich_vault_from_id(&vault_id)?; vault.increase_to_be_issued(tokens)?; Self::deposit_event(Event::::IncreaseToBeIssuedTokens(vault.id(), tokens)); - Ok(vault.data.btc_address) + Ok(vault.data.wallet.get_btc_address()) } /// Decreases the amount of tokens to be issued in the next issue request @@ -515,14 +549,14 @@ impl Module { Ok(()) } - /// Replaces the old vault by the new vault by transfering tokens + /// Replaces the old vault by the new vault by transferring tokens /// from the old vault to the new one /// /// # Arguments /// * `old_vault_id` - the id of the old vault /// * `new_vault_id` - the id of the new vault - /// * `tokens` - the amount of tokens to be transfered from the old to the new vault - /// * `colalteral` - the collateral to be locked by the new vault + /// * `tokens` - the amount of tokens to be transferred from the old to the new vault + /// * `collateral` - the collateral to be locked by the new vault /// /// # Errors /// * `VaultNotFound` - if either the old or new vault does not exist @@ -591,6 +625,7 @@ impl Module { pub fn _insert_vault>>(id: &T::AccountId, rich_vault: V) { let vault: DefaultVault = rich_vault.into(); + >::insert(vault.wallet.get_btc_address(), id); >::insert(id, vault) } @@ -612,7 +647,7 @@ impl Module { Self::is_vault_below_threshold(&vault_id, ::get()) } - pub fn _is_vault_below_auction_threshold( + pub fn is_vault_below_auction_threshold( vault_id: &T::AccountId, ) -> Result { Self::is_vault_below_threshold(&vault_id, ::get()) @@ -638,22 +673,6 @@ impl Module { Self::is_collateral_below_threshold(collateral, btc_amount, threshold) } - pub fn _get_secure_collateral_threshold() -> u128 { - ::get() - } - - pub fn _get_auction_collateral_threshold() -> u128 { - ::get() - } - - pub fn _get_premium_redeem_threshold() -> u128 { - ::get() - } - - pub fn _get_liquidation_collateral_threshold() -> u128 { - ::get() - } - pub fn _set_secure_collateral_threshold(threshold: u128) { ::set(threshold); } @@ -670,6 +689,10 @@ impl Module { ::set(threshold); } + pub fn _set_liquidation_vault(vault_id: T::AccountId) { + >::set(vault_id); + } + pub fn _is_over_minimum_collateral(amount: DOT) -> bool { amount > Self::get_minimum_collateral_vault() } @@ -693,6 +716,22 @@ impl Module { /// RPC + /// Get the total collateralization of the system. + pub fn get_total_collateralization() -> Result { + let issued_tokens = ext::treasury::total_issued::(); + let total_collateral = ext::collateral::total_locked::(); + + // convert the issued_tokens to the raw amount + let raw_issued_tokens = Self::polkabtc_to_u128(issued_tokens)?; + ensure!(raw_issued_tokens != 0, Error::::NoTokensIssued); + + // convert the collateral to polkabtc + let collateral_in_polka_btc = ext::oracle::dots_to_btc::(total_collateral)?; + let raw_collateral_in_polka_btc = Self::polkabtc_to_u128(collateral_in_polka_btc)?; + + Self::get_collateralization(raw_collateral_in_polka_btc, raw_issued_tokens) + } + /// Get the first available vault with sufficient collateral to fulfil an issue request /// with the specified amount of PolkaBTC. pub fn get_first_vault_with_sufficient_collateral( @@ -734,6 +773,15 @@ impl Module { /// Get the current collateralization of a vault pub fn get_collateralization_from_vault(vault_id: T::AccountId) -> Result { + let vault = Self::rich_vault_from_id(&vault_id)?; + let collateral = vault.get_collateral(); + Self::get_collateralization_from_vault_and_collateral(vault_id, collateral) + } + + pub fn get_collateralization_from_vault_and_collateral( + vault_id: T::AccountId, + collateral: DOT, + ) -> Result { let vault = Self::rich_vault_from_id(&vault_id)?; let issued_tokens = vault.data.issued_tokens + vault.data.to_be_issued_tokens; @@ -741,23 +789,45 @@ impl Module { let raw_issued_tokens = Self::polkabtc_to_u128(issued_tokens)?; ensure!(raw_issued_tokens != 0, Error::::NoTokensIssued); - let collateral = vault.get_collateral(); // convert the collateral to polkabtc let collateral_in_polka_btc = ext::oracle::dots_to_btc::(collateral)?; let raw_collateral_in_polka_btc = Self::polkabtc_to_u128(collateral_in_polka_btc)?; - // calculate the collateralization as a ratio of the issued tokens to the - // amount of provided collateral at the current exchange rate. The result is scaled - // by the GRANULARITY - let collateralization: u64 = raw_collateral_in_polka_btc - .checked_mul(10u128.pow(GRANULARITY)) - .ok_or(Error::::ConversionError)? - .checked_div(raw_issued_tokens) - .ok_or(Error::::ConversionError)? - .try_into() - .map_err(|_| Error::::ConversionError)?; + Self::get_collateralization(raw_collateral_in_polka_btc, raw_issued_tokens) + } - Ok(collateralization) + /// Gets the minimum amount of collateral required for the given amount of btc + /// with the current threshold and exchange rate + /// + /// # Arguments + /// * `amount_btc` - the amount of polkabtc + /// + /// # Errors + /// * `ScaleConversionError` - if a math error occurs + pub fn get_required_collateral_for_polkabtc( + amount_btc: PolkaBTC, + ) -> Result, DispatchError> { + ext::security::ensure_parachain_status_running::()?; + + let threshold = ::get(); + let collateral = + Self::get_required_collateral_for_polkabtc_with_threshold(amount_btc, threshold)?; + Ok(collateral) + } + + /// Get the amount of collateral required for the given vault to be at the + /// current SecureCollateralThreshold with the current exchange rate + pub fn get_required_collateral_for_vault( + vault_id: T::AccountId, + ) -> Result, DispatchError> { + ext::security::ensure_parachain_status_running::()?; + + let vault = Self::rich_vault_from_id(&vault_id)?; + let issued_tokens = vault.data.issued_tokens + vault.data.to_be_issued_tokens; + + let required_collateral = Self::get_required_collateral_for_polkabtc(issued_tokens)?; + + Ok(required_collateral) } /// Private getters and setters @@ -789,6 +859,24 @@ impl Module { ext::security::ensure_parachain_status_has_not_specific_errors::(error_codes) } + /// calculate the collateralization as a ratio of the issued tokens to the + /// amount of provided collateral at the current exchange rate. The result is scaled + /// by the GRANULARITY + fn get_collateralization( + raw_collateral_in_polka_btc: u128, + raw_issued_tokens: u128, + ) -> Result { + let collateralization: u64 = U256::from(raw_collateral_in_polka_btc) + .checked_mul(U256::from(10).pow(GRANULARITY.into())) + .ok_or(Error::::ConversionError)? + .checked_div(raw_issued_tokens.into()) + .ok_or(Error::::ConversionError)? + .try_into() + .map_err(|_| Error::::ConversionError)?; + + Ok(collateralization) + } + fn is_vault_below_threshold( vault_id: &T::AccountId, threshold: u128, @@ -815,6 +903,43 @@ impl Module { Ok(max_tokens < btc_amount) } + /// Gets the minimum amount of collateral required for the given amount of btc + /// with the current exchange rate and the given threshold. This function is the + /// inverse of calculate_max_polkabtc_from_collateral_for_threshold + /// + /// # Arguments + /// * `amount_btc` - the amount of polkabtc + /// * `threshold` - the required secure collateral threshold + /// + /// # Errors + /// * `ScaleConversionError` - if a math error occurs + fn get_required_collateral_for_polkabtc_with_threshold( + btc: PolkaBTC, + threshold: u128, + ) -> Result, DispatchError> { + let btc = Self::polkabtc_to_u128(btc)?; + let btc = U256::from(btc); + + // Step 1: inverse of the scaling applied in calculate_max_polkabtc_from_collateral_for_threshold + + // inverse of the div + let btc = btc + .checked_mul(threshold.into()) + .ok_or(Error::::ScaleConversionError)?; + + // To do the inverse of the multiplication, we need to do division, but + // we need to round up. To round up (a/b), we need to do ((a+b-1)/b): + let rounding_addition = U256::from(10).pow(GRANULARITY.into()) - U256::from(1); + let btc = (btc + rounding_addition) + .checked_div(U256::from(10).pow(GRANULARITY.into())) + .ok_or(Error::::ScaleConversionError)?; + + // Step 2: convert the amount to dots + let scaled = Self::u128_to_polkabtc(btc.try_into()?)?; + let amount_in_dot = ext::oracle::btc_to_dots::(scaled)?; + Ok(amount_in_dot) + } + fn calculate_max_polkabtc_from_collateral_for_threshold( collateral: DOT, threshold: u128, @@ -863,7 +988,7 @@ decl_event! { LockAdditionalCollateral(AccountId, DOT, DOT, DOT), /// id, withdrawn collateral, total collateral WithdrawCollateral(AccountId, DOT, DOT), - + UpdateBtcAddress(AccountId, H160), IncreaseToBeIssuedTokens(AccountId, BTCBalance), DecreaseToBeIssuedTokens(AccountId, BTCBalance), IssueTokens(AccountId, BTCBalance), @@ -890,6 +1015,8 @@ decl_error! { /// Returned if a vault tries to register while already being registered VaultAlreadyRegistered, VaultNotFound, + /// The Bitcoin Address has already been registered + BtcAddressTaken, /// Result is too big for type ScaleConversionError, /// Other conversion error diff --git a/crates/vault-registry/src/mock.rs b/crates/vault-registry/src/mock.rs index 78d55904d7..717be4deae 100644 --- a/crates/vault-registry/src/mock.rs +++ b/crates/vault-registry/src/mock.rs @@ -1,3 +1,4 @@ +use frame_support::traits::StorageMapShim; /// Mocking the test environment use frame_support::{ impl_outer_event, impl_outer_origin, parameter_types, @@ -31,7 +32,8 @@ impl_outer_event! { pub enum TestEvent for Test { frame_system, test_events, - pallet_balances, + pallet_balances Instance1, + pallet_balances Instance2, collateral, treasury, exchange_rate_oracle, @@ -75,7 +77,7 @@ impl frame_system::Trait for Test { type DbWeight = RocksDbWeight; type ExtrinsicBaseWeight = ExtrinsicBaseWeight; type Version = (); - type ModuleToIndex = (); + type PalletInfo = (); type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; @@ -86,25 +88,53 @@ impl frame_system::Trait for Test { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; } -impl pallet_balances::Trait for Test { +/// DOT +impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; + /// The type for recording an account's balance. type Balance = Balance; + /// The ubiquitous event type. type Event = TestEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; + type AccountStore = StorageMapShim< + pallet_balances::Account, + frame_system::CallOnCreatedAccount, + frame_system::CallKillAccount, + AccountId, + pallet_balances::AccountData, + >; + type WeightInfo = (); +} + +/// PolkaBTC +impl pallet_balances::Trait for Test { + type MaxLocks = MaxLocks; + type Balance = Balance; + type Event = TestEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = StorageMapShim< + pallet_balances::Account, + frame_system::CallOnCreatedAccount, + frame_system::CallKillAccount, + AccountId, + pallet_balances::AccountData, + >; type WeightInfo = (); } impl collateral::Trait for Test { - type DOT = Balances; type Event = TestEvent; + type DOT = pallet_balances::Module; } impl treasury::Trait for Test { - type PolkaBTC = Balances; type Event = TestEvent; + type PolkaBTC = pallet_balances::Module; } parameter_types! { @@ -119,18 +149,18 @@ impl timestamp::Trait for Test { impl exchange_rate_oracle::Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl Trait for Test { type Event = TestEvent; + type WeightInfo = (); } impl security::Trait for Test { type Event = TestEvent; } -pub type Balances = pallet_balances::Module; - pub type TestError = Error; pub type SecurityError = security::Error; pub type CollateralError = collateral::Error; @@ -147,29 +177,47 @@ pub const DEFAULT_COLLATERAL: u128 = 100; pub const RICH_COLLATERAL: u128 = DEFAULT_COLLATERAL + 50; impl ExtBuilder { - pub fn build() -> sp_io::TestExternalities { + pub fn build_with( + conf: pallet_balances::GenesisConfig, + ) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (DEFAULT_ID, DEFAULT_COLLATERAL), - (OTHER_ID, DEFAULT_COLLATERAL), - (RICH_ID, RICH_COLLATERAL), - ], - } - .assimilate_storage(&mut storage) - .unwrap(); + conf.assimilate_storage(&mut storage).unwrap(); - GenesisConfig { - secure_collateral_threshold: 100000, + pallet_balances::GenesisConfig:: { balances: vec![] } + .assimilate_storage(&mut storage) + .unwrap(); + + // Parameters to be set in tests + GenesisConfig:: { + minimum_collateral_vault: 0, + punishment_fee: 0, + punishment_delay: 0, + redeem_premium_fee: 0, + secure_collateral_threshold: 0, + auction_collateral_threshold: 0, + premium_redeem_threshold: 0, + liquidation_collateral_threshold: 0, + liquidation_vault: 0, } .assimilate_storage(&mut storage) .unwrap(); sp_io::TestExternalities::from(storage) } + pub fn build() -> sp_io::TestExternalities { + ExtBuilder::build_with( + pallet_balances::GenesisConfig:: { + balances: vec![ + (DEFAULT_ID, DEFAULT_COLLATERAL), + (OTHER_ID, DEFAULT_COLLATERAL), + (RICH_ID, RICH_COLLATERAL), + ], + }, + ) + } } pub fn run_test(test: T) -> () diff --git a/crates/vault-registry/src/tests.rs b/crates/vault-registry/src/tests.rs index a093d9dda7..daa8307b4d 100644 --- a/crates/vault-registry/src/tests.rs +++ b/crates/vault-registry/src/tests.rs @@ -6,10 +6,10 @@ use mocktopus::mocking::*; use crate::ext; use crate::mock::{ run_test, CollateralError, Origin, SecurityError, System, Test, TestError, TestEvent, - VaultRegistry, DEFAULT_COLLATERAL, DEFAULT_ID, RICH_COLLATERAL, RICH_ID, + VaultRegistry, DEFAULT_COLLATERAL, DEFAULT_ID, OTHER_ID, RICH_COLLATERAL, RICH_ID, }; -use crate::types::VaultStatus; use crate::GRANULARITY; +use crate::{Vault, VaultStatus, Wallet}; type Event = crate::Event; @@ -55,7 +55,7 @@ fn create_vault(id: u64) -> ::AccountId { .mock_safe(|| MockResult::Return(DEFAULT_COLLATERAL)); let collateral = DEFAULT_COLLATERAL; let origin = Origin::signed(id); - let result = VaultRegistry::register_vault(origin, collateral, H160::zero()); + let result = VaultRegistry::register_vault(origin, collateral, H160::random()); assert_ok!(result); id } @@ -67,6 +67,8 @@ fn create_sample_vault() -> ::AccountId { fn create_sample_vault_and_issue_tokens( issue_tokens: u128, ) -> ::AccountId { + set_default_thresholds(); + // vault has no tokens issued yet let id = create_sample_vault(); @@ -79,11 +81,14 @@ fn create_sample_vault_and_issue_tokens( let vault = VaultRegistry::_get_vault_from_id(&id).unwrap(); assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, issue_tokens), - vault.btc_address + vault.wallet.get_btc_address() ); let res = VaultRegistry::_issue_tokens(&id, issue_tokens); assert_ok!(res); + // mint tokens to the vault + treasury::Module::::mint(id, issue_tokens); + id } @@ -191,7 +196,7 @@ fn increase_to_be_issued_tokens_succeeds() { set_default_thresholds(); let res = VaultRegistry::_increase_to_be_issued_tokens(&id, 50); let vault = VaultRegistry::_get_vault_from_id(&id).unwrap(); - assert_ok!(res, vault.btc_address); + assert_ok!(res, vault.wallet.get_btc_address()); assert_eq!(vault.to_be_issued_tokens, 50); assert_emitted!(Event::IncreaseToBeIssuedTokens(id, 50)); }); @@ -216,7 +221,7 @@ fn decrease_to_be_issued_tokens_succeeds() { set_default_thresholds(); assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, 50), - vault.btc_address + vault.wallet.get_btc_address() ); let res = VaultRegistry::_decrease_to_be_issued_tokens(&id, 50); assert_ok!(res); @@ -244,7 +249,7 @@ fn issue_tokens_succeeds() { set_default_thresholds(); assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, 50), - vault.btc_address + vault.wallet.get_btc_address() ); let res = VaultRegistry::_issue_tokens(&id, 50); assert_ok!(res); @@ -275,7 +280,7 @@ fn increase_to_be_redeemed_tokens_succeeds() { assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, 50), - vault.btc_address + vault.wallet.get_btc_address() ); assert_ok!(VaultRegistry::_issue_tokens(&id, 50)); let res = VaultRegistry::_increase_to_be_redeemed_tokens(&id, 50); @@ -306,7 +311,7 @@ fn decrease_to_be_redeemed_tokens_succeeds() { assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, 50), - vault.btc_address + vault.wallet.get_btc_address() ); assert_ok!(VaultRegistry::_issue_tokens(&id, 50)); assert_ok!(VaultRegistry::_increase_to_be_redeemed_tokens(&id, 50)); @@ -491,7 +496,7 @@ fn redeem_tokens_liquidation_fails_with_insufficient_tokens() { fn replace_tokens_liquidation_succeeds() { run_test(|| { let old_id = create_sample_vault(); - let new_id = create_vault(DEFAULT_ID + 1); + let new_id = create_vault(OTHER_ID); set_default_thresholds(); ext::collateral::lock::.mock_safe(move |sender, amount| { @@ -519,7 +524,7 @@ fn replace_tokens_liquidation_succeeds() { fn replace_tokens_liquidation_fails_with_insufficient_tokens() { run_test(|| { let old_id = create_sample_vault(); - let new_id = create_vault(DEFAULT_ID + 1); + let new_id = create_vault(OTHER_ID); let res = VaultRegistry::_replace_tokens(&old_id, &new_id, 50, 20); assert_err!(res, TestError::InsufficientTokensCommitted); @@ -531,7 +536,7 @@ fn replace_tokens_liquidation_fails_with_insufficient_tokens() { fn liquidate_succeeds() { run_test(|| { let id = create_sample_vault(); - let liquidation_id = create_vault(DEFAULT_ID + 1); + let liquidation_id = create_vault(OTHER_ID); >::put(liquidation_id); set_default_thresholds(); @@ -576,7 +581,7 @@ fn liquidate_succeeds() { fn liquidate_with_status_succeeds() { run_test(|| { let id = create_sample_vault(); - let liquidation_id = create_vault(DEFAULT_ID + 1); + let liquidation_id = create_vault(OTHER_ID); >::put(liquidation_id); set_default_thresholds(); @@ -668,6 +673,39 @@ fn calculate_max_polkabtc_from_collateral_for_threshold_succeeds() { ); }) } +#[test] +fn get_required_collateral_for_polkabtc_with_threshold_succeeds() { + run_test(|| { + let threshold = 19999; // 199.99% + let random_start = 987529387592 as u128; + for btc in random_start..random_start + threshold { + ext::oracle::dots_to_btc::.mock_safe(move |x| MockResult::Return(Ok(x.clone()))); + ext::oracle::btc_to_dots::.mock_safe(move |x| MockResult::Return(Ok(x.clone()))); + + let min_collateral = + VaultRegistry::get_required_collateral_for_polkabtc_with_threshold(btc, threshold) + .unwrap(); + + let max_btc_for_min_collateral = + VaultRegistry::calculate_max_polkabtc_from_collateral_for_threshold( + min_collateral, + threshold, + ) + .unwrap(); + + let max_btc_for_below_min_collateral = + VaultRegistry::calculate_max_polkabtc_from_collateral_for_threshold( + min_collateral - 1, + threshold, + ) + .unwrap(); + + // Check that the amount we found is indeed the lowest amount that is sufficient for `btc` + assert!(max_btc_for_min_collateral >= btc); + assert!(max_btc_for_below_min_collateral < btc); + } + }) +} #[test] fn _is_vault_below_auction_threshold_false_succeeds() { @@ -680,7 +718,7 @@ fn _is_vault_below_auction_threshold_false_succeeds() { let vault = VaultRegistry::_get_vault_from_id(&id).unwrap(); assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, 50), - vault.btc_address + vault.wallet.get_btc_address() ); let res = VaultRegistry::_issue_tokens(&id, 50); assert_ok!(res); @@ -689,7 +727,7 @@ fn _is_vault_below_auction_threshold_false_succeeds() { ext::oracle::dots_to_btc::.mock_safe(|_| MockResult::Return(Ok(DEFAULT_COLLATERAL))); assert_eq!( - VaultRegistry::_is_vault_below_auction_threshold(&id), + VaultRegistry::is_vault_below_auction_threshold(&id), Ok(false) ) }); @@ -739,7 +777,7 @@ fn _is_vault_below_liquidation_threshold_true_succeeds() { let vault = VaultRegistry::_get_vault_from_id(&id).unwrap(); assert_ok!( VaultRegistry::_increase_to_be_issued_tokens(&id, 50), - vault.btc_address + vault.wallet.get_btc_address() ); let res = VaultRegistry::_issue_tokens(&id, 50); assert_ok!(res); @@ -806,3 +844,83 @@ fn get_first_vault_with_sufficient_tokens_succeeds() { ); }) } + +#[test] +fn get_total_collateralization_with_tokens_issued() { + run_test(|| { + let issue_tokens: u128 = DEFAULT_COLLATERAL / 10 / 2; // = 5 + let _id = create_sample_vault_and_issue_tokens(issue_tokens); + + assert_eq!( + VaultRegistry::get_total_collateralization(), + Ok(2 * 10u64.pow(GRANULARITY)) + ); + }) +} + +#[test] +fn wallet_add_btc_address_succeeds() { + run_test(|| { + let address1 = H160::random(); + let address2 = H160::random(); + let address3 = H160::random(); + + let mut wallet = Wallet::new(address1); + assert_eq!(wallet.get_btc_address(), address1); + + wallet.add_btc_address(address2); + assert_eq!(wallet.get_btc_address(), address2); + + wallet.add_btc_address(address3); + assert_eq!(wallet.get_btc_address(), address3); + }); +} + +#[test] +fn wallet_has_btc_address_succeeds() { + run_test(|| { + let address1 = H160::random(); + let address2 = H160::random(); + + let wallet = Wallet::new(address1); + assert_eq!(wallet.has_btc_address(&address1), true); + assert_eq!(wallet.has_btc_address(&address2), false); + }); +} + +#[test] +fn update_btc_address_fails_with_btc_address_taken() { + run_test(|| { + let origin = DEFAULT_ID; + let address = H160::random(); + + let mut vault = Vault::default(); + vault.id = origin; + vault.wallet = Wallet::new(address); + VaultRegistry::_insert_vault(&origin, vault); + + assert_err!( + VaultRegistry::update_btc_address(Origin::signed(origin), address), + TestError::BtcAddressTaken + ); + }); +} + +#[test] +fn update_btc_address_succeeds() { + run_test(|| { + let origin = DEFAULT_ID; + let address1 = H160::random(); + let address2 = H160::random(); + + let mut vault = Vault::default(); + vault.id = origin; + vault.wallet = Wallet::new(address1); + VaultRegistry::_insert_vault(&origin, vault); + + assert_ok!(VaultRegistry::update_btc_address( + Origin::signed(origin), + address2 + )); + }); +} diff --git a/crates/vault-registry/src/types.rs b/crates/vault-registry/src/types.rs index 782e4ba95d..418f4ead46 100644 --- a/crates/vault-registry/src/types.rs +++ b/crates/vault-registry/src/types.rs @@ -6,6 +6,7 @@ use frame_support::{ ensure, StorageMap, }; use sp_core::H160; +use sp_std::collections::btree_set::BTreeSet; #[cfg(test)] use mocktopus::macros::mockable; @@ -18,6 +19,41 @@ pub(crate) type DOT = pub(crate) type PolkaBTC = <::PolkaBTC as Currency<::AccountId>>::Balance; +#[derive(Encode, Decode, Clone, PartialEq, Debug, Default)] +pub struct Wallet { + // store all addresses for `report_vault_theft` checks + addresses: BTreeSet, + // we use the most recent address for issue / redeem requests + address: H160, +} + +impl Wallet { + pub fn new(hash: H160) -> Self { + let mut addresses = BTreeSet::new(); + addresses.insert(hash); + Self { + addresses, + address: hash, + } + } + + pub fn has_btc_address(&self, hash: &H160) -> bool { + self.addresses.contains(hash) + } + + pub fn add_btc_address(&mut self, hash: H160) { + // TODO: add maximum or griefing collateral + self.addresses.insert(hash); + // NOTE: updates primary address even if already contained in set + self.address = hash; + } + + pub fn get_btc_address(&self) -> H160 { + // wallet should never be empty + self.address + } +} + #[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] pub enum VaultStatus { /// Vault is active @@ -50,11 +86,10 @@ pub struct Vault { // DOT collateral locked by this Vault // collateral: DOT, // Bitcoin address of this Vault (P2PKH, P2SH, P2PKH, P2WSH) - pub btc_address: H160, + pub wallet: Wallet, // Block height until which this Vault is banned from being // used for Issue, Redeem (except during automatic liquidation) and Replace . pub banned_until: Option, - /// Current status of the vault pub status: VaultStatus, } @@ -63,9 +98,10 @@ impl Vault { pub(crate) fn new(id: AccountId, btc_address: H160) -> Vault { + let wallet = Wallet::new(btc_address); Vault { id, - btc_address, + wallet, to_be_issued_tokens: Default::default(), issued_tokens: Default::default(), to_be_redeemed_tokens: Default::default(), @@ -137,7 +173,7 @@ impl RichVault { let raw_issued_tokens_in_dot = crate::Module::::dot_to_u128(issued_tokens_in_dot)?; - let secure_threshold = crate::Module::::_get_secure_collateral_threshold(); + let secure_threshold = crate::Module::::secure_collateral_threshold(); let raw_used_collateral = raw_issued_tokens_in_dot .checked_mul(secure_threshold) @@ -153,7 +189,7 @@ impl RichVault { pub fn issuable_tokens(&self) -> Result, DispatchError> { let free_collateral = self.get_free_collateral()?; - let secure_threshold = crate::Module::::_get_secure_collateral_threshold(); + let secure_threshold = crate::Module::::secure_collateral_threshold(); let issuable = crate::Module::::calculate_max_polkabtc_from_collateral_for_threshold( free_collateral, @@ -265,6 +301,12 @@ impl RichVault { self.update(|v| v.banned_until = Some(height)); } + pub fn update_btc_address(&mut self, btc_address: H160) { + self.update(|v| { + v.wallet.add_btc_address(btc_address); + }); + } + fn update(&mut self, func: F) -> () where F: Fn(&mut DefaultVault) -> (), diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index 5b75af5910..8907ff6284 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -3,7 +3,12 @@ authors = ['Interlay Ltd'] build = 'build.rs' edition = '2018' name = 'btc-parachain' -version = '2.0.0-rc6' +version = '0.2.3' + +[features] +runtime-benchmarks = [ + "btc-parachain-runtime/runtime-benchmarks", +] [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -12,84 +17,86 @@ targets = ['x86_64-unknown-linux-gnu'] name = 'btc-parachain' [dependencies] -jsonrpc-core = '14.0.3' +jsonrpc-core = '15.0.0' structopt = '0.3.8' +frame-benchmarking = "2.0.0" +frame-benchmarking-cli = '2.0.0' [dependencies.btc-parachain-runtime] path = './runtime' -version = '2.0.0-rc6' +version = '0.2.3' [dependencies.pallet-transaction-payment-rpc] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sc-basic-authorship] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-cli] features = ['wasmtime'] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-client-api] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sc-consensus] -version = "0.8.0-rc6" +version = "0.8.0" [dependencies.sc-consensus-aura] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-executor] features = ['wasmtime'] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-finality-grandpa] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-rpc] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sc-rpc-api] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-service] features = ['wasmtime'] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sc-transaction-pool] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-api] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-block-builder] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-blockchain] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-consensus] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sp-consensus-aura] -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sp-core] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-finality-grandpa] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-inherents] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-transaction-pool] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.substrate-frame-rpc-system] -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.module-exchange-rate-oracle-rpc] path = "../crates/exchange-rate-oracle/rpc" @@ -100,5 +107,14 @@ path = "../crates/staked-relayers/rpc" [dependencies.module-vault-registry-rpc] path = "../crates/vault-registry/rpc" +[dependencies.module-issue-rpc] +path = "../crates/issue/rpc" + +[dependencies.module-redeem-rpc] +path = "../crates/redeem/rpc" + +[dependencies.module-replace-rpc] +path = "../crates/replace/rpc" + [build-dependencies.substrate-build-script-utils] -version = '2.0.0-rc6' +version = '2.0.0' diff --git a/parachain/runtime/Cargo.toml b/parachain/runtime/Cargo.toml index d360d75b7c..0d65bee8d9 100644 --- a/parachain/runtime/Cargo.toml +++ b/parachain/runtime/Cargo.toml @@ -1,10 +1,24 @@ +[dependencies.hex-literal] +optional = true +version = '0.3.1' + +[dependencies.frame-benchmarking] +version = "2.0.0" +default-features = false +optional = true + +[dependencies.frame-system-benchmarking] +default-features = false +optional = true +version = '2.0.0' + [dependencies.pallet-aura] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-balances] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.codec] default-features = false @@ -14,19 +28,19 @@ version = '1.3.4' [dependencies.frame-executive] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-support] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-grandpa] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-randomness-collective-flip] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.serde] features = ['derive'] @@ -35,75 +49,75 @@ version = '1.0.101' [dependencies.sp-api] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-block-builder] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-consensus-aura] default-features = false -version = '0.8.0-rc6' +version = '0.8.0' [dependencies.sp-core] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-inherents] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-io] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-offchain] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-runtime] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-session] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-std] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-transaction-pool] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.sp-version] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-sudo] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.frame-system-rpc-runtime-api] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-timestamp] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-transaction-payment] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [dependencies.pallet-transaction-payment-rpc-runtime-api] default-features = false -version = '2.0.0-rc6' +version = '2.0.0' [build-dependencies.wasm-builder-runner] package = 'substrate-wasm-builder-runner' @@ -171,6 +185,18 @@ path = '../../crates/staked-relayers/rpc/runtime-api' default-features = false path = '../../crates/vault-registry/rpc/runtime-api' +[dependencies.module-issue-rpc-runtime-api] +default-features = false +path = '../../crates/issue/rpc/runtime-api' + +[dependencies.module-redeem-rpc-runtime-api] +default-features = false +path = '../../crates/redeem/rpc/runtime-api' + +[dependencies.module-replace-rpc-runtime-api] +default-features = false +path = '../../crates/replace/rpc/runtime-api' + [dev-dependencies.bitcoin] default-features = false package = 'bitcoin' @@ -190,7 +216,7 @@ serde_json = "1.0" authors = ['Interlay Ltd'] edition = '2018' name = 'btc-parachain-runtime' -version = '2.0.0-rc6' +version = '0.2.3' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -227,6 +253,9 @@ std = [ 'module-exchange-rate-oracle-rpc-runtime-api/std', 'module-staked-relayers-rpc-runtime-api/std', 'module-vault-registry-rpc-runtime-api/std', + 'module-issue-rpc-runtime-api/std', + 'module-redeem-rpc-runtime-api/std', + 'module-replace-rpc-runtime-api/std', 'btc-relay/std', 'collateral/std', 'treasury/std', @@ -237,4 +266,21 @@ std = [ 'issue/std', 'redeem/std', 'replace/std', + 'frame-benchmarking/std', ] +runtime-benchmarks = [ + 'hex-literal', + + "frame-benchmarking", + 'frame-system-benchmarking', + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + + "btc-relay/runtime-benchmarks", + "exchange-rate-oracle/runtime-benchmarks", + "issue/runtime-benchmarks", + "redeem/runtime-benchmarks", + "replace/runtime-benchmarks", + "staked-relayers/runtime-benchmarks", + "vault-registry/runtime-benchmarks", +] \ No newline at end of file diff --git a/parachain/runtime/src/lib.rs b/parachain/runtime/src/lib.rs index 2eb7bf79f1..847a75b3b7 100644 --- a/parachain/runtime/src/lib.rs +++ b/parachain/runtime/src/lib.rs @@ -10,10 +10,12 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use frame_support::dispatch::{DispatchError, DispatchResult}; use frame_support::traits::StorageMapShim; +pub use module_vault_registry_rpc_runtime_api::BalanceWrapper; use pallet_grandpa::fg_primitives; use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_core::H256; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::traits::{ BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, NumberFor, Saturating, Verify, @@ -185,7 +187,7 @@ impl frame_system::Trait for Runtime { /// Converts a module to the index of the module in `construct_runtime!`. /// /// This type is being generated by `construct_runtime!`. - type ModuleToIndex = ModuleToIndex; + type PalletInfo = PalletInfo; /// What to do if a new account is created. type OnNewAccount = (); /// What to do if an account is fully reaped from the frame_system. @@ -215,6 +217,8 @@ impl pallet_grandpa::Trait for Runtime { )>>::IdentificationTuple; type HandleEquivocation = (); + + type WeightInfo = (); } parameter_types! { @@ -248,10 +252,12 @@ impl pallet_sudo::Trait for Runtime { parameter_types! { pub const ExistentialDeposit: u128 = 500; + pub const MaxLocks: u32 = 50; } /// DOT impl pallet_balances::Trait for Runtime { + type MaxLocks = MaxLocks; /// The type for recording an account's balance. type Balance = Balance; /// The ubiquitous event type. @@ -270,6 +276,7 @@ impl pallet_balances::Trait for Runtime { /// PolkaBTC impl pallet_balances::Trait for Runtime { + type MaxLocks = MaxLocks; type Balance = Balance; type Event = Event; type DustRemoval = (); @@ -286,6 +293,7 @@ impl pallet_balances::Trait for Runtime { impl btc_relay::Trait for Runtime { type Event = Event; + type WeightInfo = (); } impl collateral::Trait for Runtime { @@ -309,46 +317,50 @@ parameter_types! { pub const MinimumParticipants: u32 = 3; pub const VoteThreshold: u32 = 50; pub const VotingPeriod: BlockNumber = DAYS; + pub const MaximumMessageSize: u32 = 256; } impl staked_relayers::Trait for Runtime { type Event = Event; + type WeightInfo = (); type MaturityPeriod = MaturityPeriod; type MinimumDeposit = MinimumDeposit; type MinimumStake = MinimumStake; type MinimumParticipants = MinimumParticipants; type VoteThreshold = VoteThreshold; type VotingPeriod = VotingPeriod; + type MaximumMessageSize = MaximumMessageSize; } impl vault_registry::Trait for Runtime { type Event = Event; + type WeightInfo = (); } impl exchange_rate_oracle::Trait for Runtime { type Event = Event; + type WeightInfo = (); } -parameter_types! { - pub const IssuePeriod: BlockNumber = DAYS; -} +pub use issue::IssueRequest; impl issue::Trait for Runtime { type Event = Event; - type IssuePeriod = IssuePeriod; + type WeightInfo = (); } +pub use redeem::RedeemRequest; + impl redeem::Trait for Runtime { type Event = Event; + type WeightInfo = (); } -parameter_types! { - pub const ReplacePeriod: BlockNumber = 10; -} +pub use replace::ReplaceRequest; impl replace::Trait for Runtime { type Event = Event; - type ReplacePeriod = ReplacePeriod; + type WeightInfo = (); } construct_runtime!( @@ -372,11 +384,11 @@ construct_runtime!( Treasury: treasury::{Module, Call, Storage, Event}, Security: security::{Module, Call, Storage, Event}, StakedRelayers: staked_relayers::{Module, Call, Config, Storage, Event}, - VaultRegistry: vault_registry::{Module, Call, Config, Storage, Event}, + VaultRegistry: vault_registry::{Module, Call, Config, Storage, Event}, ExchangeRateOracle: exchange_rate_oracle::{Module, Call, Config, Storage, Event}, - Issue: issue::{Module, Call, Storage, Event}, - Redeem: redeem::{Module, Call, Storage, Event}, - Replace: replace::{Module, Call, Storage, Event}, + Issue: issue::{Module, Call, Config, Storage, Event}, + Redeem: redeem::{Module, Call, Config, Storage, Event}, + Replace: replace::{Module, Call, Config, Storage, Event}, } ); @@ -537,6 +549,45 @@ impl_runtime_apis! { } } + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + + // use frame_system_benchmarking::Module as SystemBench; + impl frame_system_benchmarking::Trait for Runtime {} + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), + // Total Issuance + hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), + // Execution Phase + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), + // Event Count + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), + // System Events + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + add_benchmark!(params, batches, btc_relay, BTCRelay); + add_benchmark!(params, batches, exchange_rate_oracle, ExchangeRateOracle); + add_benchmark!(params, batches, issue, Issue); + add_benchmark!(params, batches, redeem, Redeem); + add_benchmark!(params, batches, replace, Replace); + add_benchmark!(params, batches, staked_relayers, StakedRelayers); + add_benchmark!(params, batches, vault_registry, VaultRegistry); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } + impl module_exchange_rate_oracle_rpc_runtime_api::ExchangeRateOracleApi< Block, Balance, @@ -560,21 +611,91 @@ impl_runtime_apis! { Block, AccountId, Balance, + Balance > for Runtime { - fn get_first_vault_with_sufficient_collateral(amount: Balance) -> Result { - VaultRegistry::get_first_vault_with_sufficient_collateral(amount) + fn get_total_collateralization() -> Result { + VaultRegistry::get_total_collateralization() } - fn get_first_vault_with_sufficient_tokens(amount: Balance) -> Result { - VaultRegistry::get_first_vault_with_sufficient_tokens(amount) + fn get_first_vault_with_sufficient_collateral(amount: BalanceWrapper) -> Result { + VaultRegistry::get_first_vault_with_sufficient_collateral(amount.amount) } - fn get_issuable_tokens_from_vault(vault: AccountId) -> Result { - VaultRegistry::get_issuable_tokens_from_vault(vault) + fn get_first_vault_with_sufficient_tokens(amount: BalanceWrapper) -> Result { + VaultRegistry::get_first_vault_with_sufficient_tokens(amount.amount) + } + + fn get_issuable_tokens_from_vault(vault: AccountId) -> Result, DispatchError> { + let result = VaultRegistry::get_issuable_tokens_from_vault(vault)?; + Ok(BalanceWrapper{amount:result}) } fn get_collateralization_from_vault(vault: AccountId) -> Result { VaultRegistry::get_collateralization_from_vault(vault) } + + fn get_collateralization_from_vault_and_collateral(vault: AccountId, collateral: BalanceWrapper) -> Result { + VaultRegistry::get_collateralization_from_vault_and_collateral(vault, collateral.amount) + } + + fn get_required_collateral_for_polkabtc(amount_btc: BalanceWrapper) -> Result, DispatchError> { + let result = VaultRegistry::get_required_collateral_for_polkabtc(amount_btc.amount)?; + Ok(BalanceWrapper{amount:result}) + } + + fn get_required_collateral_for_vault(vault_id: AccountId) -> Result, DispatchError> { + let result = VaultRegistry::get_required_collateral_for_vault(vault_id)?; + Ok(BalanceWrapper{amount:result}) + } + + fn is_vault_below_auction_threshold(vault: AccountId) -> Result { + VaultRegistry::is_vault_below_auction_threshold(&vault) + } + } + + impl module_issue_rpc_runtime_api::IssueApi< + Block, + AccountId, + H256, + IssueRequest + > for Runtime { + fn get_issue_requests(account_id: AccountId) -> Vec<(H256, IssueRequest)> { + Issue::get_issue_requests_for_account(account_id) + } + + fn get_vault_issue_requests(account_id: AccountId) -> Vec<(H256, IssueRequest)> { + Issue::get_issue_requests_for_vault(account_id) + } + } + + impl module_redeem_rpc_runtime_api::RedeemApi< + Block, + AccountId, + H256, + RedeemRequest + > for Runtime { + fn get_redeem_requests(account_id: AccountId) -> Vec<(H256, RedeemRequest)> { + Redeem::get_redeem_requests_for_account(account_id) + } + + fn get_vault_redeem_requests(account_id: AccountId) -> Vec<(H256, RedeemRequest)> { + Redeem::get_redeem_requests_for_vault(account_id) + } } + + impl module_replace_rpc_runtime_api::ReplaceApi< + Block, + AccountId, + H256, + ReplaceRequest + > for Runtime { + fn get_old_vault_replace_requests(account_id: AccountId) -> Vec<(H256, ReplaceRequest)> { + Replace::get_replace_requests_for_old_vault(account_id) + } + + fn get_new_vault_replace_requests(account_id: AccountId) -> Vec<(H256, ReplaceRequest)> { + Replace::get_replace_requests_for_new_vault(account_id) + } + } + } diff --git a/parachain/runtime/tests/mock.rs b/parachain/runtime/tests/mock.rs index cfaade7243..e9a54d843c 100644 --- a/parachain/runtime/tests/mock.rs +++ b/parachain/runtime/tests/mock.rs @@ -13,6 +13,7 @@ pub use sp_std::convert::TryInto; pub const ALICE: [u8; 32] = [0u8; 32]; pub const BOB: [u8; 32] = [1u8; 32]; pub const CLAIRE: [u8; 32] = [2u8; 32]; +pub const VICTOR: [u8; 32] = [3u8; 32]; pub const CONFIRMATIONS: u32 = 6; pub type BTCRelayCall = btc_relay::Call; @@ -216,13 +217,45 @@ impl ExtBuilder { btc_relay::GenesisConfig:: { bitcoin_confirmations: CONFIRMATIONS, parachain_confirmations: CONFIRMATIONS, - difficulty_check: true, + disable_difficulty_check: false, + disable_inclusion_check: false, + disable_op_return_check: false, } .assimilate_storage(&mut storage) .unwrap(); - vault_registry::GenesisConfig { - secure_collateral_threshold: 100000, + vault_registry::GenesisConfig:: { + minimum_collateral_vault: 0, + punishment_fee: 20_000, + punishment_delay: 8, + redeem_premium_fee: 5000, + secure_collateral_threshold: 100_000, + auction_collateral_threshold: 150_000, + premium_redeem_threshold: 120_000, + liquidation_collateral_threshold: 110_000, + liquidation_vault: account_of(VICTOR), + } + .assimilate_storage(&mut storage) + .unwrap(); + + issue::GenesisConfig:: { + issue_griefing_collateral: 10, + issue_period: 10, + } + .assimilate_storage(&mut storage) + .unwrap(); + + redeem::GenesisConfig:: { + redeem_period: 10, + redeem_btc_dust_value: 1, + } + .assimilate_storage(&mut storage) + .unwrap(); + + replace::GenesisConfig:: { + replace_griefing_collateral: 10, + replace_period: 10, + replace_btc_dust_value: 1, } .assimilate_storage(&mut storage) .unwrap(); diff --git a/parachain/runtime/tests/test_replace.rs b/parachain/runtime/tests/test_replace.rs index 15cb6b8bc5..0b85502941 100644 --- a/parachain/runtime/tests/test_replace.rs +++ b/parachain/runtime/tests/test_replace.rs @@ -38,16 +38,14 @@ fn integration_test_replace_request_replace() { ExtBuilder::build().execute_with(|| { SystemModule::set_block_number(1); let amount = 1000; + let collateral = amount * 2; let griefing_collateral = 200; // peg spot rate assert_ok!(Call::ExchangeRateOracle(OracleCall::set_exchange_rate(1)) .dispatch(origin_of(account_of(BOB)))); // bob creates a vault - assert_ok!( - Call::VaultRegistry(VaultRegistryCall::register_vault(amount, H160([0; 20]))) - .dispatch(origin_of(account_of(BOB))) - ); + force_issue_tokens(ALICE, BOB, collateral, amount, H160::random()); // bob requests a replace assert_ok!( Call::Replace(ReplaceCall::request_replace(amount, griefing_collateral)) @@ -63,18 +61,15 @@ fn integration_test_replace_withdraw_replace() { ExtBuilder::build().execute_with(|| { SystemModule::set_block_number(1); let griefing_collateral = 200; - let collateral = 100_000; + let amount = 50_000; + let collateral = amount * 2; let bob = origin_of(account_of(BOB)); // peg spot rate assert_ok!(Call::ExchangeRateOracle(OracleCall::set_exchange_rate(1)) .dispatch(origin_of(account_of(BOB)))); // bob creates a vault - assert_ok!(Call::VaultRegistry(VaultRegistryCall::register_vault( - collateral, - H160([0; 20]) - )) - .dispatch(origin_of(account_of(BOB)))); + force_issue_tokens(ALICE, BOB, collateral, amount, H160::random()); // bob requests a replace assert_ok!( Call::Replace(ReplaceCall::request_replace(5000, griefing_collateral)) @@ -97,16 +92,13 @@ fn integration_test_replace_accept_replace() { // peg spot rate assert_ok!(Call::ExchangeRateOracle(OracleCall::set_exchange_rate(1)) .dispatch(origin_of(account_of(BOB)))); - // bob creates a vault - assert_ok!( - Call::VaultRegistry(VaultRegistryCall::register_vault(amount, H160([0; 20]))) - .dispatch(origin_of(account_of(ALICE))) - ); // alice creates a vault assert_ok!( - Call::VaultRegistry(VaultRegistryCall::register_vault(amount, H160([0; 20]))) - .dispatch(origin_of(account_of(BOB))) + Call::VaultRegistry(VaultRegistryCall::register_vault(amount, H160::random())) + .dispatch(origin_of(account_of(ALICE))) ); + // bob creates a vault + force_issue_tokens(ALICE, BOB, collateral, amount, H160::random()); // bob requests a replace assert_ok!( Call::Replace(ReplaceCall::request_replace(amount, griefing_collateral)) @@ -130,7 +122,9 @@ fn integration_test_replace_auction_replace() { let new_vault = BOB; let collateral = 4_000; let polkabtc = 1_000; - let vault_btc_address = H160([0u8; 20]); + + let old_vault_btc_address = H160::random(); + let new_vault_btc_address = H160::random(); set_default_thresholds(); // peg spot rate @@ -138,12 +132,12 @@ fn integration_test_replace_auction_replace() { .dispatch(origin_of(account_of(BOB)))); // old vault has issued some tokens with the user - force_issue_tokens(user, old_vault, collateral, polkabtc, vault_btc_address); + force_issue_tokens(user, old_vault, collateral, polkabtc, old_vault_btc_address); // new vault joins assert_ok!(Call::VaultRegistry(VaultRegistryCall::register_vault( collateral, - vault_btc_address + new_vault_btc_address )) .dispatch(origin_of(account_of(new_vault)))); // exchange rate drops and vault is not collateralized any more @@ -168,7 +162,9 @@ fn integration_test_replace_execute_replace() { let griefing_collateral = 50; let collateral = 4_000; let polkabtc = 1_000; - let vault_btc_address = H160([0u8; 20]); + + let old_vault_btc_address = H160::random(); + let new_vault_btc_address = H160::random(); set_default_thresholds(); SystemModule::set_block_number(1); @@ -178,12 +174,12 @@ fn integration_test_replace_execute_replace() { .dispatch(origin_of(account_of(BOB)))); // old vault has issued some tokens with the user - force_issue_tokens(user, old_vault, collateral, polkabtc, vault_btc_address); + force_issue_tokens(user, old_vault, collateral, polkabtc, old_vault_btc_address); // new vault joins assert_ok!(Call::VaultRegistry(VaultRegistryCall::register_vault( collateral, - vault_btc_address + new_vault_btc_address )) .dispatch(origin_of(account_of(new_vault)))); @@ -202,7 +198,7 @@ fn integration_test_replace_execute_replace() { // send the btc from the old_vault to the new_vault let (tx_id, tx_block_height, merkle_proof, raw_tx) = - generate_transaction_and_mine(vault_btc_address, polkabtc, replace_id); + generate_transaction_and_mine(new_vault_btc_address, polkabtc, replace_id); SystemModule::set_block_number(1 + CONFIRMATIONS); let r = Call::Replace(ReplaceCall::execute_replace( @@ -228,16 +224,13 @@ fn integration_test_replace_cancel_replace() { // peg spot rate assert_ok!(Call::ExchangeRateOracle(OracleCall::set_exchange_rate(1)) .dispatch(origin_of(account_of(BOB)))); - // bob creates a vault - assert_ok!( - Call::VaultRegistry(VaultRegistryCall::register_vault(amount, H160([0; 20]))) - .dispatch(origin_of(account_of(ALICE))) - ); // alice creates a vault assert_ok!( - Call::VaultRegistry(VaultRegistryCall::register_vault(10, H160([0; 20]))) - .dispatch(origin_of(account_of(BOB))) + Call::VaultRegistry(VaultRegistryCall::register_vault(amount, H160::random())) + .dispatch(origin_of(account_of(ALICE))) ); + // bob creates a vault + force_issue_tokens(ALICE, BOB, collateral, amount, H160::random()); // bob requests a replace assert_ok!( Call::Replace(ReplaceCall::request_replace(amount, griefing_collateral)) diff --git a/parachain/src/chain_spec.rs b/parachain/src/chain_spec.rs index 27a551bc98..f760a44ee7 100644 --- a/parachain/src/chain_spec.rs +++ b/parachain/src/chain_spec.rs @@ -1,7 +1,7 @@ use btc_parachain_runtime::{ AccountId, AuraConfig, BTCRelayConfig, DOTConfig, ExchangeRateOracleConfig, GenesisConfig, - GrandpaConfig, PolkaBTCConfig, Signature, StakedRelayersConfig, SudoConfig, SystemConfig, - VaultRegistryConfig, WASM_BINARY, + GrandpaConfig, IssueConfig, PolkaBTCConfig, RedeemConfig, ReplaceConfig, Signature, + StakedRelayersConfig, SudoConfig, SystemConfig, VaultRegistryConfig, DAYS, WASM_BINARY, }; use sc_service::ChainType; use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -9,6 +9,9 @@ use sp_core::{sr25519, Pair, Public}; use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; +#[cfg(feature = "runtime-benchmarks")] +use frame_benchmarking::account; + // The URL for the telemetry server. // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -37,7 +40,7 @@ pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { (get_from_seed::(s), get_from_seed::(s)) } -pub fn development_config() -> Result { +pub fn development_config(inclusion_check: bool) -> Result { let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?; Ok(ChainSpec::from_genesis( @@ -67,8 +70,13 @@ pub fn development_config() -> Result { get_account_id_from_seed::("Dave//stash"), get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), + #[cfg(feature = "runtime-benchmarks")] + account("Origin", 0, 0), + #[cfg(feature = "runtime-benchmarks")] + account("Vault", 0, 0), ], true, + inclusion_check, ) }, // Bootnodes @@ -84,7 +92,7 @@ pub fn development_config() -> Result { )) } -pub fn local_testnet_config() -> Result { +pub fn local_testnet_config(inclusion_check: bool) -> Result { let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?; Ok(ChainSpec::from_genesis( @@ -119,6 +127,7 @@ pub fn local_testnet_config() -> Result { get_account_id_from_seed::("Ferdie//stash"), ], true, + inclusion_check, ) }, // Bootnodes @@ -141,6 +150,7 @@ fn testnet_genesis( root_key: AccountId, endowed_accounts: Vec, _enable_println: bool, + inclusion_check: bool, ) -> GenesisConfig { let bob_account_id = get_account_id_from_seed::("Bob"); GenesisConfig { @@ -171,6 +181,9 @@ fn testnet_genesis( }), pallet_balances_Instance2: Some(PolkaBTCConfig { balances: vec![] }), staked_relayers: Some(StakedRelayersConfig { + #[cfg(feature = "runtime-benchmarks")] + gov_id: account("Origin", 0, 0), + #[cfg(not(feature = "runtime-benchmarks"))] gov_id: get_account_id_from_seed::("Alice"), }), exchange_rate_oracle: Some(ExchangeRateOracleConfig { @@ -181,10 +194,33 @@ fn testnet_genesis( btc_relay: Some(BTCRelayConfig { bitcoin_confirmations: 0, parachain_confirmations: 0, - difficulty_check: false, + disable_difficulty_check: true, + disable_inclusion_check: !inclusion_check, + disable_op_return_check: false, + }), + issue: Some(IssueConfig { + issue_griefing_collateral: 10, + issue_period: 7 * DAYS, + }), + redeem: Some(RedeemConfig { + redeem_period: 7 * DAYS, + redeem_btc_dust_value: 1000, + }), + replace: Some(ReplaceConfig { + replace_griefing_collateral: 10, + replace_period: 7 * DAYS, + replace_btc_dust_value: 1000, }), vault_registry: Some(VaultRegistryConfig { - secure_collateral_threshold: 100000, + minimum_collateral_vault: 0, + punishment_fee: 20_000, + punishment_delay: 8, + redeem_premium_fee: 5000, + secure_collateral_threshold: 200_000, + auction_collateral_threshold: 150_000, + premium_redeem_threshold: 120_000, + liquidation_collateral_threshold: 110_000, + liquidation_vault: get_account_id_from_seed::("Victor"), }), } } diff --git a/parachain/src/cli.rs b/parachain/src/cli.rs index afdf49cbcd..639156f19a 100644 --- a/parachain/src/cli.rs +++ b/parachain/src/cli.rs @@ -1,4 +1,4 @@ -use sc_cli::{RunCmd, Subcommand}; +use sc_cli::RunCmd; use structopt::StructOpt; #[derive(Debug, StructOpt)] @@ -9,3 +9,31 @@ pub struct Cli { #[structopt(flatten)] pub run: RunCmd, } + +#[derive(Debug, StructOpt)] +pub enum Subcommand { + /// Build a chain specification. + BuildSpec(sc_cli::BuildSpecCmd), + + /// Validate blocks. + CheckBlock(sc_cli::CheckBlockCmd), + + /// Export blocks. + ExportBlocks(sc_cli::ExportBlocksCmd), + + /// Export the state of a given block into a chain spec. + ExportState(sc_cli::ExportStateCmd), + + /// Import blocks. + ImportBlocks(sc_cli::ImportBlocksCmd), + + /// Remove the whole chain. + PurgeChain(sc_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// The custom benchmark subcommmand benchmarking runtime pallets. + #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} diff --git a/parachain/src/command.rs b/parachain/src/command.rs index c14925fece..3727944baf 100644 --- a/parachain/src/command.rs +++ b/parachain/src/command.rs @@ -15,9 +15,9 @@ // along with Substrate. If not, see . use crate::chain_spec; -use crate::cli::Cli; +use crate::cli::{Cli, Subcommand}; use crate::service; -use crate::service::new_partial; +use btc_parachain_runtime::Block; use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; @@ -48,8 +48,9 @@ impl SubstrateCli for Cli { fn load_spec(&self, id: &str) -> Result, String> { Ok(match id { - "dev" => Box::new(chain_spec::development_config()?), - "" | "local" => Box::new(chain_spec::local_testnet_config()?), + "dev" => Box::new(chain_spec::development_config(true)?), + "dev-no-btc" => Box::new(chain_spec::development_config(false)?), + "" | "local" => Box::new(chain_spec::local_testnet_config(true)?), path => Box::new(chain_spec::ChainSpec::from_json_file( std::path::PathBuf::from(path), )?), @@ -65,20 +66,84 @@ impl SubstrateCli for Cli { pub fn run() -> sc_cli::Result<()> { let cli = Cli::from_args(); - match cli.subcommand { - Some(ref subcommand) => { - let runner = cli.create_runner(subcommand)?; - runner.run_subcommand(subcommand, |config| { + match &cli.subcommand { + Some(Subcommand::BuildSpec(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) + } + Some(Subcommand::CheckBlock(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { let PartialComponents { client, - backend, task_manager, import_queue, .. - } = new_partial(&config)?; - Ok((client, backend, import_queue, task_manager)) + } = service::new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + } + Some(Subcommand::ExportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { + client, + task_manager, + .. + } = service::new_partial(&config)?; + Ok((cmd.run(client, config.database), task_manager)) }) } + Some(Subcommand::ExportState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { + client, + task_manager, + .. + } = service::new_partial(&config)?; + Ok((cmd.run(client, config.chain_spec), task_manager)) + }) + } + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { + client, + task_manager, + import_queue, + .. + } = service::new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + } + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.database)) + } + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { + client, + task_manager, + backend, + .. + } = service::new_partial(&config)?; + Ok((cmd.run(client, backend), task_manager)) + }) + } + Some(Subcommand::Benchmark(cmd)) => { + if cfg!(feature = "runtime-benchmarks") { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| cmd.run::(config)) + } else { + Err("Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into()) + } + } None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| { diff --git a/parachain/src/rpc.rs b/parachain/src/rpc.rs index debc2dad5a..e6737c1e18 100644 --- a/parachain/src/rpc.rs +++ b/parachain/src/rpc.rs @@ -7,11 +7,15 @@ use std::sync::Arc; -use btc_parachain_runtime::{opaque::Block, AccountId, Balance, Index}; +use btc_parachain_runtime::{ + opaque::Block, AccountId, Balance, BlockNumber, Index, IssueRequest, RedeemRequest, + ReplaceRequest, +}; pub use sc_rpc_api::DenyUnsafe; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_core::H256; use sp_transaction_pool::TransactionPool; /// Full client dependencies. @@ -34,11 +38,32 @@ where C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: module_exchange_rate_oracle_rpc::ExchangeRateOracleRuntimeApi, C::Api: module_staked_relayers_rpc::StakedRelayersRuntimeApi, - C::Api: module_vault_registry_rpc::VaultRegistryRuntimeApi, + C::Api: module_vault_registry_rpc::VaultRegistryRuntimeApi, + C::Api: module_issue_rpc::IssueRuntimeApi< + Block, + AccountId, + H256, + IssueRequest, + >, + C::Api: module_redeem_rpc::RedeemRuntimeApi< + Block, + AccountId, + H256, + RedeemRequest, + >, + C::Api: module_replace_rpc::ReplaceRuntimeApi< + Block, + AccountId, + H256, + ReplaceRequest, + >, C::Api: BlockBuilder, P: TransactionPool + 'static, { use module_exchange_rate_oracle_rpc::{ExchangeRateOracle, ExchangeRateOracleApi}; + use module_issue_rpc::{Issue, IssueApi}; + use module_redeem_rpc::{Redeem, RedeemApi}; + use module_replace_rpc::{Replace, ReplaceApi}; use module_staked_relayers_rpc::{StakedRelayers, StakedRelayersApi}; use module_vault_registry_rpc::{VaultRegistry, VaultRegistryApi}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; @@ -73,5 +98,11 @@ where client.clone(), ))); + io.extend_with(IssueApi::to_delegate(Issue::new(client.clone()))); + + io.extend_with(RedeemApi::to_delegate(Redeem::new(client.clone()))); + + io.extend_with(ReplaceApi::to_delegate(Replace::new(client.clone()))); + io } diff --git a/parachain/src/service.rs b/parachain/src/service.rs index 6dddf7b40f..3496f5b07e 100644 --- a/parachain/src/service.rs +++ b/parachain/src/service.rs @@ -18,6 +18,7 @@ native_executor_instance!( pub Executor, btc_parachain_runtime::api::dispatch, btc_parachain_runtime::native_version, + frame_benchmarking::benchmarking::HostFunctions, ); type FullClient = sc_service::TFullClient;