diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b474a0a3d..e491cf202 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,6 +42,8 @@ build: variables: DOCKER_HUB_PARACHAIN: "kiltprotocol/kilt-node" DOCKER_HUB_STANDALONE: "kiltprotocol/standalone-node" + DOCKER_HUB_DIP_PROVIDER_TEMPLATE: "kiltprotocol/dip-provider-node-template" + DOCKER_HUB_DIP_CONSUMER_TEMPLATE: "kiltprotocol/dip-consumer-node-template" before_script: - aws --version - docker --version diff --git a/.maintain/build-image.sh b/.maintain/build-image.sh index 222248273..b179b7928 100755 --- a/.maintain/build-image.sh +++ b/.maintain/build-image.sh @@ -22,3 +22,19 @@ docker build \ --build-arg NODE_TYPE=standalone-node \ -t local/standalone-node:$target_tag \ . + +# build DIP provider and consumer templates +PROVIDER_BIN_NAME="dip-provider-node-template" +docker build \ + --cache-from $AWS_REGISTRY/kilt-parachain/collator:builder \ + --cache-from $AWS_REGISTRY/$PROVIDER_BIN_NAME:$target_tag \ + --build-arg NODE_TYPE=$PROVIDER_BIN_NAME \ + -t local/$PROVIDER_BIN_NAME:$target_tag \ + . +CONSUMER_BIN_NAME="dip-consumer-node-template" +docker build \ + --cache-from $AWS_REGISTRY/kilt-parachain/collator:builder \ + --cache-from $AWS_REGISTRY/$CONSUMER_BIN_NAME:$target_tag \ + --build-arg NODE_TYPE=$CONSUMER_BIN_NAME \ + -t local/$CONSUMER_BIN_NAME:$target_tag \ + . diff --git a/.maintain/push-image.sh b/.maintain/push-image.sh index 4bb38e5e8..ba46da0ea 100755 --- a/.maintain/push-image.sh +++ b/.maintain/push-image.sh @@ -3,16 +3,27 @@ source_tag=$1 target_tag=$2 +PROVIDER_BIN_NAME="dip-provider-node-template" +CONSUMER_BIN_NAME="dip-consumer-node-template" + # publish to docker hub docker tag local/standalone-node:$source_tag ${DOCKER_HUB_STANDALONE}:$target_tag docker tag local/kilt-node:$source_tag ${DOCKER_HUB_PARACHAIN}:$target_tag +docker tag local/$PROVIDER_BIN_NAME:$source_tag ${DOCKER_HUB_DIP_PROVIDER_TEMPLATE}:$target_tag +docker tag local/$CONSUMER_BIN_NAME:$source_tag ${DOCKER_HUB_DIP_CONSUMER_TEMPLATE}:$target_tag docker push ${DOCKER_HUB_STANDALONE}:$target_tag docker push ${DOCKER_HUB_PARACHAIN}:$target_tag +docker push ${DOCKER_HUB_DIP_PROVIDER_TEMPLATE}:$target_tag +docker push ${DOCKER_HUB_DIP_CONSUMER_TEMPLATE}:$target_tag # publish to AWS docker tag local/standalone-node:$source_tag $AWS_REGISTRY/kilt/prototype-chain:$target_tag docker tag local/kilt-node:$source_tag $AWS_REGISTRY/kilt-parachain/collator:$target_tag +docker tag local/$PROVIDER_BIN_NAME:$source_tag $AWS_REGISTRY/$PROVIDER_BIN_NAME:$target_tag +docker tag local/$CONSUMER_BIN_NAME:$source_tag $AWS_REGISTRY/$CONSUMER_BIN_NAME:$target_tag docker push $AWS_REGISTRY/kilt/prototype-chain:$target_tag docker push $AWS_REGISTRY/kilt-parachain/collator:$target_tag +docker push $AWS_REGISTRY/$PROVIDER_BIN_NAME:$target_tag +docker push $AWS_REGISTRY/$CONSUMER_BIN_NAME:$target_tag diff --git a/Cargo.lock b/Cargo.lock index 9d87fcf32..d0dd8e894 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,25 +149,26 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -280,9 +281,9 @@ checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "array-bytes" -version = "6.1.0" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" +checksum = "de17a919934ad8c5cc99a1a74de4e2dab95d6121a8f27f94755ff525b630382c" [[package]] name = "arrayref" @@ -382,28 +383,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-io" -version = "1.13.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997" dependencies = [ - "async-lock", - "autocfg", + "async-lock 3.1.1", "cfg-if", "concurrent-queue", + "futures-io", "futures-lite", - "log", "parking", "polling", - "rustix 0.37.24", + "rustix 0.38.25", "slab", - "socket2 0.4.9", + "tracing", "waker-fn", + "windows-sys 0.48.0", ] [[package]] @@ -412,7 +413,18 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105" +dependencies = [ + "event-listener 3.1.0", + "event-listener-strategy", + "pin-project-lite 0.2.13", ] [[package]] @@ -423,18 +435,18 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -541,9 +553,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -596,7 +608,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -607,9 +619,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitvec" @@ -751,9 +763,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", "serde", @@ -826,9 +838,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" dependencies = [ "serde", ] @@ -900,25 +912,24 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher 0.4.4", "cpufeatures", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "aead 0.4.3", + "aead 0.5.2", "chacha20", - "cipher 0.3.0", + "cipher 0.4.4", "poly1305", "zeroize", ] @@ -976,6 +987,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1000,9 +1012,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" dependencies = [ "clap_builder", "clap_derive", @@ -1010,9 +1022,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" dependencies = [ "anstream", "anstyle", @@ -1022,27 +1034,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "coarsetime" -version = "0.1.29" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a73ef0d00d14301df35d0f13f5ea32344de6b00837485c358458f1e7f2d27db4" +checksum = "71367d3385c716342014ad17e3d19f7788ae514885a1f4c24f500260fb365e1a" dependencies = [ "libc", "once_cell", @@ -1068,12 +1080,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comfy-table" -version = "7.0.1" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b" +checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686" dependencies = [ - "strum", - "strum_macros", + "strum 0.25.0", + "strum_macros 0.25.3", "unicode-width", ] @@ -1113,23 +1125,21 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "const-random" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" dependencies = [ "const-random-macro", - "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", - "proc-macro-hack", "tiny-keccak", ] @@ -1191,9 +1201,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -1307,9 +1317,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -1383,9 +1393,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", @@ -1737,7 +1747,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2044,20 +2054,20 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "cxx" -version = "1.0.108" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292b4841d939b20ba44fff686a35808b0ab31a3256e3629917d9aedd43eb7b3a" +checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" dependencies = [ "cc", "cxxbridge-flags", @@ -2067,9 +2077,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.108" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7e35cf85fd4e90dcaba251f3ee95e08fb6f9d66e5c0588816f16a6ab939b40" +checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" dependencies = [ "cc", "codespan-reporting", @@ -2077,24 +2087,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "cxxbridge-flags" -version = "1.0.108" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7030aff1908ba2b7eb639466df50792b2a3fdf02bea9557c4ee1a531975554b" +checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" [[package]] name = "cxxbridge-macro" -version = "1.0.108" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79418ecb0c2322a7926a5fa5a9660535432b5b3588b947e1eb484cc509edbe3c" +checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2134,15 +2144,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "data-encoding-macro" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" +checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2150,9 +2160,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" +checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" dependencies = [ "data-encoding", "syn 1.0.109", @@ -2232,9 +2242,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] [[package]] name = "derivative" @@ -2307,7 +2320,7 @@ name = "did" version = "1.12.0-dev" dependencies = [ "ctype", - "env_logger 0.10.0", + "env_logger 0.10.1", "fluent-uri", "frame-benchmarking", "frame-support", @@ -2361,6 +2374,220 @@ dependencies = [ "subtle", ] +[[package]] +name = "dip-consumer-node-template" +version = "1.12.0-dev" +dependencies = [ + "clap", + "cumulus-client-cli", + "cumulus-client-consensus-aura", + "cumulus-client-consensus-common", + "cumulus-client-service", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-interface", + "dip-consumer-runtime-template", + "frame-benchmarking", + "frame-benchmarking-cli", + "futures", + "jsonrpsee", + "log", + "pallet-transaction-payment-rpc", + "parity-scale-codec", + "polkadot-cli", + "polkadot-primitives", + "sc-basic-authorship", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-executor", + "sc-network", + "sc-network-sync", + "sc-offchain", + "sc-rpc-api", + "sc-service", + "sc-sysinfo", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "sc-transaction-pool-api", + "serde", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-consensus-aura", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-timestamp", + "substrate-build-script-utils", + "substrate-frame-rpc-system", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "dip-consumer-runtime-template" +version = "1.12.0-dev" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "did", + "dip-provider-runtime-template", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "hex-literal 0.3.4", + "kilt-dip-primitives", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-did-lookup", + "pallet-dip-consumer", + "pallet-postit", + "pallet-relay-store", + "pallet-session", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "parachain-info", + "parity-scale-codec", + "polkadot-parachain", + "runtime-common", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "substrate-wasm-builder", +] + +[[package]] +name = "dip-provider-node-template" +version = "1.12.0-dev" +dependencies = [ + "clap", + "cumulus-client-cli", + "cumulus-client-consensus-aura", + "cumulus-client-consensus-common", + "cumulus-client-service", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-interface", + "dip-provider-runtime-template", + "frame-benchmarking", + "frame-benchmarking-cli", + "futures", + "jsonrpsee", + "log", + "pallet-transaction-payment-rpc", + "parity-scale-codec", + "polkadot-cli", + "polkadot-primitives", + "sc-basic-authorship", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-executor", + "sc-network", + "sc-network-sync", + "sc-offchain", + "sc-rpc-api", + "sc-service", + "sc-sysinfo", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "sc-transaction-pool-api", + "serde", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-consensus-aura", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-timestamp", + "substrate-build-script-utils", + "substrate-frame-rpc-system", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "dip-provider-runtime-template" +version = "1.12.0-dev" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "did", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "hex-literal 0.3.4", + "kilt-dip-primitives", + "kilt-runtime-api-did", + "kilt-runtime-api-dip-provider", + "kilt-support", + "log", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-deposit-storage", + "pallet-did-lookup", + "pallet-dip-provider", + "pallet-session", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "pallet-web3-names", + "parachain-info", + "parity-scale-codec", + "runtime-common", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "substrate-wasm-builder", +] + [[package]] name = "directories" version = "4.0.1" @@ -2410,7 +2637,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2434,7 +2661,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.38", + "syn 2.0.39", "termcolor", "walkdir", ] @@ -2474,9 +2701,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "ecdsa" @@ -2492,15 +2719,15 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der 0.7.8", "digest 0.10.7", - "elliptic-curve 0.13.6", + "elliptic-curve 0.13.8", "rfc6979 0.4.0", - "signature 2.1.0", + "signature 2.2.0", "spki 0.7.2", ] @@ -2515,12 +2742,12 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8 0.10.2", - "signature 2.1.0", + "signature 2.2.0", ] [[package]] @@ -2537,15 +2764,16 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek 4.1.1", - "ed25519 2.2.2", + "ed25519 2.2.3", "rand_core 0.6.4", "serde", "sha2 0.10.8", + "subtle", "zeroize", ] @@ -2593,12 +2821,12 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.6" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct 0.2.0", - "crypto-bigint 0.5.3", + "crypto-bigint 0.5.5", "digest 0.10.7", "ff 0.13.0", "generic-array 0.14.7", @@ -2645,7 +2873,7 @@ checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2656,7 +2884,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2674,9 +2902,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -2699,9 +2927,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys 0.48.0", @@ -2713,6 +2941,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.13", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener 3.1.0", + "pin-project-lite 0.2.13", +] + [[package]] name = "exit-future" version = "0.2.0" @@ -2756,7 +3005,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2771,15 +3020,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.0.1" @@ -2842,9 +3082,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" [[package]] name = "file-per-thread-logger" @@ -2852,7 +3092,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.10.0", + "env_logger 0.10.1", "log", ] @@ -2904,9 +3144,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "libz-sys", @@ -3041,7 +3281,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3160,7 +3400,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3172,7 +3412,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3182,7 +3422,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948 dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3242,9 +3482,12 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "fs2" @@ -3262,7 +3505,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" dependencies = [ - "rustix 0.38.18", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -3274,9 +3517,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -3289,9 +3532,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -3299,15 +3542,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -3317,34 +3560,29 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-lite" -version = "1.13.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" dependencies = [ - "fastrand 1.9.0", "futures-core", - "futures-io", - "memchr", - "parking", "pin-project-lite 0.2.13", - "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3360,15 +3598,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-timer" @@ -3378,9 +3616,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -3446,9 +3684,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -3535,9 +3773,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -3545,7 +3783,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -3554,9 +3792,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683" +checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" dependencies = [ "log", "pest", @@ -3587,7 +3825,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", ] [[package]] @@ -3596,14 +3834,14 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", ] [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" @@ -3715,9 +3953,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -3776,7 +4014,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite 0.2.13", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -3785,33 +4023,33 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", "hyper", "log", - "rustls 0.21.7", + "rustls 0.21.9", "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots 0.23.1", + "webpki-roots 0.25.2", ] [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows-core", ] [[package]] @@ -3852,19 +4090,19 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "if-watch" -version = "3.0.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9465340214b296cd17a0009acdb890d6160010b8adf8f78a00d0d7ab270f79f" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ "async-io", "core-foundation", @@ -3876,7 +4114,7 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows 0.34.0", + "windows", ] [[package]] @@ -3921,12 +4159,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] @@ -4017,7 +4255,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.4", + "socket2 0.5.5", "widestring", "windows-sys 0.48.0", "winreg", @@ -4025,9 +4263,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -4036,7 +4274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.3", - "rustix 0.38.18", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -4075,9 +4313,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -4126,7 +4364,7 @@ checksum = "2b5dde66c53d6dcdc8caea1874a45632ec0fcf5b437789f1e45766a1512ce803" dependencies = [ "anyhow", "arrayvec 0.7.4", - "async-lock", + "async-lock 2.8.0", "async-trait", "beef", "futures-channel", @@ -4228,13 +4466,13 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" dependencies = [ "cfg-if", - "ecdsa 0.16.8", - "elliptic-curve 0.13.6", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "once_cell", "sha2 0.10.8", ] @@ -4316,6 +4554,39 @@ dependencies = [ "sp-std", ] +[[package]] +name = "kilt-dip-primitives" +version = "1.12.0-dev" +dependencies = [ + "cfg-if", + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "did", + "frame-support", + "frame-system", + "hash-db", + "hex-literal 0.3.4", + "kilt-support", + "log", + "pallet-did-lookup", + "pallet-dip-consumer", + "pallet-dip-provider", + "pallet-relay-store", + "pallet-web3-names", + "parachain-info", + "parity-scale-codec", + "rococo-runtime", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "xcm", + "xcm-executor", +] + [[package]] name = "kilt-parachain" version = "1.12.0-dev" @@ -4392,6 +4663,14 @@ dependencies = [ "sp-std", ] +[[package]] +name = "kilt-runtime-api-dip-provider" +version = "1.12.0-dev" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + [[package]] name = "kilt-runtime-api-public-credentials" version = "1.12.0-dev" @@ -4600,9 +4879,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" @@ -4623,7 +4902,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.10", + "getrandom 0.2.11", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -4743,7 +5022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "276bb57e7af15d8f100d3c11cbdd32c6752b7eef4ba7a18ecf464972c07abcce" dependencies = [ "bs58", - "ed25519-dalek 2.0.0", + "ed25519-dalek 2.1.0", "log", "multiaddr", "multihash", @@ -4797,7 +5076,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "trust-dns-proto", "void", @@ -4939,7 +5218,7 @@ dependencies = [ "libc", "libp2p-core", "log", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", ] @@ -5039,6 +5318,17 @@ dependencies = [ "yamux", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -5154,21 +5444,15 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -5245,7 +5529,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5259,7 +5543,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5270,7 +5554,7 @@ checksum = "d710e1214dffbab3b5dacb21475dde7d6ed84c69ff722b3a47a782668d44fbac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5281,7 +5565,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5343,7 +5627,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.18", + "rustix 0.38.25", ] [[package]] @@ -5431,9 +5715,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -6113,6 +6397,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-collator-selection" +version = "3.0.0" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v1.0.0#0d17cf6bef320f156f2859d6d2b0abd4154ae1d5" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-runtime", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-collective" version = "4.0.0-dev" @@ -6184,13 +6487,32 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-deposit-storage" +version = "1.12.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "kilt-support", + "log", + "pallet-balances", + "pallet-dip-provider", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-did-lookup" version = "1.12.0-dev" dependencies = [ "base58", "blake2", - "env_logger 0.10.0", + "env_logger 0.10.1", "frame-benchmarking", "frame-support", "frame-system", @@ -6211,6 +6533,42 @@ dependencies = [ "test-log", ] +[[package]] +name = "pallet-dip-consumer" +version = "1.12.0-dev" +dependencies = [ + "cfg-if", + "frame-benchmarking", + "frame-support", + "frame-system", + "kilt-support", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-dip-provider" +version = "1.12.0-dev" +dependencies = [ + "did", + "frame-benchmarking", + "frame-support", + "frame-system", + "kilt-support", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" @@ -6231,7 +6589,7 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-std", - "strum", + "strum 0.24.1", ] [[package]] @@ -6421,7 +6779,7 @@ dependencies = [ "ctype", "delegation", "did", - "env_logger 0.10.0", + "env_logger 0.10.1", "frame-benchmarking", "frame-support", "frame-system", @@ -6583,6 +6941,18 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-postit" +version = "1.12.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-preimage" version = "4.0.0-dev" @@ -6667,6 +7037,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-relay-store" +version = "1.12.0-dev" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" @@ -6771,7 +7160,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -7069,9 +7458,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab512a34b3c2c5e465731cc7668edf79208bbe520be03484eeb05e63ed221735" +checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" dependencies = [ "blake2", "crc32fast", @@ -7128,9 +7517,9 @@ checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" @@ -7150,7 +7539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] @@ -7169,13 +7558,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] @@ -7266,6 +7655,7 @@ dependencies = [ "frame-try-runtime", "hex-literal 0.3.4", "kilt-runtime-api-did", + "kilt-runtime-api-dip-provider", "kilt-runtime-api-public-credentials", "kilt-runtime-api-staking", "kilt-support", @@ -7276,7 +7666,9 @@ dependencies = [ "pallet-collective", "pallet-configuration", "pallet-democracy", + "pallet-deposit-storage", "pallet-did-lookup", + "pallet-dip-provider", "pallet-indices", "pallet-inflation", "pallet-membership", @@ -7323,9 +7715,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -7334,9 +7726,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -7344,22 +7736,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -7373,7 +7765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] @@ -7393,7 +7785,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -7442,9 +7834,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "polkadot-approval-distribution" @@ -8061,7 +8453,7 @@ dependencies = [ "rand 0.8.5", "sc-authority-discovery", "sc-network", - "strum", + "strum 0.24.1", "thiserror", "tracing-gum", ] @@ -8634,29 +9026,27 @@ dependencies = [ [[package]] name = "polling" -version = "2.8.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" dependencies = [ - "autocfg", - "bitflags 1.3.2", "cfg-if", "concurrent-queue", - "libc", - "log", "pin-project-lite 0.2.13", + "rustix 0.38.25", + "tracing", "windows-sys 0.48.0", ] [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash 0.4.1", + "universal-hash 0.5.1", ] [[package]] @@ -8685,9 +9075,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.4.3" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -8742,7 +9138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8808,12 +9204,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro-warning" version = "0.4.2" @@ -8822,7 +9212,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8868,7 +9258,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9085,7 +9475,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -9175,14 +9565,23 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", + "getrandom 0.2.11", + "libredox", "thiserror", ] @@ -9216,7 +9615,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9233,14 +9632,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.1", - "regex-syntax 0.8.0", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -9254,13 +9653,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.0", + "regex-syntax 0.8.2", ] [[package]] @@ -9271,9 +9670,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3cbb081b9784b07cceb8824c8583f86db4814d172ab043f3c23f7dc600bf83d" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "resolv-conf" @@ -9323,12 +9722,12 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.3" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", - "getrandom 0.2.10", + "getrandom 0.2.11", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -9448,13 +9847,13 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -9485,12 +9884,12 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -9516,18 +9915,24 @@ dependencies = [ "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", + "did", + "frame-benchmarking", "frame-support", "frame-system", "kilt-asset-dids", + "kilt-dip-primitives", "kilt-support", "log", "pallet-authorship", "pallet-balances", + "pallet-did-lookup", + "pallet-dip-provider", "pallet-membership", "pallet-multisig", "pallet-tips", "pallet-transaction-payment", "pallet-treasury", + "pallet-web3-names", "parachain-staking", "parity-scale-codec", "polkadot-parachain", @@ -9539,6 +9944,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "sp-trie", "xcm", "xcm-builder", "xcm-executor", @@ -9582,9 +9988,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.15" +version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ "bitflags 1.3.2", "errno", @@ -9596,28 +10002,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.18" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a74ee2d7c2581cd139b42447d7d9389b889bdaad3a73f1ebb16f2a3237bb19c" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.10", + "linux-raw-sys 0.4.11", "windows-sys 0.48.0", ] @@ -9642,20 +10034,20 @@ checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", "ring 0.16.20", - "sct 0.7.0", + "sct 0.7.1", "webpki 0.22.4", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", - "ring 0.16.20", - "rustls-webpki 0.101.6", - "sct 0.7.0", + "ring 0.17.5", + "rustls-webpki", + "sct 0.7.1", ] [[package]] @@ -9672,31 +10064,21 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" -dependencies = [ - "base64 0.21.4", -] - -[[package]] -name = "rustls-webpki" -version = "0.100.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -9844,7 +10226,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -10121,7 +10503,7 @@ name = "sc-consensus-grandpa" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "array-bytes", "async-trait", "dyn-clone", @@ -10243,7 +10625,7 @@ dependencies = [ "cfg-if", "libc", "log", - "rustix 0.36.15", + "rustix 0.36.17", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -10364,7 +10746,7 @@ name = "sc-network-gossip" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "futures", "futures-timer", "libp2p", @@ -10767,7 +11149,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -10829,9 +11211,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ "bitvec", "cfg-if", @@ -10843,9 +11225,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10868,7 +11250,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "cfg-if", "hashbrown 0.13.2", ] @@ -10915,12 +11297,12 @@ dependencies = [ [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -11039,29 +11421,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -11070,9 +11452,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -11183,9 +11565,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -11248,9 +11630,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "snap" @@ -11260,16 +11642,16 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" +checksum = "58021967fd0a5eeeb23b08df6cc244a4d4a5b4aec1d27c9e02fad1a58b4cd74e" dependencies = [ - "aes-gcm 0.9.4", + "aes-gcm 0.10.3", "blake2", "chacha20poly1305", "curve25519-dalek 4.1.1", "rand_core 0.6.4", - "ring 0.16.20", + "ring 0.17.5", "rustc_version", "sha2 0.10.8", "subtle", @@ -11277,9 +11659,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -11287,9 +11669,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", @@ -11344,7 +11726,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -11483,7 +11865,7 @@ dependencies = [ "sp-mmr-primitives", "sp-runtime", "sp-std", - "strum", + "strum 0.24.1", ] [[package]] @@ -11581,7 +11963,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948 dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -11600,7 +11982,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948 dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -11661,7 +12043,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum", + "strum 0.24.1", ] [[package]] @@ -11807,7 +12189,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -11949,7 +12331,7 @@ name = "sp-trie" version = "22.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "hash-db", "hashbrown 0.13.2", "lazy_static", @@ -11992,7 +12374,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -12037,13 +12419,13 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spinners" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08615eea740067d9899969bc2891c68a19c315cb1f66640af9a9ecb91b13bcab" +checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" dependencies = [ "lazy_static", "maplit", - "strum", + "strum 0.24.1", ] [[package]] @@ -12147,9 +12529,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.43.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" +checksum = "35935738370302d5e33963665b77541e4b990a3e919ec904c837a56cfc891de1" dependencies = [ "Inflector", "num-format", @@ -12258,9 +12640,15 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", ] +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + [[package]] name = "strum_macros" version = "0.24.3" @@ -12274,6 +12662,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.39", +] + [[package]] name = "stun" version = "0.4.4" @@ -12295,9 +12696,9 @@ dependencies = [ [[package]] name = "substrate-bip39" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +checksum = "e620c7098893ba667438b47169c00aacdd9e7c10e042250ce2b60b087ec97328" dependencies = [ "hmac 0.11.0", "pbkdf2 0.8.0", @@ -12383,7 +12784,7 @@ dependencies = [ "filetime", "parity-wasm", "sp-maybe-compressed-blob", - "strum", + "strum 0.24.1", "tempfile", "toml 0.7.8", "walkdir", @@ -12418,9 +12819,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -12468,28 +12869,28 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.18", + "fastrand", + "redox_syscall 0.4.1", + "rustix 0.38.25", "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -12502,33 +12903,33 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test-log" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9601d162c1d77e62c1ea0bc8116cd1caf143ce3af947536c3c9052a1677fe0c" +checksum = "f66edd6b6cd810743c0c71e1d085e92b01ce6a72782032e3f794c8284fe4bcdd" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -12592,12 +12993,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", "itoa", + "powerfmt", "serde", "time-core", "time-macros", @@ -12673,9 +13075,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -12685,20 +13087,20 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite 0.2.13", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -12718,7 +13120,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.7", + "rustls 0.21.9", "tokio", ] @@ -12736,9 +13138,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -12772,9 +13174,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -12785,7 +13187,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -12809,7 +13211,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "bytes", "futures-core", "futures-util", @@ -12835,11 +13237,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite 0.2.13", "tracing-attributes", @@ -12848,20 +13249,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -12897,17 +13298,17 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -12984,7 +13385,7 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec", - "socket2 0.4.9", + "socket2 0.4.10", "thiserror", "tinyvec", "tokio", @@ -13211,11 +13612,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.4.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -13290,9 +13691,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -13300,24 +13701,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -13327,9 +13728,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -13337,22 +13738,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-instrument" @@ -13371,8 +13772,8 @@ checksum = "87fef6d0d508f08334e0ab0e6877feb4c0ecb3956bcf2cb950699b22fedf3e9c" dependencies = [ "anyhow", "libc", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "tempfile", "thiserror", "wasm-opt-cxx-sys", @@ -13472,12 +13873,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.4", + "base64 0.21.5", "bincode", "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.15", + "rustix 0.36.17", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -13573,7 +13974,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.15", + "rustix 0.36.17", ] [[package]] @@ -13604,7 +14005,7 @@ dependencies = [ "memoffset 0.8.0", "paste", "rand 0.8.5", - "rustix 0.36.15", + "rustix 0.36.17", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -13625,9 +14026,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -13649,7 +14050,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.3", + "ring 0.17.5", "untrusted 0.9.0", ] @@ -13662,15 +14063,6 @@ dependencies = [ "webpki 0.22.4", ] -[[package]] -name = "webpki-roots" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.3", -] - [[package]] name = "webpki-roots" version = "0.25.2" @@ -13804,7 +14196,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" dependencies = [ "log", - "socket2 0.4.9", + "socket2 0.4.10", "thiserror", "tokio", "webrtc-util", @@ -14001,14 +14393,14 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.18", + "rustix 0.38.25", ] [[package]] name = "wide" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebecebefc38ff1860b4bc47550bbfa63af5746061cf0d29fcd7fa63171602598" +checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242" dependencies = [ "bytemuck", "safe_arch", @@ -14053,22 +14445,19 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.34.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows_aarch64_msvc 0.34.0", - "windows_i686_gnu 0.34.0", - "windows_i686_msvc 0.34.0", - "windows_x86_64_gnu 0.34.0", - "windows_x86_64_msvc 0.34.0", + "windows-core", + "windows-targets 0.48.5", ] [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ "windows-targets 0.48.5", ] @@ -14133,12 +14522,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" -[[package]] -name = "windows_aarch64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -14151,12 +14534,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_i686_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -14169,12 +14546,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" -[[package]] -name = "windows_i686_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -14187,12 +14558,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_x86_64_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -14217,12 +14582,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" -[[package]] -name = "windows_x86_64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -14237,9 +14596,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.16" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -14389,7 +14748,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -14415,11 +14774,31 @@ dependencies = [ "time", ] +[[package]] +name = "zerocopy" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -14432,7 +14811,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -14475,11 +14854,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.9+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index c42eedb08..402d2dea5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,9 @@ version = "1.12.0-dev" [workspace] members = [ "crates/*", + "dip-template/nodes/*", + "dip-template/pallets/*", + "dip-template/runtimes/*", "nodes/*", "pallets/*", "runtime-api/*", @@ -29,10 +32,12 @@ substrate-wasm-builder = {git = "https://github.com/paritytech/substrate", branc # External (without extra features and with default disabled if necessary) base58 = {version = "0.2.0", default-features = false} bitflags = {version = "1.3.2", default-features = false} +cfg-if = "1.0" clap = "4.1.6" env_logger = "0.10.0" fluent-uri = { version = "0.1.4", default-features = false } futures = {version = "0.3.21", default-features = false} +hash-db = { version = "0.16.0", default-features = false } hex = {version = "0.4.0", default-features = false} hex-literal = "0.3.4" jsonrpsee = "0.16.2" @@ -51,8 +56,12 @@ ctype = {path = "pallets/ctype", default-features = false} delegation = {path = "pallets/delegation", default-features = false} did = {path = "pallets/did", default-features = false} pallet-configuration = {path = "pallets/pallet-configuration", default-features = false} +pallet-deposit-storage = {path = "pallets/pallet-deposit-storage", default-features = false} +pallet-dip-consumer = {path = "pallets/pallet-dip-consumer", default-features = false} +pallet-dip-provider = {path = "pallets/pallet-dip-provider", default-features = false} pallet-did-lookup = {path = "pallets/pallet-did-lookup", default-features = false} pallet-inflation = {path = "pallets/pallet-inflation", default-features = false} +pallet-relay-store = {path = "pallets/pallet-relay-store", default-features = false} pallet-web3-names = {path = "pallets/pallet-web3-names", default-features = false} parachain-staking = {path = "pallets/parachain-staking", default-features = false} public-credentials = {path = "pallets/public-credentials", default-features = false} @@ -60,11 +69,18 @@ pallet-migration = {path = "pallets/pallet-migration", default-features = false} # Internal support (with default disabled) kilt-asset-dids = {path = "crates/assets", default-features = false} +kilt-dip-primitives = {path = "crates/kilt-dip-primitives", default-features = false} kilt-support = {path = "support", default-features = false} runtime-common = {path = "runtimes/common", default-features = false} +# Templates +dip-consumer-runtime-template = {path = "dip-template/runtimes/dip-consumer", default-features = false} +dip-provider-runtime-template = {path = "dip-template/runtimes/dip-provider", default-features = false} +pallet-postit = {path = "dip-template/pallets/pallet-postit", default-features = false} + # Internal runtime API (with default disabled) kilt-runtime-api-did = {path = "runtime-api/did", default-features = false} +kilt-runtime-api-dip-provider = {path = "runtime-api/dip-provider", default-features = false} kilt-runtime-api-public-credentials = {path = "runtime-api/public-credentials", default-features = false} kilt-runtime-api-staking = {path = "runtime-api/staking", default-features = false} @@ -128,8 +144,10 @@ sp-offchain = {git = "https://github.com/paritytech/substrate", default-features sp-runtime = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} sp-session = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} sp-staking = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} +sp-state-machine = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} sp-std = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} sp-transaction-pool = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} +sp-trie = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} sp-version = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} sp-weights = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} try-runtime-cli = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v1.0.0"} @@ -137,6 +155,7 @@ try-runtime-cli = {git = "https://github.com/paritytech/substrate", default-feat # Polkadot (with default disabled) pallet-xcm = {git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v1.0.0"} polkadot-parachain = {git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v1.0.0"} +rococo-runtime = {git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v1.0.0"} xcm = {git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v1.0.0"} xcm-builder = {git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v1.0.0"} xcm-executor = {git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v1.0.0"} diff --git a/crates/kilt-dip-primitives/Cargo.toml b/crates/kilt-dip-primitives/Cargo.toml new file mode 100644 index 000000000..2afec4987 --- /dev/null +++ b/crates/kilt-dip-primitives/Cargo.toml @@ -0,0 +1,90 @@ +[package] +authors.workspace = true +description = "Primitive types, traits, and functions for the KILT Decentralized Identity Provider (DIP) functionality as implemented by the KILT blockchain." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "kilt-dip-primitives" +readme.workspace = true +repository.workspace = true +version.workspace = true + +[dependencies] +# External dependencies +hash-db.workspace = true +log.workspace = true +cfg-if.workspace = true + +# Internal dependencies +did.workspace = true +kilt-support = {workspace = true, optional = true} +pallet-did-lookup.workspace = true +pallet-dip-consumer.workspace = true +pallet-dip-provider.workspace = true +pallet-relay-store.workspace = true +pallet-web3-names.workspace = true + +# Parity dependencies +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} + +# Substrate dependencies +frame-system.workspace = true +frame-support.workspace = true +sp-core.workspace = true +sp-io.workspace = true +sp-runtime.workspace = true +sp-state-machine.workspace = true +sp-std.workspace = true +sp-trie.workspace = true + +# Polkadot dependencies +rococo-runtime.workspace = true +xcm.workspace = true +xcm-executor.workspace = true + +# Cumulus dependencies +cumulus-pallet-parachain-system.workspace = true +cumulus-primitives-core.workspace = true +parachain-info.workspace = true + +[dev-dependencies] +hex-literal.workspace = true +sp-io = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "hash-db/std", + "log/std", + "did/std", + "kilt-support?/std", + "pallet-did-lookup/std", + "pallet-dip-consumer/std", + "pallet-dip-provider/std", + "pallet-relay-store/std", + "pallet-web3-names/std", + "parity-scale-codec/std", + "scale-info/std", + "frame-system/std", + "frame-support/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-state-machine/std", + "sp-std/std", + "sp-trie/std", + "rococo-runtime/std", + "xcm/std", + "xcm-executor/std", + "cumulus-pallet-parachain-system/std", + "cumulus-primitives-core/std", + "parachain-info/std", +] +runtime-benchmarks = [ + "kilt-support/runtime-benchmarks", + "pallet-dip-consumer/runtime-benchmarks", + "pallet-dip-provider/runtime-benchmarks", + "rococo-runtime/runtime-benchmarks" +] diff --git a/crates/kilt-dip-primitives/src/did.rs b/crates/kilt-dip-primitives/src/did.rs new file mode 100644 index 000000000..683e95228 --- /dev/null +++ b/crates/kilt-dip-primitives/src/did.rs @@ -0,0 +1,223 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Module to deal with cross-chain KILT DIDs. + +use did::{ + did_details::{DidPublicKey, DidPublicKeyDetails, DidVerificationKey}, + DidSignature, DidVerificationKeyRelationship, +}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; +use sp_runtime::traits::CheckedSub; +use sp_std::vec::Vec; + +use crate::{ + merkle::RevealedDidKey, + traits::{DidSignatureVerifierContext, DipCallOriginFilter, Incrementable}, +}; + +/// Type returned by the Merkle proof verifier component of the DIP consumer +/// after verifying a DIP Merkle proof. +#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)] +pub(crate) struct RevealedDidKeysAndSignature { + /// The keys revelaed in the Merkle proof. + pub merkle_leaves: RevealedDidKeys, + /// The [`DIDSignature`] + consumer chain block number to which the DID + /// signature is anchored. + pub did_signature: TimeBoundDidSignature, +} + +/// A DID signature anchored to a specific block height. +#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)] +pub struct TimeBoundDidSignature { + /// The signature. + pub signature: DidSignature, + /// The block number, in the context of the local executor, to which the + /// signature is anchored. + pub block_number: BlockNumber, +} + +#[cfg(feature = "runtime-benchmarks")] +impl kilt_support::traits::GetWorstCase for TimeBoundDidSignature +where + DidSignature: kilt_support::traits::GetWorstCase, + BlockNumber: Default, +{ + fn worst_case(context: Context) -> Self { + Self { + signature: DidSignature::worst_case(context), + block_number: BlockNumber::default(), + } + } +} + +pub enum RevealedDidKeysSignatureAndCallVerifierError { + SignatureNotFresh, + SignatureUnverifiable, + OriginCheckFailed, + Internal, +} + +impl From for u8 { + fn from(value: RevealedDidKeysSignatureAndCallVerifierError) -> Self { + match value { + RevealedDidKeysSignatureAndCallVerifierError::SignatureNotFresh => 0, + RevealedDidKeysSignatureAndCallVerifierError::SignatureUnverifiable => 1, + RevealedDidKeysSignatureAndCallVerifierError::OriginCheckFailed => 2, + RevealedDidKeysSignatureAndCallVerifierError::Internal => u8::MAX, + } + } +} + +/// Function that tries to verify a DID signature over a given payload by +/// using one of the DID keys revealed in the Merkle proof. This verifier is +/// typically used in conjunction with a verifier that takes a user-provided +/// input Merkle proof, verifies it, and transforms it into a struct that this +/// and other verifiers can easily consume, e.g., a list of DID keys. +/// The generic types are the following: +/// * `Call`: The call to be dispatched on the local chain after verifying the +/// DID signature. +/// * `Submitter`: The blockchain account (**not** the identity subject) +/// submitting the cross-chain transaction (and paying for its execution +/// fees). +/// * `DidLocalDetails`: Any information associated to the identity subject that +/// is stored locally, e.g., under the `IdentityEntries` map of the +/// `pallet-dip-consumer` pallet. +/// * `MerkleProofEntries`: The type returned by the Merkle proof verifier that +/// includes the identity parts revealed in the Merkle proof. +/// * `ContextProvider`: Provides additional local context (e.g., current block +/// number) to verify the DID signature. +/// * `RemoteKeyId`: Definition of a DID key ID as specified by the provider. +/// * `RemoteAccountId`: Definition of a linked account ID as specified by the +/// provider. +/// * `RemoteBlockNumber`: Definition of a block number on the provider chain. +/// * `CallVerifier`: A type specifying whether the provided `Call` can be +/// dispatched with the information provided in the DIP proof. +pub(crate) fn verify_did_signature_for_call< + Call, + Submitter, + DidLocalDetails, + MerkleProofEntries, + ContextProvider, + RemoteKeyId, + RemoteAccountId, + RemoteBlockNumber, + CallVerifier, +>( + call: &Call, + submitter: &Submitter, + local_details: &mut Option, + merkle_revealed_did_signature: RevealedDidKeysAndSignature, +) -> Result< + (DidVerificationKey, DidVerificationKeyRelationship), + RevealedDidKeysSignatureAndCallVerifierError, +> +where + Call: Encode, + Submitter: Encode, + ContextProvider: DidSignatureVerifierContext, + ContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, + ContextProvider::Hash: Encode, + ContextProvider::SignedExtra: Encode, + DidLocalDetails: Incrementable + Default + Encode, + RemoteAccountId: Clone, + MerkleProofEntries: sp_std::borrow::Borrow<[RevealedDidKey]>, + CallVerifier: + DipCallOriginFilter, DidVerificationKeyRelationship)>, +{ + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + {} + } else { + let block_number = ContextProvider::current_block_number(); + let is_signature_fresh = if let Some(blocks_ago_from_now) = + block_number.checked_sub(&merkle_revealed_did_signature.did_signature.block_number) + { + // False if the signature is too old. + blocks_ago_from_now <= ContextProvider::SIGNATURE_VALIDITY.into() + } else { + // Signature generated at a future time, not possible to verify. + false + }; + frame_support::ensure!( + is_signature_fresh, + RevealedDidKeysSignatureAndCallVerifierError::SignatureNotFresh, + ); + } + } + let encoded_payload = ( + call, + &local_details, + submitter, + &merkle_revealed_did_signature.did_signature.block_number, + ContextProvider::genesis_hash(), + ContextProvider::signed_extra(), + ) + .encode(); + // Only consider verification keys from the set of revealed keys. + let proof_verification_keys: Vec<(DidVerificationKey, DidVerificationKeyRelationship)> = merkle_revealed_did_signature.merkle_leaves.borrow().iter().filter_map(|RevealedDidKey { + relationship, details: DidPublicKeyDetails { key, .. }, .. } | { + let DidPublicKey::PublicVerificationKey(key) = key else { return None }; + if let Ok(vr) = DidVerificationKeyRelationship::try_from(*relationship) { + // TODO: Fix this logic to avoid cloning + Some(Ok((key.clone(), vr))) + } else { + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + None + } else { + log::error!("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."); + Some(Err(RevealedDidKeysSignatureAndCallVerifierError::Internal)) + } + } + } + }).collect::>()?; + let valid_signing_key = proof_verification_keys.iter().find(|(verification_key, _)| { + verification_key + .verify_signature(&encoded_payload, &merkle_revealed_did_signature.did_signature.signature) + .is_ok() + }); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + let default = ( + DidVerificationKey::Ed25519(sp_core::ed25519::Public::from_raw([0u8; 32])), + DidVerificationKeyRelationship::Authentication, + ); + let (key, relationship) = valid_signing_key.unwrap_or(&default); + } else { + let (key, relationship) = valid_signing_key.ok_or(RevealedDidKeysSignatureAndCallVerifierError::SignatureUnverifiable)?; + } + } + + if let Some(details) = local_details { + details.increment(); + } else { + *local_details = Some(DidLocalDetails::default()); + }; + let res = CallVerifier::check_call_origin_info(call, &(key.clone(), *relationship)); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| RevealedDidKeysSignatureAndCallVerifierError::OriginCheckFailed)?; + } + } + Ok((key.clone(), *relationship)) +} diff --git a/crates/kilt-dip-primitives/src/lib.rs b/crates/kilt-dip-primitives/src/lib.rs new file mode 100644 index 000000000..f8abdd6aa --- /dev/null +++ b/crates/kilt-dip-primitives/src/lib.rs @@ -0,0 +1,39 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Collection of support traits, types, and functions for integrating KILT as +//! an identity provider following the Decentralized Identity Provider (DIP) +//! protocol. +//! +//! Consumers of KILT identities should prefer directly using +//! [`KiltVersionedRelaychainVerifier`] for consumer relaychains and +//! [`KiltVersionedParachainVerifier`] for consumer sibling parachains. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod did; +pub mod merkle; +pub mod state_proofs; +pub mod traits; +pub mod utils; +pub mod verifier; + +pub use state_proofs::relaychain::RelayStateRootsViaRelayStorePallet; +pub use traits::{FrameSystemDidSignatureContext, ProviderParachainStateInfoViaProviderPallet}; +pub use utils::BoundedBlindedValue; +pub use verifier::*; diff --git a/crates/kilt-dip-primitives/src/merkle.rs b/crates/kilt-dip-primitives/src/merkle.rs new file mode 100644 index 000000000..6d744777f --- /dev/null +++ b/crates/kilt-dip-primitives/src/merkle.rs @@ -0,0 +1,416 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Module to deal with cross-chain Merkle proof as generated by the KILT chain. + +use did::{did_details::DidPublicKeyDetails, DidVerificationKeyRelationship}; +use frame_support::{traits::ConstU32, DefaultNoBound, RuntimeDebug}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::{BoundedVec, SaturatedConversion}; +use sp_std::{fmt::Debug, vec::Vec}; +use sp_trie::{verify_trie_proof, LayoutV1}; + +/// Type of a Merkle proof containing DID-related information. +#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, Default, TypeInfo)] +pub struct DidMerkleProof { + pub blinded: BlindedValues, + // TODO: Probably replace with a different data structure for better lookup capabilities + pub revealed: Vec, +} + +#[cfg(feature = "runtime-benchmarks")] +impl kilt_support::traits::GetWorstCase for DidMerkleProof +where + BlindedValues: kilt_support::traits::GetWorstCase, + Leaf: Default + Clone, +{ + fn worst_case(context: Context) -> Self { + Self { + blinded: BlindedValues::worst_case(context), + revealed: sp_std::vec![Leaf::default(); 64], + } + } +} + +/// Relationship of a key to a DID Document. +#[derive(Clone, Copy, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, PartialOrd, Ord, MaxEncodedLen)] +pub enum DidKeyRelationship { + Encryption, + Verification(DidVerificationKeyRelationship), +} + +impl From for DidKeyRelationship { + fn from(value: DidVerificationKeyRelationship) -> Self { + Self::Verification(value) + } +} + +impl TryFrom for DidVerificationKeyRelationship { + type Error = (); + + fn try_from(value: DidKeyRelationship) -> Result { + if let DidKeyRelationship::Verification(rel) = value { + Ok(rel) + } else { + Err(()) + } + } +} + +/// The key of a Merkle leaf revealing a DID key for a DID Document. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct DidKeyMerkleKey(pub KeyId, pub DidKeyRelationship); + +impl From<(KeyId, DidKeyRelationship)> for DidKeyMerkleKey { + fn from(value: (KeyId, DidKeyRelationship)) -> Self { + Self(value.0, value.1) + } +} +/// The value of a Merkle leaf revealing a DID key for a DID Document. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct DidKeyMerkleValue(pub DidPublicKeyDetails); + +impl From> + for DidKeyMerkleValue +{ + fn from(value: DidPublicKeyDetails) -> Self { + Self(value) + } +} + +/// The key of a Merkle leaf revealing the web3name linked to a DID Document. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct Web3NameMerkleKey(pub Web3Name); + +impl From for Web3NameMerkleKey { + fn from(value: Web3Name) -> Self { + Self(value) + } +} +/// The value of a Merkle leaf revealing the web3name linked to a DID Document. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct Web3NameMerkleValue(pub BlockNumber); + +impl From for Web3NameMerkleValue { + fn from(value: BlockNumber) -> Self { + Self(value) + } +} + +/// The key of a Merkle leaf revealing an account linked to a DID Document. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct LinkedAccountMerkleKey(pub AccountId); + +impl From for LinkedAccountMerkleKey { + fn from(value: AccountId) -> Self { + Self(value) + } +} +/// The value of a Merkle leaf revealing an account linked to a DID +/// Document. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct LinkedAccountMerkleValue; + +impl From<()> for LinkedAccountMerkleValue { + fn from(_value: ()) -> Self { + Self + } +} + +/// All possible Merkle leaf types that can be revealed as part of a DIP +/// identity Merkle proof. +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub enum RevealedDidMerkleProofLeaf { + DidKey(DidKeyMerkleKey, DidKeyMerkleValue), + Web3Name(Web3NameMerkleKey, Web3NameMerkleValue), + LinkedAccount(LinkedAccountMerkleKey, LinkedAccountMerkleValue), +} + +#[cfg(feature = "runtime-benchmarks")] +impl Default + for RevealedDidMerkleProofLeaf +where + KeyId: Default, + BlockNumber: Default, +{ + fn default() -> Self { + Self::DidKey( + (KeyId::default(), DidVerificationKeyRelationship::Authentication.into()).into(), + DidPublicKeyDetails { + key: did::did_details::DidVerificationKey::Ed25519(sp_core::ed25519::Public::from_raw([0u8; 32])) + .into(), + block_number: BlockNumber::default(), + } + .into(), + ) + } +} + +impl + RevealedDidMerkleProofLeaf +where + KeyId: Encode, + Web3Name: Encode, + LinkedAccountId: Encode, +{ + pub fn encoded_key(&self) -> Vec { + match self { + RevealedDidMerkleProofLeaf::DidKey(key, _) => key.encode(), + RevealedDidMerkleProofLeaf::Web3Name(key, _) => key.encode(), + RevealedDidMerkleProofLeaf::LinkedAccount(key, _) => key.encode(), + } + } +} + +impl + RevealedDidMerkleProofLeaf +where + AccountId: Encode, + BlockNumber: Encode, +{ + pub fn encoded_value(&self) -> Vec { + match self { + RevealedDidMerkleProofLeaf::DidKey(_, value) => value.encode(), + RevealedDidMerkleProofLeaf::Web3Name(_, value) => value.encode(), + RevealedDidMerkleProofLeaf::LinkedAccount(_, value) => value.encode(), + } + } +} + +/// The details of a DID key after it has been successfully verified in a Merkle +/// proof. +#[derive(Clone, Encode, Decode, PartialEq, MaxEncodedLen, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct RevealedDidKey { + /// The key ID, according to the provider's definition. + pub id: KeyId, + /// The key relationship to the subject's DID Document. + pub relationship: DidKeyRelationship, + /// The details of the DID Key, including its creation block number on the + /// provider chain. + pub details: DidPublicKeyDetails, +} + +/// The details of a web3name after it has been successfully verified in a +/// Merkle proof. +#[derive(Clone, Encode, Decode, PartialEq, MaxEncodedLen, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct RevealedWeb3Name { + /// The web3name. + pub web3_name: Web3Name, + /// The block number on the provider chain in which it was linked to the DID + /// subject. + pub claimed_at: BlockNumber, +} + +/// The complete set of information that is provided by the DIP Merkle proof +/// verifier upon successful verification of a DIP Merkle proof. +#[derive(Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode, DefaultNoBound)] +pub struct RevealedDidMerkleProofLeaves< + KeyId, + AccountId, + BlockNumber, + Web3Name, + LinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, +> { + /// The list of [`RevealedDidKey`]s revealed in the Merkle proof, up to a + /// maximum of `MAX_REVEALED_KEYS_COUNT`. + pub did_keys: BoundedVec, ConstU32>, + /// The optional [`RevealedWeb3Name`] revealed in the Merkle proof. + pub web3_name: Option>, + /// The list of linked accounts revealed in the Merkle proof, up to a + /// maximum of `MAX_REVEALED_ACCOUNTS_COUNT`. + pub linked_accounts: BoundedVec>, +} + +impl< + KeyId, + AccountId, + BlockNumber, + Web3Name, + LinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + > sp_std::borrow::Borrow<[RevealedDidKey]> + for RevealedDidMerkleProofLeaves< + KeyId, + AccountId, + BlockNumber, + Web3Name, + LinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + > +{ + fn borrow(&self) -> &[RevealedDidKey] { + self.did_keys.borrow() + } +} + +pub enum DidMerkleProofVerifierError { + InvalidMerkleProof, + TooManyRevealedKeys, + TooManyRevealedAccounts, +} + +impl From for u8 { + fn from(value: DidMerkleProofVerifierError) -> Self { + match value { + DidMerkleProofVerifierError::InvalidMerkleProof => 0, + DidMerkleProofVerifierError::TooManyRevealedKeys => 1, + DidMerkleProofVerifierError::TooManyRevealedAccounts => 2, + } + } +} + +/// A function that verifies a DIP Merkle proof revealing some leaves +/// representing parts of a KILT DID identity stored on the KILT chain. +/// If cross-chain DID signatures are not required for the specific use case, +/// this verifier can also be used on its own, without any DID signature +/// verification. +/// The Merkle proof is assumed to have been generated using one of the +/// versioned identity commitment generators, as shown in the [KILT runtime +/// definitions](../../../runtimes/common/src/dip/README.md). +/// The generic types are the following: +/// * `Hasher`: The hasher used by the producer to hash the Merkle leaves and +/// produce the identity commitment. +/// * `KeyId`: The type of a DID key ID according to the producer's definition. +/// * `AccountId`: The type of an account ID according to the producer's +/// definition. +/// * `BlockNumber`: The type of a block number according to the producer's +/// definition. +/// * `Web3Name`: The type of a web3names according to the producer's +/// definition. +/// * `LinkedAccountId`: The type of a DID-linked account ID according to the +/// producer's definition. +/// * `MAX_REVEALED_KEYS_COUNT`: The maximum number of DID keys that are +/// supported when verifying the Merkle proof. +/// * `MAX_REVEALED_ACCOUNTS_COUNT`: The maximum number of linked accounts that +/// are supported when verifying the Merkle proof. +pub(crate) fn verify_dip_merkle_proof< + Hasher, + KeyId, + AccountId, + BlockNumber, + Web3Name, + LinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, +>( + identity_commitment: &Hasher::Out, + proof: DidMerkleProof< + crate::BoundedBlindedValue, + RevealedDidMerkleProofLeaf, + >, +) -> Result< + RevealedDidMerkleProofLeaves< + KeyId, + AccountId, + BlockNumber, + Web3Name, + LinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >, + DidMerkleProofVerifierError, +> +where + BlockNumber: Encode + Clone, + Hasher: sp_core::Hasher, + KeyId: Encode + Clone, + AccountId: Encode + Clone, + LinkedAccountId: Encode + Clone, + Web3Name: Encode + Clone, +{ + // TODO: more efficient by removing cloning and/or collecting. + // Did not find another way of mapping a Vec<(Vec, Vec)> to a + // Vec<(Vec, Option>)>. + let proof_leaves = proof + .revealed + .iter() + .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) + .collect::, Option>)>>(); + let res = verify_trie_proof::, _, _, _>(identity_commitment, &proof.blinded, &proof_leaves); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| DidMerkleProofVerifierError::InvalidMerkleProof)?; + } + } + + // At this point, we know the proof is valid. We just need to map the revealed + // leaves to something the consumer can easily operate on. + #[allow(clippy::type_complexity)] + let (did_keys, web3_name, linked_accounts): ( + BoundedVec, ConstU32>, + Option>, + BoundedVec>, + ) = proof.revealed.into_iter().try_fold( + ( + BoundedVec::with_bounded_capacity(MAX_REVEALED_KEYS_COUNT.saturated_into()), + None, + BoundedVec::with_bounded_capacity(MAX_REVEALED_ACCOUNTS_COUNT.saturated_into()), + ), + |(mut keys, web3_name, mut linked_accounts), leaf| match leaf { + RevealedDidMerkleProofLeaf::DidKey(key_id, key_value) => { + let res = keys.try_push(RevealedDidKey { + id: key_id.0, + relationship: key_id.1, + details: key_value.0, + }); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| DidMerkleProofVerifierError::TooManyRevealedKeys)?; + } + } + + Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) + } + RevealedDidMerkleProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( + keys, + Some(RevealedWeb3Name { + web3_name: revealed_web3_name.0, + claimed_at: details.0, + }), + linked_accounts, + )), + RevealedDidMerkleProofLeaf::LinkedAccount(account_id, _) => { + let res = linked_accounts.try_push(account_id.0); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| DidMerkleProofVerifierError::TooManyRevealedAccounts)?; + } + } + + Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) + } + }, + )?; + + Ok(RevealedDidMerkleProofLeaves { + did_keys, + web3_name, + linked_accounts, + }) +} diff --git a/crates/kilt-dip-primitives/src/state_proofs/mod.rs b/crates/kilt-dip-primitives/src/state_proofs/mod.rs new file mode 100644 index 000000000..f21a27b14 --- /dev/null +++ b/crates/kilt-dip-primitives/src/state_proofs/mod.rs @@ -0,0 +1,81 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Module to deal with cross-chain state proofs. + +/// Parachain-related state proof logic. +pub(crate) mod parachain; +/// Relaychain-related state proof logic. +pub(crate) mod relaychain; + +// Ported from https://github.com/paritytech/substrate/blob/b27c470eaff379f512d1dec052aff5d551ed3b03/primitives/state-machine/src/lib.rs#L1076 +// Needs to be replaced with its runtime-friendly version when available, or be +// kept up-to-date with upstream. +mod substrate_no_std_port { + use hash_db::EMPTY_PREFIX; + use parity_scale_codec::Codec; + use sp_core::Hasher; + use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder}; + use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; + use sp_trie::{HashDBT, MemoryDB, StorageProof}; + + pub(super) fn read_proof_check( + root: H::Out, + proof: StorageProof, + keys: I, + ) -> Result, Option>>, ()> + where + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let proving_backend = create_proof_check_backend::(root, proof)?; + let mut result = BTreeMap::new(); + for key in keys.into_iter() { + let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?; + result.insert(key.as_ref().to_vec(), value); + } + Ok(result) + } + + fn read_proof_check_on_proving_backend( + proving_backend: &TrieBackend, H>, + key: &[u8], + ) -> Result>, ()> + where + H: Hasher, + H::Out: Ord + Codec, + { + proving_backend.storage(key).map_err(|_| ()) + } + + fn create_proof_check_backend(root: H::Out, proof: StorageProof) -> Result, H>, ()> + where + H: Hasher, + H::Out: Codec, + { + let db = proof.into_memory_db(); + + if db.contains(&root, EMPTY_PREFIX) { + Ok(TrieBackendBuilder::new(db, root).build()) + } else { + Err(()) + } + } +} diff --git a/crates/kilt-dip-primitives/src/state_proofs/parachain.rs b/crates/kilt-dip-primitives/src/state_proofs/parachain.rs new file mode 100644 index 000000000..3ad51695f --- /dev/null +++ b/crates/kilt-dip-primitives/src/state_proofs/parachain.rs @@ -0,0 +1,168 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use parity_scale_codec::Decode; +use sp_core::RuntimeDebug; +use sp_std::marker::PhantomData; +use sp_trie::StorageProof; + +use crate::{ + state_proofs::substrate_no_std_port::read_proof_check, traits::ProviderParachainStorageInfo, utils::OutputOf, +}; + +#[derive(RuntimeDebug)] +pub enum DipIdentityCommitmentProofVerifierError { + InvalidMerkleProof, + RequiredLeafNotRevealed, + CommitmentDecode, +} + +impl From for u8 { + fn from(value: DipIdentityCommitmentProofVerifierError) -> Self { + match value { + DipIdentityCommitmentProofVerifierError::InvalidMerkleProof => 0, + DipIdentityCommitmentProofVerifierError::RequiredLeafNotRevealed => 1, + DipIdentityCommitmentProofVerifierError::CommitmentDecode => 2, + } + } +} + +/// Verifier of state proofs that reveal the value of the DIP commitment for +/// a given subject on the provider chain. The generic types indicate the +/// following: +/// * `ParaInfo`: defines the provider parachain runtime types relevant for +/// state proof verification, and returns the provider's runtime storage key +/// identifying the identity commitment for a subject with the given +/// identifier. +pub struct DipIdentityCommitmentProofVerifier(PhantomData); + +impl DipIdentityCommitmentProofVerifier +where + ParaInfo: ProviderParachainStorageInfo, + OutputOf: Ord, + ParaInfo::Commitment: Decode, + ParaInfo::Key: AsRef<[u8]>, +{ + /// Given a parachain state root, verify a state proof for the + /// commitment of a given subject identifier. + #[cfg(not(feature = "runtime-benchmarks"))] + pub fn verify_proof_for_identifier( + identifier: &ParaInfo::Identifier, + state_root: OutputOf, + proof: impl IntoIterator>, + ) -> Result { + let dip_commitment_storage_key = ParaInfo::dip_subject_storage_key(identifier, 0); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = + read_proof_check::(state_root, storage_proof, [&dip_commitment_storage_key].iter()) + .map_err(|_| DipIdentityCommitmentProofVerifierError::InvalidMerkleProof)?; + // TODO: Remove at some point + { + debug_assert!(revealed_leaves.len() == 1usize); + debug_assert!(revealed_leaves.contains_key(dip_commitment_storage_key.as_ref())); + } + let Some(Some(encoded_commitment)) = revealed_leaves.get(dip_commitment_storage_key.as_ref()) else { + return Err(DipIdentityCommitmentProofVerifierError::RequiredLeafNotRevealed); + }; + ParaInfo::Commitment::decode(&mut &encoded_commitment[..]) + .map_err(|_| DipIdentityCommitmentProofVerifierError::CommitmentDecode) + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn verify_proof_for_identifier( + identifier: &ParaInfo::Identifier, + state_root: OutputOf, + proof: impl IntoIterator>, + ) -> Result + where + ParaInfo::Commitment: Default, + { + let dip_commitment_storage_key = ParaInfo::dip_subject_storage_key(identifier, 0); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = + read_proof_check::(state_root, storage_proof, [&dip_commitment_storage_key].iter()) + .unwrap_or_default(); + let encoded_commitment = + if let Some(Some(encoded_commitment)) = revealed_leaves.get(dip_commitment_storage_key.as_ref()) { + encoded_commitment.clone() + } else { + sp_std::vec::Vec::default() + }; + let commitment = ParaInfo::Commitment::decode(&mut &encoded_commitment[..]).unwrap_or_default(); + Ok(commitment) + } +} + +#[cfg(test)] +mod spiritnet_test_event_count_value { + use super::*; + + use hex_literal::hex; + use pallet_dip_provider::IdentityCommitmentVersion; + use sp_core::{storage::StorageKey, H256}; + use sp_runtime::traits::BlakeTwo256; + + // Spiritnet block n: 4_184_668, + // hash 0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5 + struct StaticSpiritnetInfoProvider; + + // We use the `system::eventCount()` storage entry as a unit test here. + impl ProviderParachainStorageInfo for StaticSpiritnetInfoProvider { + type BlockNumber = u32; + // The type of the `eventCount()` storage entry. + type Commitment = u32; + type Hasher = BlakeTwo256; + // Irrelevant for this test here + type Identifier = (); + type Key = StorageKey; + + fn dip_subject_storage_key(_identifier: &Self::Identifier, _version: IdentityCommitmentVersion) -> Self::Key { + // system::eventCount() raw storage key + let storage_key = hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(); + StorageKey(storage_key) + } + } + + #[test] + fn test_spiritnet_event_count() { + // As of RPC state_getReadProof(" + // 0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850", + // "0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5") + let spiritnet_event_count_proof_at_block = [ + hex!("800404645ea5c1b19ab7a04f536c519aca4983ac205cda3f0000000000545e98fdbe9ce6c55837576c60c7af38501005000000").to_vec(), + hex!("80401080481e2bd8085a02c5b58987bce7a69f0b5c7fa651e8e82c5481c94707860be9078067785103d453293707ba847e21df7e35a7a57b8fb929d40465328b6642669fcc").to_vec(), + hex!("80ffff8010623b5a3a9dbc752963d827be0bb855bf3e24258ae09341d5f762e96a836ac180c34b753605e821528756b55b4ddafb742df6e54fbc03ef401d4ebfd6dd4f3e44806f83646e0bf3ca0ac9f2092dea5b0e3caf210cc6b54c3b44a51855a133367a6580b02cde7b1fd3f8d13f698ef6e9daa29b32258d4d97a8947051070a4540aecacd80903d521961849d07ceee132617b8dde96c3ff472f5a9a089d4055ffe7ffd1e988016c29c943c106713bb8f16b776eb7daed005540165696da286cddf6b25d085448019a464010cb746b0589891f72b0eed603d4712b04af46f7bcae724564194801480a305ffe069db7eb21841f75b5939943f62c4abb3a051d530839c5dd935ccbc8a8035d8938b0c856878de1e3fe45a559588b2da52ccf195ab1e3d0aca6ac7bb079d8064019a474a283c19f46ff4652a5e1f636efd4013d3b8a91c49573045c6ff01c0801a191dcb736faddb84889a13c7aa717d260e9b635b30a9eb3907f925a2253d6880f8bc389fc62ca951609bae208b7506bae497623e647424062d1c56cb1f2d2e1c80211a9fb5f8b794f9fbfbdcd4519aa475ecaf9737b4ee513dde275d5fbbe64da080c267d0ead99634e9b9cfbf61a583877e0241ac518e62e909fbb017469de275f780b3059a7226d4b320c25e9b2f8ffe19cf93467e3b306885962c5f34b5671d15fe8092dfba9e30e1bbefab13c792755d06927e6141f7220b7485e5aa40de92401a66").to_vec(), + hex!("9eaa394eea5630e07c48ae0c9558cef7398f8069ef420a0deb5a428c9a08563b28a78874bba09124eecc8d28bf30b0e2ddd310745f04abf5cb34d6244378cddbf18e849d962c000000000736d8e8140100505f0e7b9012096b41c4eb3aaf947f6ea4290800004c5f0684a022a34dd8bfa2baaf44f172b710040180dd3270a03a1a13fc20bcdf24d1aa4ddccc6183db2e2e153b8a68ba8540699a8a80b413dad63538a591f7f2575d287520ee44d7143aa5ec2411969861e1f55a2989804c3f0f541a13980689894db7c60c785dd29e066f213bb29b17aa740682ad7efd8026d3a50544f5c89500745aca2be36cfe076f599c5115192fb9deae227e2710c980bd04b00bf6b42756a06a4fbf05a5231c2094e48182eca95d2cff73ab907592aa").to_vec(), + ].to_vec(); + let spiritnet_state_root: H256 = + hex!("94c23fda279cea4a4370e90f1544c8938923dfd4ac201a420c7a26fb0d3caf8c").into(); + // As of query system::eventCount() at block + // "0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5" which + // results in the key + // "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850" + let expected_event_count_at_block = 5; + let returned_event_count = + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + &(), + spiritnet_state_root, + spiritnet_event_count_proof_at_block, + ) + .unwrap(); + assert!(returned_event_count == expected_event_count_at_block, "Spiritnet event count returned from the state proof verification should not be different than the pre-computed one."); + } +} diff --git a/crates/kilt-dip-primitives/src/state_proofs/relaychain.rs b/crates/kilt-dip-primitives/src/state_proofs/relaychain.rs new file mode 100644 index 000000000..018b98481 --- /dev/null +++ b/crates/kilt-dip-primitives/src/state_proofs/relaychain.rs @@ -0,0 +1,261 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use parity_scale_codec::{Encode, HasCompact}; +use sp_core::{storage::StorageKey, RuntimeDebug, U256}; +use sp_runtime::{generic::Header, traits::BlakeTwo256}; +use sp_std::{marker::PhantomData, vec::Vec}; +use sp_trie::StorageProof; + +use crate::{ + state_proofs::substrate_no_std_port::read_proof_check, + traits::{RelayChainStateInfo, RelayChainStorageInfo}, + utils::OutputOf, +}; + +#[derive(RuntimeDebug)] +pub enum ParachainHeadProofVerifierError { + InvalidMerkleProof, + RequiredLeafNotRevealed, + HeaderDecode, + RelaychainStateRootNotFound, +} + +impl From for u8 { + fn from(value: ParachainHeadProofVerifierError) -> Self { + match value { + ParachainHeadProofVerifierError::InvalidMerkleProof => 0, + ParachainHeadProofVerifierError::RequiredLeafNotRevealed => 1, + ParachainHeadProofVerifierError::HeaderDecode => 2, + ParachainHeadProofVerifierError::RelaychainStateRootNotFound => 3, + } + } +} + +/// Verifier of state proofs that reveal the value of a parachain head at a +/// given relaychain block number. +/// The generic types are the following: +/// * `RelayChainState`: defines the relaychain runtime types relevant for state +/// proof verification, and returns the relaychain runtime's storage key +/// identifying a parachain with a given ID. +pub struct ParachainHeadProofVerifier(PhantomData); + +// Uses the provided `root` to verify the proof. +impl ParachainHeadProofVerifier +where + RelayChainState: RelayChainStorageInfo, + OutputOf: Ord, + RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayChainState::Key: AsRef<[u8]>, +{ + /// Given a relaychain state root, verify a state proof for the + /// parachain with the provided ID. + #[cfg(not(feature = "runtime-benchmarks"))] + pub fn verify_proof_for_parachain_with_root( + para_id: &RelayChainState::ParaId, + root: &OutputOf<::Hasher>, + proof: impl IntoIterator>, + ) -> Result, ParachainHeadProofVerifierError> { + use parity_scale_codec::Decode; + + let parachain_storage_key = RelayChainState::parachain_head_storage_key(para_id); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = + read_proof_check::(*root, storage_proof, [¶chain_storage_key].iter()) + .map_err(|_| ParachainHeadProofVerifierError::InvalidMerkleProof)?; + // TODO: Remove at some point + { + debug_assert!(revealed_leaves.len() == 1usize); + debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); + } + let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { + return Err(ParachainHeadProofVerifierError::RequiredLeafNotRevealed); + }; + // TODO: Figure out why RPC call returns 2 bytes in front which we don't need + let mut unwrapped_head = &encoded_head[2..]; + Header::decode(&mut unwrapped_head).map_err(|_| ParachainHeadProofVerifierError::HeaderDecode) + } + + // Ignores any errors returned by the `read_proof_check` function and returns a + // default Header in case of failure. + #[cfg(feature = "runtime-benchmarks")] + pub fn verify_proof_for_parachain_with_root( + para_id: &RelayChainState::ParaId, + root: &OutputOf<::Hasher>, + proof: impl IntoIterator>, + ) -> Result, ParachainHeadProofVerifierError> { + use parity_scale_codec::Decode; + + let parachain_storage_key = RelayChainState::parachain_head_storage_key(para_id); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = + read_proof_check::(*root, storage_proof, [¶chain_storage_key].iter()) + .unwrap_or_default(); + let encoded_head = if let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) { + encoded_head.clone() + } else { + sp_std::vec![0u8; 3] + }; + let mut unwrapped_head = &encoded_head[2..]; + let header = Header::decode(&mut unwrapped_head).unwrap_or(Header { + number: U256::from(0u64) + .try_into() + .map_err(|_| "Block number should be created from a u64") + .unwrap(), + digest: Default::default(), + extrinsics_root: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }); + Ok(header) + } + + /// Given a relaychain state root provided by the `RelayChainState` + /// generic type, verify a state proof for the parachain with the + /// provided ID. + #[cfg(not(feature = "runtime-benchmarks"))] + pub fn verify_proof_for_parachain( + para_id: &RelayChainState::ParaId, + relay_height: &RelayChainState::BlockNumber, + proof: impl IntoIterator>, + ) -> Result, ParachainHeadProofVerifierError> + where + RelayChainState: RelayChainStateInfo, + { + let relay_state_root = RelayChainState::state_root_for_block(relay_height) + .ok_or(ParachainHeadProofVerifierError::RelaychainStateRootNotFound)?; + Self::verify_proof_for_parachain_with_root(para_id, &relay_state_root, proof) + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn verify_proof_for_parachain( + para_id: &RelayChainState::ParaId, + relay_height: &RelayChainState::BlockNumber, + proof: impl IntoIterator>, + ) -> Result, ParachainHeadProofVerifierError> + where + RelayChainState: RelayChainStateInfo, + { + let relay_state_root = RelayChainState::state_root_for_block(relay_height).unwrap_or_default(); + Self::verify_proof_for_parachain_with_root(para_id, &relay_state_root, proof) + } +} + +/// Implementor of the [`RelayChainStorageInfo`] trait that return the state +/// root of a relaychain block with a given number by retrieving it from the +/// [`pallet_relay_store::Pallet`] pallet storage. It hardcodes the +/// relaychain `BlockNumber`, `Hasher`, `StorageKey`, and `ParaId` to the +/// ones used by Polkadot-based relaychains. This type cannot be used with +/// relaychains that adopt a different definition for any on those types. +pub struct RelayStateRootsViaRelayStorePallet(PhantomData); + +impl RelayChainStorageInfo for RelayStateRootsViaRelayStorePallet +where + Runtime: pallet_relay_store::Config, +{ + type BlockNumber = u32; + type Hasher = BlakeTwo256; + type Key = StorageKey; + type ParaId = u32; + + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { + // TODO: Access the runtime definition from here, once and if exposed. + let encoded_para_id = para_id.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), + sp_io::hashing::twox_64(&encoded_para_id).as_slice(), + encoded_para_id.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } +} + +impl RelayChainStateInfo for RelayStateRootsViaRelayStorePallet +where + Runtime: pallet_relay_store::Config, +{ + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option> { + pallet_relay_store::Pallet::::latest_relay_head_for_block(block_height) + .map(|relay_header| relay_header.relay_parent_storage_root) + } +} + +#[cfg(test)] +mod polkadot_parachain_head_proof_verifier_tests { + use super::*; + + use hex_literal::hex; + use sp_runtime::traits::BlakeTwo256; + + // Polkadot block n: 16_363_919, + // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 + struct StaticPolkadotInfoProvider; + + impl RelayChainStorageInfo for StaticPolkadotInfoProvider { + type BlockNumber = u32; + type Hasher = BlakeTwo256; + type Key = StorageKey; + type ParaId = u32; + + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { + // Adapted from https://github.com/polytope-labs/substrate-ismp/blob/7fb09da6c7b818a98c25c962fee0ddde8e737306/parachain/src/consensus.rs#L369 + // Used for testing. In production this would be generated from the relay + // runtime definition of the `paras` storage map. + let encoded_para_id = para_id.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), + sp_io::hashing::twox_64(&encoded_para_id).as_slice(), + encoded_para_id.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } + } + + impl RelayChainStateInfo for StaticPolkadotInfoProvider { + fn state_root_for_block(_block_height: &Self::BlockNumber) -> Option> { + Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) + } + } + + #[test] + fn test_spiritnet_head_proof() { + // As of RPC state_getReadProof("0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000", "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39") + let spiritnet_head_proof_at_block = [ + hex!("570c0cfd6c23b92a7826080000f102e90265541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(), + hex!("80046480186b1513c5112466ada33da3c65558979906ca9fb82510b62f6ea01f550a4807808bc90ded5636f31c8395a315b5f27a1a25a2ceebd36921a518669ce7e52f80e680993c5e952e6e4f72f295ba04951ace9029b23e9a87887b41895c16f77bec42ee80b798b224c5ee3d668519e75ca98504116f645fb969a5e2653a298b0181f9a694").to_vec(), + hex!("80ffff806ecd86e87715a007ee9b216d8a99a604773014260d51f6552b6fbd7c21786d9c80e23ef51809d6c80c01a6e264ff0d298cce01c1addfdbb0789597b9a6b3f3e4fd80c9c5f0f29d777e2cebcdbd06ddf1c2cfa8ee83524b37ace99d8b7a3aeff039b380da013185503cfefa6c9cc88751993f1f2bf4b8fa4918e876f499fb9405e3206c803a89668f636552a0fb93619913dcc46cf3e087363d532b76a345155a44a46b5180c2e7fc654720b7dcc0316ae1591fde4beb8b853a343b7e5e3ee564d2692c2ee280840f9c4ae7c16ae948828bf50faf062264402e6134d2d6144a5e3ecb0a1e1d9c80f93c2be1ef51fb2032445cc7fbc2023b9e3b8cf8c0d832b464ae48a020bfaa8c8010c63537c9bf58d50c8c0e13c154fd88b2f683e13701901bdc64565aa9b756d580f0b60eaf17fb680827e8a8938c717ac943b85ff373c0fc911e06c34a3a30327280ccb29f1efa59fd7c80a730cb88789a5a256b01fee7e83ac9a3c90da330adc7a480c8e57c547edb33d4b712f017f09d2de2e055f18815669c83eef2f7f3e5dcafae80b7b7e7ffc91a7dd4c4902f7f15cd7598d1258a75433ea953565661d114e2dcca80ebc3a2df819c7c2fd1a33eb1d484beaf7b71114d6a6db240d8b07dc10bfdc49b80a71f21aa3fa5d7475bf134d50f25e2515c797d0a4c2e93998888150c1f969ab8801e32613f54e70c95e9b16a14f5797522ef5e2ef7867868ff663e33e8880994ed").to_vec(), + hex!("9e710b30bd2eab0352ddcc26417aa1945fd380d49ebc7ca5c1b751c2badb5e5a326d3ba9e331d8b7c6cf279ed7fd71a8882b6c8038088652f73dc8a22336d10f492f0ef8836beaba0ccfeb0f8fabdc9df1d17e2d807f88402cbbed7fa3307e07044200b572d5e8e12913b41e1923dcb2c0799bc2be804d57e9a8e4934fab698a9db50682052ee9459c666a075d1bfc471da8e5da14da80b9aee043e378f8313e68a6030679ccf3880fa1e7ab19b6244b5c262b7a152f004c5f03c716fb8fff3de61a883bb76adb34a2040080f282bc12648ffb197ffc257edc7ff3a3fdda452daa51091ccbd2dfb91d8aa9518008a0c609ab4888f02c2545c002153297c2641c5a7b4f3d8e25c634e721f80bea80b6617c764df278313c426c46961ccde8ee7a03f9007b74bc8bc6c49d1583cf7d8077b493d45eb153353026cc330307e0753ac41a5cb8e843ceb1efdc46655f33a0808bdaa43fc5dc0e928e2da0ce8ed02096b0b74c61feaba2546980ed9c6174f71d").to_vec(), + hex!("9f0b3c252fcb29d88eff4f3de5de4476c3ffbf8013c601cc93de3437f9d415bd52c48d794b341f218b9d0020a4b646746c24d0ca80348b8e2c39c479a146933297f62b7051df82e92e1bca761432c3e6f64c74033f80220131e7cd7a08b97f8aa06225f7aefbbca8118fb436c07689c552ed3f577145806d974dd9e4db5e407e29f84c4121ccc58f9c6adc3933afc1bcaef52defe77de5801e9e1a21db053de56365fdee57998488ddae7d664c0430da90469dde17936c1f80c5c11751bbfc99a1ad805c58a65b9704e0bad58e694023e9cc57ce6ef84cdb0b8038f6c242700eaea04ffad5c25ca9a9b1cc2af7303655a32eb59e84b6bb927cd3802575469e76e104b0db8b18dbc762b997a78aa666432a44c4b955ced044a4691f80a81408b856272feeec08845af515e27d033efd3ff8b46de6bc706c38e600086a809ee78332c2a38a3918070942421e651e0b9a43e4b8b2c92e87a2552cede73e8380c9d79f411f742cad0c6f2b070aa08703a04cb7db840c3821a6762837dd8d00e9807dcfbc7f2fcc9415e2cb40eef7f718758d76193f325b3f8b7180e3e5e7d6b81e8036252cae6d24a531a151ce1ee223a07bf71cf82a7fdf49090e4ca345d27d68ca80e3f08ef11671f8f1defa66fa2af71e1a871430e9352df9b3f1d427b5a5dabfb280b51d28c9b99030d050fc1578cd23b5506e769b86c8f4ccc6aded4b8d7c1a73b7").to_vec(), + ].to_vec(); + // As of query paras::heads(2_086) at block + // "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39" + // (16_363_919) which results in the key + // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" + // + let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); + let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( + &2_086, + &16_363_919, + spiritnet_head_proof_at_block, + ) + .expect("Parachain head proof verification should not fail."); + assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); + } +} diff --git a/crates/kilt-dip-primitives/src/traits.rs b/crates/kilt-dip-primitives/src/traits.rs new file mode 100644 index 000000000..b96ac7d33 --- /dev/null +++ b/crates/kilt-dip-primitives/src/traits.rs @@ -0,0 +1,214 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_dip_provider::{IdentityCommitmentOf, IdentityCommitmentVersion}; +use sp_core::storage::StorageKey; +use sp_runtime::traits::{CheckedAdd, One, Zero}; +use sp_std::marker::PhantomData; + +use crate::utils::OutputOf; + +// TODO: Switch to the `Incrementable` trait once it's added to the root of +// `frame_support`. +/// A trait for "incrementable" types, i.e., types that have some notion of +/// order of its members. +pub trait Incrementable { + /// Increment the type instance to its next value. Overflows are assumed to + /// be taken care of by the type internal logic. + fn increment(&mut self); +} + +impl Incrementable for T +where + T: CheckedAdd + Zero + One, +{ + fn increment(&mut self) { + *self = self.checked_add(&Self::one()).unwrap_or_else(Self::zero); + } +} + +/// A trait for types that implement access control logic where the call is the +/// controlled resource and access is granted based on the provided info. +/// The generic types are the following: +/// * `Call`: The type of the call being checked. +pub trait DipCallOriginFilter { + /// The error type for cases where the checks fail. + type Error; + /// The type of additional information required by the type to perform the + /// checks on the `Call` input. + type OriginInfo; + /// The success type for cases where the checks succeed. + type Success; + + /// Check whether the provided call can be dispatch with the given origin + /// information. + fn check_call_origin_info(call: &Call, info: &Self::OriginInfo) -> Result; +} + +/// A trait that provides context (e.g., runtime type definitions, storage keys) +/// about the relaychain that is relevant for cross-chain state proofs. +pub trait RelayChainStorageInfo { + /// The type of relaychain block numbers. + type BlockNumber; + /// The type of the relaychain hashing algorithm. + type Hasher: sp_runtime::traits::Hash; + /// The type of the relaychain storage key. + type Key; + /// The type of parachain IDs. + type ParaId; + + /// Return the storage key pointing to the head of the parachain + /// identified by the provided ID. + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; +} + +/// A trait that provides state information about specific relaychain blocks. +pub trait RelayChainStateInfo: RelayChainStorageInfo { + /// Return the relaychain state root at a given block height. + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option>; +} + +/// A trait that provides context (e.g., runtime type definitions, storage keys) +/// about the DIP provider parachain that is relevant for cross-chain state +/// proofs. +pub trait ProviderParachainStorageInfo { + /// The type of the provider chain's block numbers. + type BlockNumber; + /// The type of the provider chain's identity commitments. + type Commitment; + /// The type of the provider chain's storage keys. + type Key; + /// The type of the provider chain's hashing algorithm. + type Hasher: sp_runtime::traits::Hash; + /// The type of the provider chain's identity subject identifiers. + type Identifier; + + /// Return the storage key pointing to the identity commitment for the given + /// identifier and version. + fn dip_subject_storage_key(identifier: &Self::Identifier, version: IdentityCommitmentVersion) -> Self::Key; +} + +/// Implementation of the [`ProviderParachainStorageInfo`] trait that builds on +/// the definitions of a runtime that includes the DIP provider pallet (e.g., +/// KILT runtimes). +/// The generic types are the following: +/// * `T`: The runtime including the [`pallet_dip_provider::Pallet`] pallet. +pub struct ProviderParachainStateInfoViaProviderPallet(PhantomData); + +impl ProviderParachainStorageInfo for ProviderParachainStateInfoViaProviderPallet +where + T: pallet_dip_provider::Config, +{ + type BlockNumber = BlockNumberFor; + type Commitment = IdentityCommitmentOf; + type Hasher = T::Hashing; + type Identifier = T::Identifier; + type Key = StorageKey; + + fn dip_subject_storage_key(identifier: &Self::Identifier, version: IdentityCommitmentVersion) -> Self::Key { + StorageKey(pallet_dip_provider::IdentityCommitments::::hashed_key_for( + identifier, version, + )) + } +} + +/// A trait that provides the consumer parachain runtime additional context to +/// verify cross-chain DID signatures by subjects of the provider parachain. +pub trait DidSignatureVerifierContext { + /// Max number of blocks a cross-chain DID signature can have to be + /// considered fresh. + const SIGNATURE_VALIDITY: u16; + + /// The type of consumer parachain's block numbers. + type BlockNumber; + /// The type of consumer parachain's hashes. + type Hash; + /// Additional information that must be included in the payload being + /// DID-signed by the subject. + type SignedExtra; + + /// Returns the block number of the consumer's chain in which the DID + /// signature is being evaluated. + fn current_block_number() -> Self::BlockNumber; + /// Returns the genesis hash of the consumer's chain. + fn genesis_hash() -> Self::Hash; + /// Returns any additional info that must be appended to the payload before + /// verifying a cross-chain DID signature. + fn signed_extra() -> Self::SignedExtra; +} + +/// Implementation of the [`DidSignatureVerifierContext`] trait that draws +/// information dynamically from the consumer's runtime using its system pallet. +/// The generic types are the following: +/// * `T`: The runtime including the [`frame_system::Pallet`] pallet. +/// * `SIGNATURE_VALIDITY`: The max number of blocks DID signatures can have to +/// be considered valid. +pub struct FrameSystemDidSignatureContext(PhantomData); + +impl DidSignatureVerifierContext + for FrameSystemDidSignatureContext +where + T: frame_system::Config, +{ + const SIGNATURE_VALIDITY: u16 = SIGNATURE_VALIDITY; + + type BlockNumber = BlockNumberFor; + type Hash = T::Hash; + type SignedExtra = (); + + fn current_block_number() -> Self::BlockNumber { + frame_system::Pallet::::block_number() + } + + fn genesis_hash() -> Self::Hash { + frame_system::Pallet::::block_hash(Self::BlockNumber::zero()) + } + + fn signed_extra() -> Self::SignedExtra {} +} + +/// A trait that provides access to information on historical blocks. +pub trait HistoricalBlockRegistry { + /// The runtime definition of block numbers. + type BlockNumber; + /// The runtime hashing algorithm. + type Hasher: sp_runtime::traits::Hash; + + /// Retrieve a block hash given its number. + fn block_hash_for(block: &Self::BlockNumber) -> Option>; +} + +impl HistoricalBlockRegistry for T +where + T: frame_system::Config, +{ + type BlockNumber = BlockNumberFor; + type Hasher = T::Hashing; + + fn block_hash_for(block: &Self::BlockNumber) -> Option> { + let retrieved_block = frame_system::Pallet::::block_hash(block); + let default_block_hash_value = ::default(); + + if retrieved_block == default_block_hash_value { + None + } else { + Some(retrieved_block) + } + } +} diff --git a/crates/kilt-dip-primitives/src/utils.rs b/crates/kilt-dip-primitives/src/utils.rs new file mode 100644 index 000000000..184ea12e8 --- /dev/null +++ b/crates/kilt-dip-primitives/src/utils.rs @@ -0,0 +1,82 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; +use sp_std::vec::Vec; + +/// The output of a type implementing the [`sp_runtime::traits::Hash`] trait. +pub type OutputOf = ::Output; + +/// The vector of vectors that implements a statically-configured maximum length +/// without requiring const generics, used in benchmarking worst cases. +#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] +pub struct BoundedBlindedValue(Vec>); + +impl BoundedBlindedValue { + pub fn into_inner(self) -> Vec> { + self.0 + } +} + +impl From for BoundedBlindedValue +where + C: Iterator>, +{ + fn from(value: C) -> Self { + Self(value.into_iter().collect()) + } +} + +impl sp_std::ops::Deref for BoundedBlindedValue { + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl IntoIterator for BoundedBlindedValue { + type IntoIter = > as IntoIterator>::IntoIter; + type Item = > as IntoIterator>::Item; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl kilt_support::traits::GetWorstCase for BoundedBlindedValue +where + T: Default + Clone, +{ + fn worst_case(_context: Context) -> Self { + Self(sp_std::vec![sp_std::vec![T::default(); 128]; 64]) + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl Default for BoundedBlindedValue +where + T: Default + Clone, +{ + fn default() -> Self { + Self(sp_std::vec![sp_std::vec![T::default(); 128]; 64]) + } +} diff --git a/crates/kilt-dip-primitives/src/verifier/common.rs b/crates/kilt-dip-primitives/src/verifier/common.rs new file mode 100644 index 000000000..455c5848a --- /dev/null +++ b/crates/kilt-dip-primitives/src/verifier/common.rs @@ -0,0 +1,77 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub mod latest { + pub use super::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}; +} + +pub mod v0 { + use parity_scale_codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_core::RuntimeDebug; + + use crate::{did::TimeBoundDidSignature, merkle::DidMerkleProof, BoundedBlindedValue}; + + #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] + pub struct ParachainRootStateProof { + /// The relaychain block height for which the proof has been generated. + pub(crate) relay_block_height: RelayBlockHeight, + /// The raw state proof. + pub(crate) proof: BoundedBlindedValue, + } + + #[cfg(feature = "runtime-benchmarks")] + impl kilt_support::traits::GetWorstCase + for ParachainRootStateProof + where + RelayBlockHeight: Default, + { + fn worst_case(context: Context) -> Self { + Self { + relay_block_height: RelayBlockHeight::default(), + proof: BoundedBlindedValue::worst_case(context), + } + } + } + + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] + pub struct DipMerkleProofAndDidSignature { + /// The DIP Merkle proof revealing some leaves about the DID subject's + /// identity. + pub(crate) leaves: DidMerkleProof, + /// The cross-chain DID signature. + pub(crate) signature: TimeBoundDidSignature, + } + + #[cfg(feature = "runtime-benchmarks")] + impl kilt_support::traits::GetWorstCase + for DipMerkleProofAndDidSignature + where + BlindedValues: kilt_support::traits::GetWorstCase, + Leaf: Default + Clone, + BlockNumber: Default, + Context: Clone, + { + fn worst_case(context: Context) -> Self { + Self { + leaves: DidMerkleProof::worst_case(context.clone()), + signature: TimeBoundDidSignature::worst_case(context), + } + } + } +} diff --git a/crates/kilt-dip-primitives/src/verifier/mod.rs b/crates/kilt-dip-primitives/src/verifier/mod.rs new file mode 100644 index 000000000..a48871a30 --- /dev/null +++ b/crates/kilt-dip-primitives/src/verifier/mod.rs @@ -0,0 +1,35 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +/// Verification logic to integrate a sibling chain as a DIP provider. +pub mod parachain; +/// Verification logic to integrate a child chain as a DIP provider. +pub mod relaychain; + +mod common; + +pub use parachain::{ + DipParachainStateProofVerifierError, KiltVersionedParachainVerifier, VersionedDipParachainStateProof, +}; +pub use relaychain::{ + DipRelaychainStateProofVerifierError, KiltVersionedRelaychainVerifier, VersionedRelaychainStateProof, +}; + +pub mod latest { + pub use super::{common::latest::*, parachain::latest::*, relaychain::latest::*}; +} diff --git a/crates/kilt-dip-primitives/src/verifier/parachain.rs b/crates/kilt-dip-primitives/src/verifier/parachain.rs new file mode 100644 index 000000000..c8b715172 --- /dev/null +++ b/crates/kilt-dip-primitives/src/verifier/parachain.rs @@ -0,0 +1,768 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use cumulus_primitives_core::ParaId; +use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyIdOf}; +use frame_support::Parameter; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_consumer::{traits::IdentityProofVerifier, RuntimeCallOf}; +use pallet_dip_provider::IdentityCommitmentOf; +use parity_scale_codec::{Decode, Encode, HasCompact}; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, U256}; +use sp_runtime::traits::Get; +use sp_std::marker::PhantomData; + +use crate::{ + did::RevealedDidKeysSignatureAndCallVerifierError, + merkle::{DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifierError, relaychain::ParachainHeadProofVerifierError}, + traits::{self, DidSignatureVerifierContext, DipCallOriginFilter, Incrementable}, + utils::OutputOf, + BoundedBlindedValue, FrameSystemDidSignatureContext, ProviderParachainStateInfoViaProviderPallet, +}; + +/// A KILT-specific DIP identity proof for a sibling consumer that supports +/// versioning. +/// +/// For more info, refer to the version-specific proofs. +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] +pub enum VersionedDipParachainStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, +> { + V0( + v0::ParachainDipStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, + >, + ), +} + +#[cfg(feature = "runtime-benchmarks")] +impl + kilt_support::traits::GetWorstCase + for VersionedDipParachainStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, + > where + RelayBlockHeight: Default, + DipMerkleProofBlindedValues: kilt_support::traits::GetWorstCase, + DipMerkleProofRevealedLeaf: Default + Clone, + LocalBlockNumber: Default, + Context: Clone, +{ + fn worst_case(context: Context) -> Self { + Self::V0(v0::ParachainDipStateProof::worst_case(context)) + } +} + +pub enum DipParachainStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, +> { + UnsupportedVersion, + ParachainHeadMerkleProof(ParachainHeadMerkleProofVerificationError), + IdentityCommitmentMerkleProof(IdentityCommitmentMerkleProofVerificationError), + DipProof(DipProofVerificationError), + DidSignature(DidSignatureVerificationError), +} + +impl< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + > + From< + DipParachainStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + > for u16 +where + ParachainHeadMerkleProofVerificationError: Into, + IdentityCommitmentMerkleProofVerificationError: Into, + DipProofVerificationError: Into, + DidSignatureVerificationError: Into, +{ + fn from( + value: DipParachainStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + ) -> Self { + match value { + DipParachainStateProofVerifierError::UnsupportedVersion => 0, + DipParachainStateProofVerifierError::ParachainHeadMerkleProof(error) => { + u8::MAX as u16 + error.into() as u16 + } + DipParachainStateProofVerifierError::IdentityCommitmentMerkleProof(error) => { + u8::MAX as u16 * 2 + error.into() as u16 + } + DipParachainStateProofVerifierError::DipProof(error) => u8::MAX as u16 * 3 + error.into() as u16, + DipParachainStateProofVerifierError::DidSignature(error) => u8::MAX as u16 * 4 + error.into() as u16, + } + } +} + +/// Proof verifier configured given a specific KILT runtime implementation. +/// +/// It is a specialization of the +/// [`GenericVersionedParachainVerifier`] type, with +/// configurations derived from the provided KILT runtime. +/// +/// The generic types +/// indicate the following: +/// * `KiltRuntime`: A KILT runtime definition. +/// * `KiltParachainId`: The ID of the specific KILT parachain instance. +/// * `RelayChainInfo`: The type providing information about the relaychain. +/// * `KiltDipMerkleHasher`: The hashing algorithm used by the KILT parachain +/// for the generation of the DIP identity commitment. +/// * `LocalDidCallVerifier`: Logic to map `RuntimeCall`s to a specific DID key +/// relationship. This information is used once the Merkle proof is verified, +/// to filter only the revealed keys that match the provided relationship. +/// * `MAX_REVEALED_KEYS_COUNT`: **OPTIONAL** Max number of DID keys that the +/// verifier will accept revealed as part of the DIP identity proof. It +/// defaults to **10**. +/// * `MAX_REVEALED_ACCOUNTS_COUNT`: **OPTIONAL** Max number of linked accounts +/// that the verifier will accept revealed as part of the DIP identity proof. +/// It defaults to **10**. +/// * `MAX_DID_SIGNATURE_DURATION`: **OPTIONAL** Max number of blocks a +/// cross-chain DID signature is considered fresh. It defaults to **50**. +/// +/// It specializes the [`GenericVersionedParachainVerifier`] +/// type by using the following types for its generics: +/// * `RelayChainInfo`: The provided `RelayChainInfo`. +/// * `ChildProviderParachainId`: The provided `KiltParachainId`. +/// * `ChildProviderStateInfo`: The +/// [`ProviderParachainStateInfoViaProviderPallet`] type configured with the +/// provided `KiltRuntime`. +/// * `ProviderDipMerkleHasher`: The provided `KiltDipMerkleHasher`. +/// * `ProviderDidKeyId`: The [`KeyIdOf`] type configured with the provided +/// `KiltRuntime`. +/// * `ProviderAccountId`: The `KiltRuntime::AccountId` type. +/// * `ProviderWeb3Name`: The `KiltRuntime::Web3Name` type. +/// * `ProviderLinkedAccountId`: The [`LinkableAccountId`] type. +/// * `MAX_REVEALED_KEYS_COUNT`: The provided `MAX_REVEALED_KEYS_COUNT`. +/// * `MAX_REVEALED_ACCOUNTS_COUNT`: The provided `MAX_REVEALED_ACCOUNTS_COUNT`. +/// * `LocalContextProvider`: The [`FrameSystemDidSignatureContext`] type +/// configured with the provided `KiltRuntime` and +/// `MAX_DID_SIGNATURE_DURATION`. +/// * `LocalDidCallVerifier`: The provided `LocalDidCallVerifier`. +pub struct KiltVersionedParachainVerifier< + KiltRuntime, + KiltParachainId, + RelayChainStateInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + const MAX_REVEALED_KEYS_COUNT: u32 = 10, + const MAX_REVEALED_ACCOUNTS_COUNT: u32 = 10, + const MAX_DID_SIGNATURE_DURATION: u16 = 50, +>( + PhantomData<( + KiltRuntime, + KiltParachainId, + RelayChainStateInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + )>, +); + +impl< + ConsumerRuntime, + KiltRuntime, + KiltParachainId, + RelayChainStateInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + const MAX_DID_SIGNATURE_DURATION: u16, + > IdentityProofVerifier + for KiltVersionedParachainVerifier< + KiltRuntime, + KiltParachainId, + RelayChainStateInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + MAX_DID_SIGNATURE_DURATION, + > where + KiltRuntime: did::Config + + pallet_web3_names::Config + + pallet_did_lookup::Config + + parachain_info::Config + + pallet_dip_provider::Config, + KiltParachainId: Get, + OutputOf: Ord + From>, + KeyIdOf: Into, + KiltDipMerkleHasher: sp_core::Hasher>, + ConsumerRuntime: pallet_dip_consumer::Config, + ConsumerRuntime::LocalIdentityInfo: Incrementable + Default + Encode, + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, + RelayChainStateInfo::ParaId: From, + RelayChainStateInfo::BlockNumber: Parameter + 'static + Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, + LocalDidCallVerifier: DipCallOriginFilter< + RuntimeCallOf, + OriginInfo = ( + DidVerificationKey, + DidVerificationKeyRelationship, + ), + >, +{ + type Error = DipParachainStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type Proof = VersionedDipParachainStateProof< + RelayChainStateInfo::BlockNumber, + BoundedBlindedValue, + RevealedDidMerkleProofLeaf< + KeyIdOf, + KiltRuntime::AccountId, + BlockNumberFor, + KiltRuntime::Web3Name, + LinkableAccountId, + >, + BlockNumberFor, + >; + type VerificationResult = RevealedDidMerkleProofLeaves< + KeyIdOf, + KiltRuntime::AccountId, + BlockNumberFor, + KiltRuntime::Web3Name, + LinkableAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &ConsumerRuntime::Identifier, + submitter: &ConsumerRuntime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + , + KiltDipMerkleHasher, + KeyIdOf, + KiltRuntime::AccountId, + KiltRuntime::Web3Name, + LinkableAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + FrameSystemDidSignatureContext, + LocalDidCallVerifier, + > as IdentityProofVerifier>::verify_proof_for_call_against_details( + call, + subject, + submitter, + identity_details, + proof, + ) + } +} + +/// Generic proof verifier for KILT-specific DIP identity proofs of different +/// versions coming from a sibling provider running one of the available KILT +/// runtimes. +/// +/// It expects the DIP proof to be a [`VersionedDipParachainStateProof`], +/// and returns [`RevealedDidMerkleProofLeaves`] if the proof is successfully +/// verified. +/// +/// For more info, refer to the version-specific proof identifiers. +pub struct GenericVersionedParachainVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, +>( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + ConsumerRuntime, + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for GenericVersionedParachainVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalContextProvider, + LocalDidCallVerifier, + > where + ConsumerRuntime: pallet_dip_consumer::Config, + ConsumerRuntime::LocalIdentityInfo: Incrementable + Default, + + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, + OutputOf: Ord, + RelayChainStateInfo::BlockNumber: Parameter + 'static + Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, + + SiblingProviderParachainId: Get, + + SiblingProviderStateInfo: traits::ProviderParachainStorageInfo< + Identifier = ConsumerRuntime::Identifier, + Commitment = ProviderDipMerkleHasher::Out, + >, + OutputOf: Ord + From>, + SiblingProviderStateInfo::BlockNumber: Parameter + 'static, + SiblingProviderStateInfo::Commitment: Decode, + SiblingProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: + DidSignatureVerifierContext, Hash = ConsumerRuntime::Hash>, + LocalContextProvider::SignedExtra: Encode, + LocalDidCallVerifier: DipCallOriginFilter< + RuntimeCallOf, + OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship), + >, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Parameter + 'static + Into, + ProviderAccountId: Parameter + 'static, + ProviderLinkedAccountId: Parameter + 'static, + ProviderWeb3Name: Parameter + 'static, +{ + type Error = DipParachainStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type Proof = VersionedDipParachainStateProof< + RelayChainStateInfo::BlockNumber, + BoundedBlindedValue, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + BlockNumberFor, + >; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &ConsumerRuntime::Identifier, + submitter: &ConsumerRuntime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + match proof { + VersionedDipParachainStateProof::V0(v0_proof) => as IdentityProofVerifier>::verify_proof_for_call_against_details( + call, + subject, + submitter, + identity_details, + v0_proof, + ), + } + } +} + +pub mod latest { + pub use super::v0::ParachainDipStateProof; +} + +pub mod v0 { + use super::*; + + use frame_support::Parameter; + use sp_std::borrow::Borrow; + + use crate::{ + did::{verify_did_signature_for_call, RevealedDidKeysAndSignature}, + merkle::verify_dip_merkle_proof, + state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relaychain::ParachainHeadProofVerifier}, + traits::ProviderParachainStorageInfo, + verifier::common::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}, + }; + + /// The expected format of a cross-chain DIP identity proof when the + /// identity information is bridged from a provider that is a sibling + /// of the chain where the information is consumed (i.e., consumer + /// chain). + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] + pub struct ParachainDipStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, + > { + /// The state proof for the given parachain head. + pub(crate) para_state_root: ParachainRootStateProof, + /// The raw state proof for the DIP commitment of the given subject. + pub(crate) dip_identity_commitment: BoundedBlindedValue, + /// The cross-chain DID signature. + pub(crate) did: + DipMerkleProofAndDidSignature, + } + + #[cfg(feature = "runtime-benchmarks")] + impl + kilt_support::traits::GetWorstCase + for ParachainDipStateProof + where + DipMerkleProofBlindedValues: kilt_support::traits::GetWorstCase, + DipMerkleProofRevealedLeaf: Default + Clone, + RelayBlockHeight: Default, + LocalBlockNumber: Default, + Context: Clone, + { + fn worst_case(context: Context) -> Self { + Self { + para_state_root: ParachainRootStateProof::worst_case(context.clone()), + dip_identity_commitment: BoundedBlindedValue::worst_case(context.clone()), + did: DipMerkleProofAndDidSignature::worst_case(context), + } + } + } + + /// Generic proof verifier for KILT-specific DIP identity proofs coming from + /// a sibling provider running one of the available KILT runtimes. + /// + /// The proof verification step is performed on every request, and this + /// specific verifier has no knowledge of caching or storing state about the + /// subject. It only takes the provided + /// `ConsumerRuntime::LocalIdentityInfo` and increases it if the proof is + /// successfully verified, to prevent replay attacks. If additional logic is + /// to be stored under the `ConsumerRuntime::LocalIdentityInfo` entry, a + /// different verifier or a wrapper around this verifier must be built. + /// + /// It expects the DIP proof to be a + /// [`VersionedDipParachainStateProof`], and returns + /// [`RevealedDidMerkleProofLeaves`] if the proof is successfully verified. + /// This information is then made availabe as an origin to the downstream + /// call dispatched. + /// + /// The verifier performs the following steps: + /// 1. Verifies the state proof about the state root of the relaychain block + /// at the provided height. The state root is provided by the + /// `RelayChainInfo` type. + /// 2. Verifies the state proof about the DIP commitment value on the + /// provider parachain at the block finalized at the given relaychain + /// block, using the relay state root validated in the previous step. + /// 3. Verifies the DIP Merkle proof revealing parts of the subject's DID + /// Document against the retrieved DIP commitment validated in the + /// previous step. + /// 4. Verifies the cross-chain DID signature over the payload composed by + /// the SCALE-encoded tuple of `(C, D, S, B, G, E)`, with: + /// * `C`: The `RuntimeCall` to dispatch after performing DIP + /// verification. + /// * `D`: The local details associated to the DID subject as stored in + /// the [`pallet_dip_consumer`] `IdentityEntries` storage map. + /// * `S`: The tx submitter's address. + /// * `B`: The block number of the consumer chain provided in the + /// cross-chain DID signature. + /// * `G`: The genesis hash of the consumer chain. + /// * `E`: Any additional information provided by the + /// `LocalContextProvider` implementation. + /// The generic types + /// indicate the following: + /// * `RelayChainInfo`: The type providing information about the relaychain. + /// * `SiblingProviderParachainId`: The parachain ID of the provider KILT + /// sibling parachain. + /// * `SiblingProviderStateInfo`: The type providing storage and state + /// information about the provider KILT sibling parachain. + /// * `ProviderDipMerkleHasher`: The hashing algorithm used by the KILT + /// parachain for the generation of the DIP identity commitment. + /// * `ProviderDidKeyId`: The runtime type of a DID key ID as defined by the + /// KILT child parachain. + /// * `ProviderAccountId`: The runtime type of an account ID as defined by + /// the KILT child parachain. + /// * `ProviderWeb3Name`: The runtime type of a web3name as defined by the + /// KILT child parachain. + /// * `ProviderLinkedAccountId`: The runtime type of a linked account ID as + /// defined by the KILT child parachain. + /// * `MAX_REVEALED_KEYS_COUNT`: Max number of DID keys that the verifier + /// will accept revealed as part of the DIP identity proof. + /// * `MAX_REVEALED_ACCOUNTS_COUNT`: Max number of linked accounts that the + /// verifier will accept revealed as part of the DIP identity proof. + /// * `LocalContextProvider`: The type providing context of the consumer + /// chain (e.g., current block number) for the sake of cross-chain DID + /// signature verification. + /// * `LocalDidCallVerifier`: Logic to map `RuntimeCall`s to a specific DID + /// key relationship. This information is used once the Merkle proof is + /// verified, to filter only the revealed keys that match the provided + /// relationship. + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] + pub struct ParachainVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, + >( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalContextProvider, + LocalDidCallVerifier, + )>, + ); + + impl< + ConsumerRuntime, + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for ParachainVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalContextProvider, + LocalDidCallVerifier, + > where + ConsumerRuntime: pallet_dip_consumer::Config, + ConsumerRuntime::LocalIdentityInfo: Incrementable + Default, + + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, + OutputOf: Ord, + RelayChainStateInfo::BlockNumber: Parameter + 'static + Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, + + SiblingProviderParachainId: Get, + + SiblingProviderStateInfo: traits::ProviderParachainStorageInfo< + Identifier = ConsumerRuntime::Identifier, + Commitment = ProviderDipMerkleHasher::Out, + >, + OutputOf: Ord + From>, + SiblingProviderStateInfo::BlockNumber: Parameter + 'static, + SiblingProviderStateInfo::Commitment: Decode, + SiblingProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: + DidSignatureVerifierContext, Hash = ConsumerRuntime::Hash>, + LocalContextProvider::SignedExtra: Encode, + LocalDidCallVerifier: DipCallOriginFilter< + RuntimeCallOf, + OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship), + >, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Parameter + 'static + Into, + ProviderAccountId: Parameter + 'static, + ProviderLinkedAccountId: Parameter + 'static, + ProviderWeb3Name: Parameter + 'static, + { + type Error = DipParachainStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type Proof = ParachainDipStateProof< + RelayChainStateInfo::BlockNumber, + BoundedBlindedValue, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + BlockNumberFor, + >; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &ConsumerRuntime::Identifier, + submitter: &ConsumerRuntime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + // 1. Verify parachain state is finalized by relay chain and fresh. + let provider_parachain_header = + ParachainHeadProofVerifier::::verify_proof_for_parachain( + &SiblingProviderParachainId::get(), + &proof.para_state_root.relay_block_height, + proof.para_state_root.proof, + ) + .map_err(DipParachainStateProofVerifierError::ParachainHeadMerkleProof)?; + + // 2. Verify commitment is included in provider parachain. + let subject_identity_commitment = + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + subject, + provider_parachain_header.state_root.into(), + proof.dip_identity_commitment, + ) + .map_err(DipParachainStateProofVerifierError::IdentityCommitmentMerkleProof)?; + + // 3. Verify DIP merkle proof. + let proof_leaves: RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + ::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + > = verify_dip_merkle_proof::< + ProviderDipMerkleHasher, + _, + _, + _, + _, + _, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >(&subject_identity_commitment, proof.did.leaves) + .map_err(DipParachainStateProofVerifierError::DipProof)?; + + // 4. Verify call is signed by one of the DID keys revealed at step 3. + verify_did_signature_for_call::<_, _, _, _, LocalContextProvider, _, _, _, LocalDidCallVerifier>( + call, + submitter, + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.did.signature, + }, + ) + .map_err(DipParachainStateProofVerifierError::DidSignature)?; + + Ok(proof_leaves) + } + } +} diff --git a/crates/kilt-dip-primitives/src/verifier/relaychain.rs b/crates/kilt-dip-primitives/src/verifier/relaychain.rs new file mode 100644 index 000000000..a68dd497f --- /dev/null +++ b/crates/kilt-dip-primitives/src/verifier/relaychain.rs @@ -0,0 +1,805 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use cumulus_primitives_core::ParaId; +use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyIdOf}; +use frame_support::Parameter; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_consumer::{traits::IdentityProofVerifier, RuntimeCallOf}; +use pallet_dip_provider::IdentityCommitmentOf; +use parity_scale_codec::{Codec, Decode, Encode, HasCompact}; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, U256}; +use sp_runtime::traits::{AtLeast32BitUnsigned, Get, Hash, MaybeDisplay, Member, SimpleBitOps}; +use sp_std::marker::PhantomData; + +use crate::{ + did::RevealedDidKeysSignatureAndCallVerifierError, + merkle::{DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifierError, relaychain::ParachainHeadProofVerifierError}, + traits::{ + DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, Incrementable, + ProviderParachainStorageInfo, RelayChainStorageInfo, + }, + utils::OutputOf, + BoundedBlindedValue, FrameSystemDidSignatureContext, ProviderParachainStateInfoViaProviderPallet, +}; + +/// A KILT-specific DIP identity proof for a parent consumer that supports +/// versioning. +/// +/// For more info, refer to the version-specific proofs. +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] +pub enum VersionedRelaychainStateProof< + ParentBlockHeight: Copy + Into + TryFrom, + ParentBlockHasher: Hash, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, +> { + V0( + v0::RelaychainDipStateProof< + ParentBlockHeight, + ParentBlockHasher, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + >, + ), +} + +pub enum DipRelaychainStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, +> { + UnsupportedVersion, + InvalidBlockHeight, + InvalidBlockHash, + ParachainHeadMerkleProof(ParachainHeadMerkleProofVerificationError), + IdentityCommitmentMerkleProof(IdentityCommitmentMerkleProofVerificationError), + DipProof(DipProofVerificationError), + DidSignature(DidSignatureVerificationError), +} + +impl< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + > + From< + DipRelaychainStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + > for u16 +where + ParachainHeadMerkleProofVerificationError: Into, + IdentityCommitmentMerkleProofVerificationError: Into, + DipProofVerificationError: Into, + DidSignatureVerificationError: Into, +{ + fn from( + value: DipRelaychainStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + ) -> Self { + match value { + DipRelaychainStateProofVerifierError::UnsupportedVersion => 0, + DipRelaychainStateProofVerifierError::InvalidBlockHeight => 1, + DipRelaychainStateProofVerifierError::InvalidBlockHash => 2, + DipRelaychainStateProofVerifierError::ParachainHeadMerkleProof(error) => { + u8::MAX as u16 + error.into() as u16 + } + DipRelaychainStateProofVerifierError::IdentityCommitmentMerkleProof(error) => { + u8::MAX as u16 * 2 + error.into() as u16 + } + DipRelaychainStateProofVerifierError::DipProof(error) => u8::MAX as u16 * 3 + error.into() as u16, + DipRelaychainStateProofVerifierError::DidSignature(error) => u8::MAX as u16 * 4 + error.into() as u16, + } + } +} + +/// Proof verifier configured given a specific KILT runtime implementation. +/// +/// A specialization of the +/// [`GenericVersionedRelaychainVerifier`] type, with +/// configurations derived from the provided KILT runtime. +/// +/// The generic types are the following: +/// * `KiltRuntime`: A KILT runtime definition. +/// * `KiltParachainId`: The ID of the specific KILT parachain instance. +/// * `RelayChainInfo`: The type providing information about the consumer +/// (relay)chain. +/// * `KiltDipMerkleHasher`: The hashing algorithm used by the KILT parachain +/// for the generation of the DIP identity commitment. +/// * `LocalDidCallVerifier`: Logic to map `RuntimeCall`s to a specific DID key +/// relationship. This information is used once the Merkle proof is verified, +/// to filter only the revealed keys that match the provided relationship. +/// * `MAX_REVEALED_KEYS_COUNT`: **OPTIONAL** Max number of DID keys that the +/// verifier will accept revealed as part of the DIP identity proof. It +/// defaults to **10**. +/// * `MAX_REVEALED_ACCOUNTS_COUNT`: **OPTIONAL** Max number of linked accounts +/// that the verifier will accept revealed as part of the DIP identity proof. +/// It defaults to **10**. +/// * `MAX_DID_SIGNATURE_DURATION`: **OPTIONAL** Max number of blocks a +/// cross-chain DID signature is considered fresh. It defaults to **50**. +/// +/// It specializes the [`GenericVersionedRelaychainVerifier`] +/// type by using the following types for its generics: +/// * `RelayChainInfo`: The provided `RelayChainInfo`. +/// * `ChildProviderParachainId`: The provided `KiltParachainId`. +/// * `ChildProviderStateInfo`: The +/// [`ProviderParachainStateInfoViaProviderPallet`] type configured with the +/// provided `KiltRuntime`. +/// * `ProviderDipMerkleHasher`: The provided `KiltDipMerkleHasher`. +/// * `ProviderDidKeyId`: The [`KeyIdOf`] type configured with the provided +/// `KiltRuntime`. +/// * `ProviderAccountId`: The `KiltRuntime::AccountId` type. +/// * `ProviderWeb3Name`: The `KiltRuntime::Web3Name` type. +/// * `ProviderLinkedAccountId`: The [`LinkableAccountId`] type. +/// * `MAX_REVEALED_KEYS_COUNT`: The provided `MAX_REVEALED_KEYS_COUNT`. +/// * `MAX_REVEALED_ACCOUNTS_COUNT`: The provided `MAX_REVEALED_ACCOUNTS_COUNT`. +/// * `LocalContextProvider`: The [`FrameSystemDidSignatureContext`] type +/// configured with the provided `KiltRuntime` and +/// `MAX_DID_SIGNATURE_DURATION`. +/// * `LocalDidCallVerifier`: The provided `LocalDidCallVerifier`. +pub struct KiltVersionedRelaychainVerifier< + KiltRuntime, + KiltParachainId, + RelayChainInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + const MAX_REVEALED_KEYS_COUNT: u32 = 10, + const MAX_REVEALED_ACCOUNTS_COUNT: u32 = 10, + const MAX_DID_SIGNATURE_DURATION: u16 = 50, +>( + PhantomData<( + KiltRuntime, + KiltParachainId, + RelayChainInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + )>, +); + +impl< + ConsumerRuntime, + KiltRuntime, + KiltParachainId, + RelayChainInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + const MAX_DID_SIGNATURE_DURATION: u16, + > IdentityProofVerifier + for KiltVersionedRelaychainVerifier< + KiltRuntime, + KiltParachainId, + RelayChainInfo, + KiltDipMerkleHasher, + LocalDidCallVerifier, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + MAX_DID_SIGNATURE_DURATION, + > where + KiltRuntime: did::Config + + pallet_web3_names::Config + + pallet_did_lookup::Config + + parachain_info::Config + + pallet_dip_provider::Config, + KiltParachainId: Get, + OutputOf: Ord + From::Hasher>>, + KeyIdOf: Into, + KiltDipMerkleHasher: sp_core::Hasher>, + ConsumerRuntime: pallet_dip_consumer::Config, + ConsumerRuntime::LocalIdentityInfo: Incrementable + Default + Encode, + RelayChainInfo: RelayChainStorageInfo> + + HistoricalBlockRegistry< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + RelayChainInfo::ParaId: From, + OutputOf<::Hasher>: + Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + ::Hasher: Parameter + 'static, + ::BlockNumber: Copy + + Into + + TryFrom + + HasCompact + + Member + + sp_std::hash::Hash + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec + + Parameter + + 'static, + RelayChainInfo::Key: AsRef<[u8]>, + LocalDidCallVerifier: DipCallOriginFilter< + RuntimeCallOf, + OriginInfo = ( + DidVerificationKey, + DidVerificationKeyRelationship, + ), + >, +{ + type Error = DipRelaychainStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type Proof = VersionedRelaychainStateProof< + ::BlockNumber, + ::Hasher, + BoundedBlindedValue, + RevealedDidMerkleProofLeaf< + KeyIdOf, + KiltRuntime::AccountId, + BlockNumberFor, + KiltRuntime::Web3Name, + LinkableAccountId, + >, + >; + type VerificationResult = RevealedDidMerkleProofLeaves< + KeyIdOf, + KiltRuntime::AccountId, + BlockNumberFor, + KiltRuntime::Web3Name, + LinkableAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &ConsumerRuntime::Identifier, + submitter: &ConsumerRuntime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + , + KiltDipMerkleHasher, + KeyIdOf, + KiltRuntime::AccountId, + KiltRuntime::Web3Name, + LinkableAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + FrameSystemDidSignatureContext, + LocalDidCallVerifier, + > as IdentityProofVerifier>::verify_proof_for_call_against_details( + call, + subject, + submitter, + identity_details, + proof, + ) + } +} + +/// Generic proof verifier for KILT-specific DIP identity proofs of different +/// versions coming from a child provider running one of the available KILT +/// runtimes. +/// +/// It expects the DIP proof to be a [`VersionedRelaychainStateProof`], +/// and returns [`RevealedDidMerkleProofLeaves`] if the proof is successfully +/// verified. +/// +/// For more info, refer to the version-specific proof identifiers. +pub struct GenericVersionedRelaychainVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, +>( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + ConsumerRuntime, + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for GenericVersionedRelaychainVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalContextProvider, + LocalDidCallVerifier, + > where + ConsumerRuntime: pallet_dip_consumer::Config, + ConsumerRuntime::LocalIdentityInfo: Incrementable + Default, + + RelayChainInfo: RelayChainStorageInfo> + + HistoricalBlockRegistry< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + OutputOf<::Hasher>: + Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + ::Hasher: Parameter + 'static, + ::BlockNumber: Copy + + Into + + TryFrom + + HasCompact + + Member + + sp_std::hash::Hash + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec + + Parameter + + 'static, + RelayChainInfo::Key: AsRef<[u8]>, + + ChildProviderParachainId: Get, + + ChildProviderStateInfo: ProviderParachainStorageInfo< + Identifier = ConsumerRuntime::Identifier, + Commitment = ProviderDipMerkleHasher::Out, + >, + OutputOf: Ord + From::Hasher>>, + ChildProviderStateInfo::BlockNumber: Parameter + 'static, + ChildProviderStateInfo::Commitment: Decode, + ChildProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: + DidSignatureVerifierContext, Hash = ConsumerRuntime::Hash>, + LocalContextProvider::SignedExtra: Encode, + LocalDidCallVerifier: DipCallOriginFilter< + RuntimeCallOf, + OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship), + >, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Parameter + 'static + Into, + ProviderAccountId: Parameter + 'static, + ProviderLinkedAccountId: Parameter + 'static, + ProviderWeb3Name: Parameter + 'static, +{ + type Error = DipRelaychainStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type Proof = VersionedRelaychainStateProof< + ::BlockNumber, + ::Hasher, + BoundedBlindedValue, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + >; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &ConsumerRuntime::Identifier, + submitter: &ConsumerRuntime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + match proof { + VersionedRelaychainStateProof::V0(v0_proof) => as IdentityProofVerifier>::verify_proof_for_call_against_details( + call, + subject, + submitter, + identity_details, + v0_proof, + ), + } + } +} + +pub mod latest { + pub use super::v0::RelaychainDipStateProof; +} + +pub mod v0 { + use super::*; + + use parity_scale_codec::Codec; + use sp_runtime::{ + generic::Header, + traits::{AtLeast32BitUnsigned, Hash, MaybeDisplay, Member, SimpleBitOps}, + }; + use sp_std::{borrow::Borrow, vec::Vec}; + + use crate::{ + did::{ + verify_did_signature_for_call, RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifierError, + }, + merkle::{ + verify_dip_merkle_proof, DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, + RevealedDidMerkleProofLeaves, + }, + state_proofs::{ + parachain::{DipIdentityCommitmentProofVerifier, DipIdentityCommitmentProofVerifierError}, + relaychain::{ParachainHeadProofVerifier, ParachainHeadProofVerifierError}, + }, + traits::{ + DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, Incrementable, + ProviderParachainStorageInfo, RelayChainStorageInfo, + }, + utils::OutputOf, + verifier::common::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}, + }; + + /// The expected format of a cross-chain DIP identity proof when the + /// identity information is bridged from a provider that is a child of + /// the chain where the information is consumed (i.e., consumer + /// chain). + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] + pub struct RelaychainDipStateProof< + ParentBlockHeight: Copy + Into + TryFrom, + ParentBlockHasher: Hash, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + > { + /// The state proof for the given parachain head. + para_state_root: ParachainRootStateProof, + /// The relaychain header for the relaychain block specified in the + /// `para_state_root`. + relay_header: Header, + /// The raw state proof for the DIP commitment of the given subject. + dip_identity_commitment: Vec>, + /// The cross-chain DID signature. + did: DipMerkleProofAndDidSignature, + } + + /// Generic proof verifier for KILT-specific DIP identity proofs coming from + /// a child provider running one of the available KILT runtimes. + /// The proof verification step is performed on every request, and this + /// specific verifier has no knowledge of caching or storing state about the + /// subject. It only takes the provided + /// `ConsumerRuntime::LocalIdentityInfo` and increases it if the proof is + /// successfully verified, to prevent replay attacks. If additional logic is + /// to be stored under the `ConsumerRuntime::LocalIdentityInfo` entry, a + /// different verifier or a wrapper around this verifier must be built. + /// + /// It expects the DIP proof to be a + /// [`VersionedRelaychainStateProof`], and returns + /// [`RevealedDidMerkleProofLeaves`] if the proof is successfully verified. + /// This information is then made availabe as an origin to the downstream + /// call dispatched. + /// + /// The verifier performs the following steps: + /// 1. Verifies the state proof about the state root of the relaychain block + /// at the provided height. The state root is retrieved from the provided + /// relaychain header, which is checked to be the header of a + /// previously-finalized relaychain block. + /// 2. Verifies the state proof about the DIP commitment value on the + /// provider parachain at the block finalized at the given relaychain + /// block, using the relay state root validated in the previous step. + /// 3. Verifies the DIP Merkle proof revealing parts of the subject's DID + /// Document against the retrieved DIP commitment validated in the + /// previous step. + /// 4. Verifies the cross-chain DID signature over the payload composed by + /// the SCALE-encoded tuple of `(C, D, S, B, G, E)`, with: + /// * `C`: The `RuntimeCall` to dispatch after performing DIP + /// verification. + /// * `D`: The local details associated to the DID subject as stored in + /// the [`pallet_dip_consumer`] `IdentityEntries` storage map. + /// * `S`: The tx submitter's address. + /// * `B`: The block number of the consumer chain provided in the + /// cross-chain DID signature. + /// * `G`: The genesis hash of the consumer chain. + /// * `E`: Any additional information provided by the + /// `LocalContextProvider` implementation. + /// The generic types + /// indicate the following: + /// * `RelayChainInfo`: The type providing information about the consumer + /// (relay)chain. + /// * `ChildProviderParachainId`: The parachain ID of the provider KILT + /// child parachain. + /// * `ChildProviderStateInfo`: The type providing storage and state + /// information about the provider KILT child parachain. + /// * `ProviderDipMerkleHasher`: The hashing algorithm used by the KILT + /// parachain for the generation of the DIP identity commitment. + /// * `ProviderDidKeyId`: The runtime type of a DID key ID as defined by the + /// KILT child parachain. + /// * `ProviderAccountId`: The runtime type of an account ID as defined by + /// the KILT child parachain. + /// * `ProviderWeb3Name`: The runtime type of a web3name as defined by the + /// KILT child parachain. + /// * `ProviderLinkedAccountId`: The runtime type of a linked account ID as + /// defined by the KILT child parachain. + /// * `MAX_REVEALED_KEYS_COUNT`: Max number of DID keys that the verifier + /// will accept revealed as part of the DIP identity proof. + /// * `MAX_REVEALED_ACCOUNTS_COUNT`: Max number of linked accounts that the + /// verifier will accept revealed as part of the DIP identity proof. + /// * `LocalContextProvider`: The type providing context of the consumer + /// chain (e.g., current block number) for the sake of cross-chain DID + /// signature verification. + /// * `LocalDidCallVerifier`: Logic to map `RuntimeCall`s to a specific DID + /// key relationship. This information is used once the Merkle proof is + /// verified, to filter only the revealed keys that match the provided + /// relationship. + pub struct RelaychainVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, + >( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalContextProvider, + LocalDidCallVerifier, + )>, + ); + + impl< + ConsumerRuntime, + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for RelaychainVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalContextProvider, + LocalDidCallVerifier, + > where + ConsumerRuntime: pallet_dip_consumer::Config, + ConsumerRuntime::LocalIdentityInfo: Incrementable + Default, + + RelayChainInfo: RelayChainStorageInfo> + + HistoricalBlockRegistry< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + ::Hasher: Parameter + 'static, + OutputOf<::Hasher>: + Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + ::BlockNumber: Copy + + Into + + TryFrom + + HasCompact + + Member + + sp_std::hash::Hash + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec + + Parameter + + 'static, + RelayChainInfo::Key: AsRef<[u8]>, + + ChildProviderParachainId: Get, + + ChildProviderStateInfo: ProviderParachainStorageInfo< + Identifier = ConsumerRuntime::Identifier, + Commitment = ProviderDipMerkleHasher::Out, + >, + OutputOf: + Ord + From::Hasher>>, + ChildProviderStateInfo::BlockNumber: Parameter + 'static, + ChildProviderStateInfo::Commitment: Decode, + ChildProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: + DidSignatureVerifierContext, Hash = ConsumerRuntime::Hash>, + LocalContextProvider::SignedExtra: Encode, + LocalDidCallVerifier: DipCallOriginFilter< + RuntimeCallOf, + OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship), + >, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Parameter + 'static + Into, + ProviderAccountId: Parameter + 'static, + ProviderLinkedAccountId: Parameter + 'static, + ProviderWeb3Name: Parameter + 'static, + { + type Error = DipRelaychainStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type Proof = RelaychainDipStateProof< + ::BlockNumber, + ::Hasher, + BoundedBlindedValue, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + >; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &ConsumerRuntime::Identifier, + submitter: &ConsumerRuntime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + // 1. Retrieve block hash from provider at the proof height + let block_hash_at_height = RelayChainInfo::block_hash_for(&proof.para_state_root.relay_block_height) + .ok_or(DipRelaychainStateProofVerifierError::InvalidBlockHeight)?; + + // 1.1 Verify that the provided header hashes to the same block has retrieved + if block_hash_at_height != proof.relay_header.hash() { + return Err(DipRelaychainStateProofVerifierError::InvalidBlockHash); + } + // 1.2 If so, extract the state root from the header + let state_root_at_height = proof.relay_header.state_root; + + // 2. Verify relay chain proof + let provider_parachain_header = + ParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( + &ChildProviderParachainId::get(), + &state_root_at_height, + proof.para_state_root.proof, + ) + .map_err(DipRelaychainStateProofVerifierError::ParachainHeadMerkleProof)?; + + // 3. Verify parachain state proof. + let subject_identity_commitment = + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + subject, + provider_parachain_header.state_root.into(), + proof.dip_identity_commitment, + ) + .map_err(DipRelaychainStateProofVerifierError::IdentityCommitmentMerkleProof)?; + + // 4. Verify DIP merkle proof. + let proof_leaves = verify_dip_merkle_proof::< + ProviderDipMerkleHasher, + _, + _, + _, + _, + _, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >(&subject_identity_commitment, proof.did.leaves) + .map_err(DipRelaychainStateProofVerifierError::DipProof)?; + + // 5. Verify DID signature. + verify_did_signature_for_call::<_, _, _, _, LocalContextProvider, _, _, _, LocalDidCallVerifier>( + call, + submitter, + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.did.signature, + }, + ) + .map_err(DipRelaychainStateProofVerifierError::DidSignature)?; + Ok(proof_leaves) + } + } +} diff --git a/dip-template/nodes/dip-consumer/Cargo.toml b/dip-template/nodes/dip-consumer/Cargo.toml new file mode 100644 index 000000000..76fcdebdc --- /dev/null +++ b/dip-template/nodes/dip-consumer/Cargo.toml @@ -0,0 +1,77 @@ +[package] +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true +name = "dip-consumer-node-template" +description = "Node template for the KILT Decentralized Identity Provider (DIP) consumer." +build = "build.rs" + +[dependencies] +clap = {workspace = true, features = ["std", "derive"]} +futures = { workspace = true } +log = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["std"] } +serde = {workspace = true, features = ["std", "derive"]} +jsonrpsee = {workspace = true, features = ["server"]} + +# Internal dependencies +dip-consumer-runtime-template = { workspace = true, features = ["std"] } + +# Substrate +frame-benchmarking.workspace = true +frame-benchmarking-cli.workspace = true +pallet-transaction-payment-rpc.workspace = true +sc-basic-authorship.workspace = true +sc-chain-spec.workspace = true +sc-cli.workspace = true +sc-client-api.workspace = true +sc-consensus.workspace = true +sc-executor.workspace = true +sc-network.workspace = true +sc-network-sync.workspace = true +sc-offchain.workspace = true +sc-rpc-api.workspace = true +sc-service.workspace = true +sc-sysinfo.workspace = true +sc-telemetry.workspace = true +sc-tracing.workspace = true +sc-transaction-pool.workspace = true +sc-transaction-pool-api.workspace = true +sp-api = { workspace = true, features = ["std"] } +sp-block-builder = { workspace = true, features = ["std"] } +sp-blockchain.workspace = true +sp-consensus-aura = { workspace = true, features = ["std"] } +sp-core = { workspace = true, features = ["std"] } +sp-keystore = { workspace = true, features = ["std"] } +sp-runtime = { workspace = true, features = ["std"] } +sp-timestamp = { workspace = true, features = ["std"] } +substrate-frame-rpc-system.workspace = true +substrate-prometheus-endpoint.workspace = true + +# Polkadot +polkadot-cli.workspace = true +polkadot-primitives = { workspace = true, features = ["std"] } + +# Cumulus +cumulus-client-cli.workspace = true +cumulus-client-consensus-aura.workspace = true +cumulus-client-consensus-common.workspace = true +cumulus-client-service.workspace = true +cumulus-primitives-core = { workspace = true, features = ["std"] } +cumulus-primitives-parachain-inherent = { workspace = true, features = ["std"] } +cumulus-relay-chain-interface.workspace = true + +[build-dependencies] +substrate-build-script-utils.workspace = true + +[features] +default = [] +runtime-benchmarks = [ + "frame-benchmarking-cli/runtime-benchmarks", + "dip-consumer-runtime-template/runtime-benchmarks", +] diff --git a/dip-template/nodes/dip-consumer/build.rs b/dip-template/nodes/dip-consumer/build.rs new file mode 100644 index 000000000..961231c47 --- /dev/null +++ b/dip-template/nodes/dip-consumer/build.rs @@ -0,0 +1,25 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; + +fn main() { + generate_cargo_keys(); + + rerun_if_git_head_changed(); +} diff --git a/dip-template/nodes/dip-consumer/src/chain_spec.rs b/dip-template/nodes/dip-consumer/src/chain_spec.rs new file mode 100644 index 000000000..5494ee79d --- /dev/null +++ b/dip-template/nodes/dip-consumer/src/chain_spec.rs @@ -0,0 +1,146 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use cumulus_primitives_core::ParaId; +use dip_consumer_runtime_template::{ + AccountId, AuraId, BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, RuntimeGenesisConfig, + SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, EXISTENTIAL_DEPOSIT, SS58_PREFIX, WASM_BINARY, +}; +use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, Properties}; +use sc_service::{ChainType, GenericChainSpec}; +use serde::{Deserialize, Serialize}; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +const PARA_ID: u32 = 2_001; + +pub type ChainSpec = GenericChainSpec; +type AccountPublic = ::Signer; + +pub(crate) fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] +#[serde(deny_unknown_fields)] +pub struct Extensions { + pub relay_chain: String, + pub para_id: u32, +} + +impl Extensions { + pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { + sc_chain_spec::get_extension(chain_spec.extensions()) + } +} + +pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { + get_from_seed::(seed) +} + +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +pub fn template_session_keys(keys: AuraId) -> SessionKeys { + SessionKeys { aura: keys } +} + +fn testnet_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, +) -> RuntimeGenesisConfig { + RuntimeGenesisConfig { + system: SystemConfig { + code: WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + ..Default::default() + }, + parachain_system: Default::default(), + parachain_info: ParachainInfoConfig { + parachain_id: id, + ..Default::default() + }, + sudo: SudoConfig { + key: Some(endowed_accounts.first().unwrap().clone()), + }, + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + transaction_payment: Default::default(), + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: EXISTENTIAL_DEPOSIT * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| (acc.clone(), acc, template_session_keys(aura))) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + } +} + +pub fn development_config() -> ChainSpec { + let mut properties = Properties::new(); + properties.insert("tokenSymbol".into(), "REILT".into()); + properties.insert("tokenDecimals".into(), 12.into()); + properties.insert("ss58Format".into(), SS58_PREFIX.into()); + + ChainSpec::from_genesis( + "DIP consumer dev", + "dip-consumer-dev", + ChainType::Development, + move || { + testnet_genesis( + vec![( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed("Alice"), + )], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Charlie//stash"), + ], + PARA_ID.into(), + ) + }, + Vec::new(), + None, + "dip-consumer-dev".into(), + None, + None, + Extensions { + relay_chain: "rococo-local".into(), + para_id: PARA_ID, + }, + ) +} diff --git a/dip-template/nodes/dip-consumer/src/cli.rs b/dip-template/nodes/dip-consumer/src/cli.rs new file mode 100644 index 000000000..da4f53612 --- /dev/null +++ b/dip-template/nodes/dip-consumer/src/cli.rs @@ -0,0 +1,92 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use std::path::PathBuf; + +use cumulus_client_cli::{ExportGenesisStateCommand, ExportGenesisWasmCommand, PurgeChainCmd}; +use polkadot_cli::RunCmd; +use sc_cli::{BuildSpecCmd, CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; +use sc_service::Configuration; + +use crate::chain_spec::Extensions; + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, clap::Subcommand)] +pub enum Subcommand { + BuildSpec(BuildSpecCmd), + + CheckBlock(CheckBlockCmd), + + ExportBlocks(ExportBlocksCmd), + + ExportState(ExportStateCmd), + + ImportBlocks(ImportBlocksCmd), + + Revert(RevertCmd), + + PurgeChain(PurgeChainCmd), + + ExportGenesisState(ExportGenesisStateCommand), + + ExportGenesisWasm(ExportGenesisWasmCommand), + #[command(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} + +#[derive(Debug, clap::Parser)] +#[command( + propagate_version = true, + args_conflicts_with_subcommands = true, + subcommand_negates_reqs = true +)] +pub struct Cli { + #[command(subcommand)] + pub subcommand: Option, + + #[command(flatten)] + pub run: cumulus_client_cli::RunCmd, + + #[arg(long)] + pub no_hardware_benchmarks: bool, + + #[arg(raw = true)] + pub relay_chain_args: Vec, +} + +#[derive(Debug)] +pub struct RelayChainCli { + pub base: RunCmd, + + pub chain_id: Option, + + pub base_path: Option, +} + +impl RelayChainCli { + pub fn new<'a>(para_config: &Configuration, relay_chain_args: impl Iterator) -> Self { + let extension = Extensions::try_get(&*para_config.chain_spec); + let chain_id = extension.map(|e| e.relay_chain.clone()); + let base_path = Some(para_config.base_path.path().join("polkadot")); + Self { + base_path, + chain_id, + base: clap::Parser::parse_from(relay_chain_args), + } + } +} diff --git a/dip-template/nodes/dip-consumer/src/command.rs b/dip-template/nodes/dip-consumer/src/command.rs new file mode 100644 index 000000000..f41f3c337 --- /dev/null +++ b/dip-template/nodes/dip-consumer/src/command.rs @@ -0,0 +1,410 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use std::{fs::create_dir_all, net::SocketAddr}; + +use cumulus_primitives_core::ParaId; +use dip_consumer_runtime_template::Block; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; +use log::{info, warn}; +use sc_cli::{ + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, LoggerBuilder, + NetworkParams, Result, SharedParams, SubstrateCli, +}; +use sc_service::{ + config::{BasePath, PrometheusConfig}, + Configuration, Role, RpcMethods, TransactionPoolOptions, +}; +use sc_sysinfo::gather_hwbench; +use sc_telemetry::TelemetryEndpoints; +use sp_runtime::traits::AccountIdConversion; + +use crate::{ + chain_spec::{development_config, ChainSpec as ConsumerChainSpec, Extensions}, + cli::{Cli, RelayChainCli, Subcommand}, + service::{new_partial, start_parachain_node}, +}; + +fn load_spec(id: &str) -> std::result::Result, String> { + match id { + "dev" | "" => Ok(Box::new(development_config())), + path => Ok(Box::new(ConsumerChainSpec::from_json_file(std::path::PathBuf::from( + path, + ))?)), + } +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "DIP Consumer Node Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + format!( + "DIP Consumer Node Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relay chain node.\n\n\ + {} -- ", + Self::executable_name() + ) + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/kiltprotocol/kilt-node/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2023 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + load_spec(id) + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + "DIP Consumer Node Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + format!( + "DIP Consumer Node Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relay chain node.\n\n\ + {} -- ", + Self::executable_name() + ) + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/kiltprotocol/kilt-node/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2023 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) + } +} + +macro_rules! construct_async_run { + (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ + let runner = $cli.create_runner($cmd)?; + runner.async_run(|$config| { + let $components = new_partial(&$config)?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) + }} +} + +pub fn run() -> Result<()> { + let cli = Cli::from_args(); + + 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)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + } + Some(Subcommand::ExportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok(cmd.run(components.client, config.database))) + } + Some(Subcommand::ExportState(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok(cmd.run(components.client, config.chain_spec))) + } + Some(Subcommand::ImportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + } + Some(Subcommand::Revert(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.backend, None)) + }) + } + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()] + .iter() + .chain(cli.relay_chain_args.iter()), + ); + + let polkadot_config = + SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, config.tokio_handle.clone()) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + cmd.run(config, polkadot_config) + }) + } + Some(Subcommand::ExportGenesisState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| { + let partials = new_partial(&config)?; + cmd.run(&*config.chain_spec, &*partials.client) + }) + } + Some(Subcommand::ExportGenesisWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|_config| { + let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; + cmd.run(&*spec) + }) + } + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => { + if cfg!(feature = "runtime-benchmarks") { + 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()) + } + } + BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { + let partials = new_partial(&config)?; + cmd.run(partials.client) + }), + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => { + return Err(sc_cli::Error::Input( + "Compile with --features=runtime-benchmarks \ + to enable storage benchmarks." + .into(), + ) + .into()) + } + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { + let partials = new_partial(&config)?; + let db = partials.backend.expose_db(); + let storage = partials.backend.expose_storage(); + cmd.run(config, partials.client.clone(), db, storage) + }), + BenchmarkCmd::Machine(cmd) => { + runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())) + } + #[allow(unreachable_patterns)] + _ => Err("Benchmarking sub-command unsupported".into()), + } + } + None => { + let runner = cli.create_runner(&cli.run.normalize())?; + let collator_options = cli.run.collator_options(); + + runner.run_node_until_exit(|config| async move { + let hwbench = (!cli.no_hardware_benchmarks) + .then_some(config.database.path().map(|database_path| { + let _ = create_dir_all(database_path); + gather_hwbench(Some(database_path)) + })) + .flatten(); + + let para_id = Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or("Could not find parachain ID in chain-spec.")?; + + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()] + .iter() + .chain(cli.relay_chain_args.iter()), + ); + + let id = ParaId::from(para_id); + + let parachain_account = + AccountIdConversion::::into_account_truncating(&id); + + let tokio_handle = config.tokio_handle.clone(); + let polkadot_config = SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + info!("Parachain Account: {}", parachain_account); + info!( + "Is collating: {}", + if config.role.is_authority() { "yes" } else { "no" } + ); + + if !collator_options.relay_chain_rpc_urls.is_empty() && cli.relay_chain_args.is_empty() { + warn!( + "Detected relay chain node arguments together with --relay-chain-rpc-url. \ + This command starts a minimal Polkadot node that only uses a \ + network-related subset of all relay chain CLI options." + ); + } + + start_parachain_node(config, polkadot_config, collator_options, id, hwbench) + .await + .map(|r| r.0) + .map_err(Into::into) + }) + } + } +} + +impl DefaultConfigurationValues for RelayChainCli { + fn p2p_listen_port() -> u16 { + 30334 + } + + fn rpc_listen_port() -> u16 { + 9945 + } + + fn prometheus_listen_port() -> u16 { + 9616 + } +} + +impl CliConfiguration for RelayChainCli { + fn shared_params(&self) -> &SharedParams { + self.base.base.shared_params() + } + + fn import_params(&self) -> Option<&ImportParams> { + self.base.base.import_params() + } + + fn network_params(&self) -> Option<&NetworkParams> { + self.base.base.network_params() + } + + fn keystore_params(&self) -> Option<&KeystoreParams> { + self.base.base.keystore_params() + } + + fn base_path(&self) -> Result> { + Ok(self + .shared_params() + .base_path()? + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_addr(&self, default_listen_port: u16) -> Result> { + self.base.base.rpc_addr(default_listen_port) + } + + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> Result> { + self.base.base.prometheus_config(default_listen_port, chain_spec) + } + + fn init( + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + _config: &Configuration, + ) -> Result<()> + where + F: FnOnce(&mut LoggerBuilder, &Configuration), + { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> Result { + let chain_id = self.base.base.chain_id(is_dev)?; + + Ok(if chain_id.is_empty() { + self.chain_id.clone().unwrap_or_default() + } else { + chain_id + }) + } + + fn role(&self, is_dev: bool) -> Result { + self.base.base.role(is_dev) + } + + fn transaction_pool(&self, is_dev: bool) -> Result { + self.base.base.transaction_pool(is_dev) + } + + fn trie_cache_maximum_size(&self) -> Result> { + self.base.base.trie_cache_maximum_size() + } + + fn rpc_methods(&self) -> Result { + self.base.base.rpc_methods() + } + + fn rpc_max_connections(&self) -> Result { + self.base.base.rpc_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> Result>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> Result> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> Result { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> Result { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> Result> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> Result { + self.base.base.announce_block() + } + + fn telemetry_endpoints(&self, chain_spec: &Box) -> Result> { + self.base.base.telemetry_endpoints(chain_spec) + } +} diff --git a/dip-template/nodes/dip-consumer/src/main.rs b/dip-template/nodes/dip-consumer/src/main.rs new file mode 100644 index 000000000..21ec9b13e --- /dev/null +++ b/dip-template/nodes/dip-consumer/src/main.rs @@ -0,0 +1,32 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! KILT Decentralized Identity Provider (DIP) consumer CLI. + +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; +mod rpc; + +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/dip-template/nodes/dip-consumer/src/rpc.rs b/dip-template/nodes/dip-consumer/src/rpc.rs new file mode 100644 index 000000000..56dabbeaf --- /dev/null +++ b/dip-template/nodes/dip-consumer/src/rpc.rs @@ -0,0 +1,70 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![warn(missing_docs)] + +pub use sc_rpc_api::DenyUnsafe; +use substrate_frame_rpc_system::AccountNonceApi; + +use std::{error::Error, sync::Arc}; + +use dip_consumer_runtime_template::{AccountId, Balance, NodeBlock as Block, Nonce}; +use jsonrpsee::RpcModule; +use pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi; +use sc_client_api::AuxStore; +use sc_transaction_pool_api::TransactionPool; +use sp_api::ProvideRuntimeApi; +use sp_block_builder::BlockBuilder; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; + +pub type RpcExtension = RpcModule<()>; + +pub struct FullDeps { + pub client: Arc, + pub pool: Arc

, + pub deny_unsafe: DenyUnsafe, +} + +pub fn create_full(deps: FullDeps) -> Result> +where + C: ProvideRuntimeApi + + HeaderBackend + + AuxStore + + HeaderMetadata + + Send + + Sync + + 'static, + C::Api: TransactionPaymentRuntimeApi, + C::Api: AccountNonceApi, + C::Api: BlockBuilder, + P: TransactionPool + Sync + Send + 'static, +{ + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use substrate_frame_rpc_system::{System, SystemApiServer}; + + let mut module = RpcExtension::new(()); + let FullDeps { + client, + pool, + deny_unsafe, + } = deps; + + module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(TransactionPayment::new(client).into_rpc())?; + Ok(module) +} diff --git a/dip-template/nodes/dip-consumer/src/service.rs b/dip-template/nodes/dip-consumer/src/service.rs new file mode 100644 index 000000000..658759005 --- /dev/null +++ b/dip-template/nodes/dip-consumer/src/service.rs @@ -0,0 +1,428 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use std::{error::Error, sync::Arc, time::Duration}; + +use cumulus_client_cli::CollatorOptions; +use cumulus_client_consensus_aura::{ + import_queue, slot_duration, AuraConsensus, BuildAuraConsensusParams, ImportQueueParams, SlotProportion, +}; +use cumulus_client_consensus_common::{ParachainBlockImport as TParachainBlockImport, ParachainConsensus}; +use cumulus_client_service::{ + build_network, build_relay_chain_interface, prepare_node_config, start_collator, start_full_node, + BuildNetworkParams, StartCollatorParams, StartFullNodeParams, +}; +use cumulus_primitives_core::ParaId; +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use cumulus_relay_chain_interface::RelayChainInterface; +use dip_consumer_runtime_template::{api, native_version, NodeBlock as Block, RuntimeApi}; +use frame_benchmarking::benchmarking::HostFunctions; +use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; +use sc_basic_authorship::ProposerFactory; +use sc_client_api::Backend; +use sc_consensus::{DefaultImportQueue, ImportQueue}; +use sc_executor::NativeElseWasmExecutor; +use sc_network::NetworkBlock; +use sc_network_sync::SyncingService; +use sc_service::{ + new_full_parts, spawn_tasks, Configuration, PartialComponents, SpawnTasksParams, TFullBackend, TFullClient, + TaskManager, +}; +use sc_sysinfo::{initialize_hwbench_telemetry, print_hwbench, HwBench}; +use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sc_transaction_pool::{BasicPool, FullPool}; +use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use sp_keystore::KeystorePtr; +use substrate_prometheus_endpoint::Registry; + +use crate::rpc::{create_full, FullDeps}; + +pub struct ParachainNativeExecutor; + +impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor { + type ExtendHostFunctions = HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + native_version() + } +} + +type ParachainExecutor = NativeElseWasmExecutor; +type ParachainClient = TFullClient; +type ParachainBackend = TFullBackend; +type ParachainBlockImport = TParachainBlockImport, ParachainBackend>; + +#[allow(clippy::type_complexity)] +pub fn new_partial( + config: &Configuration, +) -> Result< + PartialComponents< + ParachainClient, + ParachainBackend, + (), + DefaultImportQueue, + FullPool, + (ParachainBlockImport, Option, Option), + >, + sc_service::Error, +> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let executor = sc_service::new_native_or_wasm_executor(config); + + let (client, backend, keystore_container, task_manager) = new_full_parts::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let import_queue = build_import_queue( + client.clone(), + block_import.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + Ok(PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (block_import, telemetry, telemetry_worker_handle), + }) +} + +#[sc_tracing::logging::prefix_logs_with("Parachain")] +async fn start_node_impl( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc)> { + let parachain_config = prepare_node_config(parachain_config); + + let params = new_partial(¶chain_config)?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + let mut task_manager = params.task_manager; + + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let force_authoring = parachain_config.force_authoring; + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = sc_network::config::FullNetworkConfiguration::new(¶chain_config.network); + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + net_config, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + }) + .await?; + + if parachain_config.offchain_worker.enabled { + use futures::FutureExt; + + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-work", + sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { + runtime_api_provider: client.clone(), + keystore: Some(params.keystore_container.keystore()), + offchain_db: backend.offchain_storage(), + transaction_pool: Some(OffchainTransactionPoolFactory::new(transaction_pool.clone())), + network_provider: network.clone(), + is_validator: parachain_config.role.is_authority(), + enable_http_requests: false, + custom_extensions: move |_| vec![], + }) + .run(client.clone(), task_manager.spawn_handle()) + .boxed(), + ); + } + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + + Box::new(move |deny_unsafe, _| { + let deps = FullDeps { + client: client.clone(), + pool: transaction_pool.clone(), + deny_unsafe, + }; + + create_full(deps).map_err(Into::into) + }) + }; + + spawn_tasks(SpawnTasksParams { + rpc_builder, + sync_service: sync_service.clone(), + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend, + network: network.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + print_hwbench(&hwbench); + if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && validator { + log::warn!("⚠️ The hardware does not meet the minimal requirements for role 'Authority'."); + } + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let sync = sync_service.clone(); + Arc::new(move |hash, data| sync.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + if validator { + let parachain_consensus = build_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + sync_service.clone(), + params.keystore_container.keystore(), + force_authoring, + para_id, + )?; + + let spawner = task_manager.spawn_handle(); + let params = StartCollatorParams { + para_id, + block_status: client.clone(), + announce_block, + client: client.clone(), + task_manager: &mut task_manager, + relay_chain_interface, + sync_service: sync_service.clone(), + spawner, + parachain_consensus, + import_queue: import_queue_service, + collator_key: collator_key.expect("Command line arguments do not allow this. qed"), + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle), + }; + + start_collator(params).await?; + } else { + let params = StartFullNodeParams { + client: client.clone(), + announce_block, + task_manager: &mut task_manager, + para_id, + relay_chain_interface, + sync_service, + relay_chain_slot_duration, + import_queue: import_queue_service, + recovery_handle: Box::new(overseer_handle), + }; + + start_full_node(params)?; + } + + start_network.start_network(); + + Ok((task_manager, client)) +} + +fn build_import_queue( + client: Arc, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> { + let slot_duration = slot_duration(&*client)?; + + import_queue::(ImportQueueParams { + block_import, + client, + create_inherent_data_providers: move |_, _| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + registry: config.prometheus_registry(), + spawner: &task_manager.spawn_essential_handle(), + telemetry, + }) + .map_err(Into::into) +} + +#[allow(clippy::too_many_arguments)] +fn build_consensus( + client: Arc, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>, + sync_oracle: Arc>, + keystore: KeystorePtr, + force_authoring: bool, + para_id: ParaId, +) -> Result>, sc_service::Error> { + let slot_duration = slot_duration(&*client)?; + + let proposer_factory = ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let params = BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = + ParachainInherentData::create_at(relay_parent, &relay_chain_interface, &validation_data, para_id) + .await; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + let parachain_inherent = parachain_inherent + .ok_or_else(|| Box::::from("Failed to create parachain inherent"))?; + Ok((slot, timestamp, parachain_inherent)) + } + }, + block_import, + para_client: client, + backoff_authoring_blocks: Option::<()>::None, + sync_oracle, + keystore, + force_authoring, + slot_duration, + block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), + max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), + telemetry, + }; + + Ok(AuraConsensus::build::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + _, + >(params)) +} + +pub async fn start_parachain_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc)> { + start_node_impl(parachain_config, polkadot_config, collator_options, para_id, hwbench).await +} diff --git a/dip-template/nodes/dip-provider/Cargo.toml b/dip-template/nodes/dip-provider/Cargo.toml new file mode 100644 index 000000000..6ca76df48 --- /dev/null +++ b/dip-template/nodes/dip-provider/Cargo.toml @@ -0,0 +1,77 @@ +[package] +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true +name = "dip-provider-node-template" +description = "Node template for the KILT Decentralized Identity Provider (DIP) provider." +build = "build.rs" + +[dependencies] +clap = {workspace = true, features = ["std", "derive"]} +futures = { workspace = true } +log = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["std"] } +serde = {workspace = true, features = ["std", "derive"]} +jsonrpsee = {workspace = true, features = ["server"]} + +# Internal dependencies +dip-provider-runtime-template = { workspace = true, features = ["std"] } + +# Substrate +frame-benchmarking.workspace = true +frame-benchmarking-cli.workspace = true +pallet-transaction-payment-rpc.workspace = true +sc-basic-authorship.workspace = true +sc-chain-spec.workspace = true +sc-cli.workspace = true +sc-client-api.workspace = true +sc-consensus.workspace = true +sc-executor.workspace = true +sc-network.workspace = true +sc-network-sync.workspace = true +sc-offchain.workspace = true +sc-rpc-api.workspace = true +sc-service.workspace = true +sc-sysinfo.workspace = true +sc-telemetry.workspace = true +sc-tracing.workspace = true +sc-transaction-pool.workspace = true +sc-transaction-pool-api.workspace = true +sp-api = { workspace = true, features = ["std"] } +sp-block-builder = { workspace = true, features = ["std"] } +sp-blockchain.workspace = true +sp-consensus-aura = { workspace = true, features = ["std"] } +sp-core = { workspace = true, features = ["std"] } +sp-keystore = { workspace = true, features = ["std"] } +sp-runtime = { workspace = true, features = ["std"] } +sp-timestamp = { workspace = true, features = ["std"] } +substrate-frame-rpc-system.workspace = true +substrate-prometheus-endpoint.workspace = true + +# Polkadot +polkadot-cli.workspace = true +polkadot-primitives = { workspace = true, features = ["std"] } + +# Cumulus +cumulus-client-cli.workspace = true +cumulus-client-consensus-aura.workspace = true +cumulus-client-consensus-common.workspace = true +cumulus-client-service.workspace = true +cumulus-primitives-core = { workspace = true, features = ["std"] } +cumulus-primitives-parachain-inherent = { workspace = true, features = ["std"] } +cumulus-relay-chain-interface.workspace = true + +[build-dependencies] +substrate-build-script-utils.workspace = true + +[features] +default = [] +runtime-benchmarks = [ + "frame-benchmarking-cli/runtime-benchmarks", + "dip-provider-runtime-template/runtime-benchmarks" +] diff --git a/dip-template/nodes/dip-provider/build.rs b/dip-template/nodes/dip-provider/build.rs new file mode 100644 index 000000000..961231c47 --- /dev/null +++ b/dip-template/nodes/dip-provider/build.rs @@ -0,0 +1,25 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; + +fn main() { + generate_cargo_keys(); + + rerun_if_git_head_changed(); +} diff --git a/dip-template/nodes/dip-provider/src/chain_spec.rs b/dip-template/nodes/dip-provider/src/chain_spec.rs new file mode 100644 index 000000000..a6f54068a --- /dev/null +++ b/dip-template/nodes/dip-provider/src/chain_spec.rs @@ -0,0 +1,147 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use cumulus_primitives_core::ParaId; +use dip_provider_runtime_template::{ + AccountId, AuraId, BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, RuntimeGenesisConfig, + SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, EXISTENTIAL_DEPOSIT, SS58_PREFIX, WASM_BINARY, +}; +use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, Properties}; +use sc_service::{ChainType, GenericChainSpec}; +use serde::{Deserialize, Serialize}; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +const PARA_ID: u32 = 2_000; + +pub type ChainSpec = GenericChainSpec; +type AccountPublic = ::Signer; + +pub(crate) fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] +#[serde(deny_unknown_fields)] +pub struct Extensions { + pub relay_chain: String, + pub para_id: u32, +} + +impl Extensions { + pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { + sc_chain_spec::get_extension(chain_spec.extensions()) + } +} + +pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { + get_from_seed::(seed) +} + +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +pub fn template_session_keys(keys: AuraId) -> SessionKeys { + SessionKeys { aura: keys } +} + +fn testnet_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, +) -> RuntimeGenesisConfig { + RuntimeGenesisConfig { + system: SystemConfig { + code: WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + ..Default::default() + }, + parachain_system: Default::default(), + parachain_info: ParachainInfoConfig { + parachain_id: id, + ..Default::default() + }, + sudo: SudoConfig { + key: Some(endowed_accounts.first().unwrap().clone()), + }, + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + transaction_payment: Default::default(), + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: EXISTENTIAL_DEPOSIT * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| (acc.clone(), acc, template_session_keys(aura))) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + did_lookup: Default::default(), + } +} + +pub fn development_config() -> ChainSpec { + let mut properties = Properties::new(); + properties.insert("tokenSymbol".into(), "SEILT".into()); + properties.insert("tokenDecimals".into(), 12.into()); + properties.insert("ss58Format".into(), SS58_PREFIX.into()); + + ChainSpec::from_genesis( + "DIP provider dev", + "dip-provider-dev", + ChainType::Development, + move || { + testnet_genesis( + vec![( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed("Alice"), + )], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Charlie//stash"), + ], + PARA_ID.into(), + ) + }, + Vec::new(), + None, + "dip-provider-dev".into(), + None, + None, + Extensions { + relay_chain: "rococo-local".into(), + para_id: PARA_ID, + }, + ) +} diff --git a/dip-template/nodes/dip-provider/src/cli.rs b/dip-template/nodes/dip-provider/src/cli.rs new file mode 100644 index 000000000..da4f53612 --- /dev/null +++ b/dip-template/nodes/dip-provider/src/cli.rs @@ -0,0 +1,92 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use std::path::PathBuf; + +use cumulus_client_cli::{ExportGenesisStateCommand, ExportGenesisWasmCommand, PurgeChainCmd}; +use polkadot_cli::RunCmd; +use sc_cli::{BuildSpecCmd, CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; +use sc_service::Configuration; + +use crate::chain_spec::Extensions; + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, clap::Subcommand)] +pub enum Subcommand { + BuildSpec(BuildSpecCmd), + + CheckBlock(CheckBlockCmd), + + ExportBlocks(ExportBlocksCmd), + + ExportState(ExportStateCmd), + + ImportBlocks(ImportBlocksCmd), + + Revert(RevertCmd), + + PurgeChain(PurgeChainCmd), + + ExportGenesisState(ExportGenesisStateCommand), + + ExportGenesisWasm(ExportGenesisWasmCommand), + #[command(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} + +#[derive(Debug, clap::Parser)] +#[command( + propagate_version = true, + args_conflicts_with_subcommands = true, + subcommand_negates_reqs = true +)] +pub struct Cli { + #[command(subcommand)] + pub subcommand: Option, + + #[command(flatten)] + pub run: cumulus_client_cli::RunCmd, + + #[arg(long)] + pub no_hardware_benchmarks: bool, + + #[arg(raw = true)] + pub relay_chain_args: Vec, +} + +#[derive(Debug)] +pub struct RelayChainCli { + pub base: RunCmd, + + pub chain_id: Option, + + pub base_path: Option, +} + +impl RelayChainCli { + pub fn new<'a>(para_config: &Configuration, relay_chain_args: impl Iterator) -> Self { + let extension = Extensions::try_get(&*para_config.chain_spec); + let chain_id = extension.map(|e| e.relay_chain.clone()); + let base_path = Some(para_config.base_path.path().join("polkadot")); + Self { + base_path, + chain_id, + base: clap::Parser::parse_from(relay_chain_args), + } + } +} diff --git a/dip-template/nodes/dip-provider/src/command.rs b/dip-template/nodes/dip-provider/src/command.rs new file mode 100644 index 000000000..3fb8b8322 --- /dev/null +++ b/dip-template/nodes/dip-provider/src/command.rs @@ -0,0 +1,410 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use std::{fs::create_dir_all, net::SocketAddr}; + +use cumulus_primitives_core::ParaId; +use dip_provider_runtime_template::Block; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; +use log::{info, warn}; +use sc_cli::{ + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, LoggerBuilder, + NetworkParams, Result, SharedParams, SubstrateCli, +}; +use sc_service::{ + config::{BasePath, PrometheusConfig}, + Configuration, Role, RpcMethods, TransactionPoolOptions, +}; +use sc_sysinfo::gather_hwbench; +use sc_telemetry::TelemetryEndpoints; +use sp_runtime::traits::AccountIdConversion; + +use crate::{ + chain_spec::{development_config, ChainSpec as ProviderChainSpec, Extensions}, + cli::{Cli, RelayChainCli, Subcommand}, + service::{new_partial, start_parachain_node}, +}; + +fn load_spec(id: &str) -> std::result::Result, String> { + match id { + "dev" | "" => Ok(Box::new(development_config())), + path => Ok(Box::new(ProviderChainSpec::from_json_file(std::path::PathBuf::from( + path, + ))?)), + } +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "DIP Provider Node Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + format!( + "DIP Provider Node Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relay chain node.\n\n\ + {} -- ", + Self::executable_name() + ) + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/kiltprotocol/kilt-node/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2023 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + load_spec(id) + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + "DIP Provider Node Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + format!( + "DIP Provider Node Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relay chain node.\n\n\ + {} -- ", + Self::executable_name() + ) + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/kiltprotocol/kilt-node/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2023 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) + } +} + +macro_rules! construct_async_run { + (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ + let runner = $cli.create_runner($cmd)?; + runner.async_run(|$config| { + let $components = new_partial(&$config)?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) + }} +} + +pub fn run() -> Result<()> { + let cli = Cli::from_args(); + + 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)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + } + Some(Subcommand::ExportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok(cmd.run(components.client, config.database))) + } + Some(Subcommand::ExportState(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok(cmd.run(components.client, config.chain_spec))) + } + Some(Subcommand::ImportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + } + Some(Subcommand::Revert(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.backend, None)) + }) + } + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()] + .iter() + .chain(cli.relay_chain_args.iter()), + ); + + let polkadot_config = + SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, config.tokio_handle.clone()) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + cmd.run(config, polkadot_config) + }) + } + Some(Subcommand::ExportGenesisState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| { + let partials = new_partial(&config)?; + cmd.run(&*config.chain_spec, &*partials.client) + }) + } + Some(Subcommand::ExportGenesisWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|_config| { + let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; + cmd.run(&*spec) + }) + } + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => { + if cfg!(feature = "runtime-benchmarks") { + 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()) + } + } + BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { + let partials = new_partial(&config)?; + cmd.run(partials.client) + }), + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => { + return Err(sc_cli::Error::Input( + "Compile with --features=runtime-benchmarks \ + to enable storage benchmarks." + .into(), + ) + .into()) + } + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { + let partials = new_partial(&config)?; + let db = partials.backend.expose_db(); + let storage = partials.backend.expose_storage(); + cmd.run(config, partials.client.clone(), db, storage) + }), + BenchmarkCmd::Machine(cmd) => { + runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())) + } + #[allow(unreachable_patterns)] + _ => Err("Benchmarking sub-command unsupported".into()), + } + } + None => { + let runner = cli.create_runner(&cli.run.normalize())?; + let collator_options = cli.run.collator_options(); + + runner.run_node_until_exit(|config| async move { + let hwbench = (!cli.no_hardware_benchmarks) + .then_some(config.database.path().map(|database_path| { + let _ = create_dir_all(database_path); + gather_hwbench(Some(database_path)) + })) + .flatten(); + + let para_id = Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or("Could not find parachain ID in chain-spec.")?; + + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()] + .iter() + .chain(cli.relay_chain_args.iter()), + ); + + let id = ParaId::from(para_id); + + let parachain_account = + AccountIdConversion::::into_account_truncating(&id); + + let tokio_handle = config.tokio_handle.clone(); + let polkadot_config = SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + info!("Parachain Account: {}", parachain_account); + info!( + "Is collating: {}", + if config.role.is_authority() { "yes" } else { "no" } + ); + + if !collator_options.relay_chain_rpc_urls.is_empty() && cli.relay_chain_args.is_empty() { + warn!( + "Detected relay chain node arguments together with --relay-chain-rpc-url. \ + This command starts a minimal Polkadot node that only uses a \ + network-related subset of all relay chain CLI options." + ); + } + + start_parachain_node(config, polkadot_config, collator_options, id, hwbench) + .await + .map(|r| r.0) + .map_err(Into::into) + }) + } + } +} + +impl DefaultConfigurationValues for RelayChainCli { + fn p2p_listen_port() -> u16 { + 30334 + } + + fn rpc_listen_port() -> u16 { + 9945 + } + + fn prometheus_listen_port() -> u16 { + 9616 + } +} + +impl CliConfiguration for RelayChainCli { + fn shared_params(&self) -> &SharedParams { + self.base.base.shared_params() + } + + fn import_params(&self) -> Option<&ImportParams> { + self.base.base.import_params() + } + + fn network_params(&self) -> Option<&NetworkParams> { + self.base.base.network_params() + } + + fn keystore_params(&self) -> Option<&KeystoreParams> { + self.base.base.keystore_params() + } + + fn base_path(&self) -> Result> { + Ok(self + .shared_params() + .base_path()? + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_addr(&self, default_listen_port: u16) -> Result> { + self.base.base.rpc_addr(default_listen_port) + } + + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> Result> { + self.base.base.prometheus_config(default_listen_port, chain_spec) + } + + fn init( + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + _config: &Configuration, + ) -> Result<()> + where + F: FnOnce(&mut LoggerBuilder, &Configuration), + { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> Result { + let chain_id = self.base.base.chain_id(is_dev)?; + + Ok(if chain_id.is_empty() { + self.chain_id.clone().unwrap_or_default() + } else { + chain_id + }) + } + + fn role(&self, is_dev: bool) -> Result { + self.base.base.role(is_dev) + } + + fn transaction_pool(&self, is_dev: bool) -> Result { + self.base.base.transaction_pool(is_dev) + } + + fn trie_cache_maximum_size(&self) -> Result> { + self.base.base.trie_cache_maximum_size() + } + + fn rpc_methods(&self) -> Result { + self.base.base.rpc_methods() + } + + fn rpc_max_connections(&self) -> Result { + self.base.base.rpc_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> Result>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> Result> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> Result { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> Result { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> Result> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> Result { + self.base.base.announce_block() + } + + fn telemetry_endpoints(&self, chain_spec: &Box) -> Result> { + self.base.base.telemetry_endpoints(chain_spec) + } +} diff --git a/dip-template/nodes/dip-provider/src/main.rs b/dip-template/nodes/dip-provider/src/main.rs new file mode 100644 index 000000000..272c3dd49 --- /dev/null +++ b/dip-template/nodes/dip-provider/src/main.rs @@ -0,0 +1,32 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! KILT Decentralized Identity Provider (DIP) Provider CLI. + +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; +mod rpc; + +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/dip-template/nodes/dip-provider/src/rpc.rs b/dip-template/nodes/dip-provider/src/rpc.rs new file mode 100644 index 000000000..f710eb483 --- /dev/null +++ b/dip-template/nodes/dip-provider/src/rpc.rs @@ -0,0 +1,70 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![warn(missing_docs)] + +pub use sc_rpc_api::DenyUnsafe; +use substrate_frame_rpc_system::AccountNonceApi; + +use std::{error::Error, sync::Arc}; + +use dip_provider_runtime_template::{AccountId, Balance, NodeBlock as Block, Nonce}; +use jsonrpsee::RpcModule; +use pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi; +use sc_client_api::AuxStore; +use sc_transaction_pool_api::TransactionPool; +use sp_api::ProvideRuntimeApi; +use sp_block_builder::BlockBuilder; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; + +pub type RpcExtension = RpcModule<()>; + +pub struct FullDeps { + pub client: Arc, + pub pool: Arc

, + pub deny_unsafe: DenyUnsafe, +} + +pub fn create_full(deps: FullDeps) -> Result> +where + C: ProvideRuntimeApi + + HeaderBackend + + AuxStore + + HeaderMetadata + + Send + + Sync + + 'static, + C::Api: TransactionPaymentRuntimeApi, + C::Api: AccountNonceApi, + C::Api: BlockBuilder, + P: TransactionPool + Sync + Send + 'static, +{ + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use substrate_frame_rpc_system::{System, SystemApiServer}; + + let mut module = RpcExtension::new(()); + let FullDeps { + client, + pool, + deny_unsafe, + } = deps; + + module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(TransactionPayment::new(client).into_rpc())?; + Ok(module) +} diff --git a/dip-template/nodes/dip-provider/src/service.rs b/dip-template/nodes/dip-provider/src/service.rs new file mode 100644 index 000000000..06b5fee20 --- /dev/null +++ b/dip-template/nodes/dip-provider/src/service.rs @@ -0,0 +1,428 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use std::{error::Error, sync::Arc, time::Duration}; + +use cumulus_client_cli::CollatorOptions; +use cumulus_client_consensus_aura::{ + import_queue, slot_duration, AuraConsensus, BuildAuraConsensusParams, ImportQueueParams, SlotProportion, +}; +use cumulus_client_consensus_common::{ParachainBlockImport as TParachainBlockImport, ParachainConsensus}; +use cumulus_client_service::{ + build_network, build_relay_chain_interface, prepare_node_config, start_collator, start_full_node, + BuildNetworkParams, StartCollatorParams, StartFullNodeParams, +}; +use cumulus_primitives_core::ParaId; +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use cumulus_relay_chain_interface::RelayChainInterface; +use dip_provider_runtime_template::{api, native_version, NodeBlock as Block, RuntimeApi}; +use frame_benchmarking::benchmarking::HostFunctions; +use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; +use sc_basic_authorship::ProposerFactory; +use sc_client_api::Backend; +use sc_consensus::{DefaultImportQueue, ImportQueue}; +use sc_executor::NativeElseWasmExecutor; +use sc_network::NetworkBlock; +use sc_network_sync::SyncingService; +use sc_service::{ + new_full_parts, spawn_tasks, Configuration, PartialComponents, SpawnTasksParams, TFullBackend, TFullClient, + TaskManager, +}; +use sc_sysinfo::{initialize_hwbench_telemetry, print_hwbench, HwBench}; +use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sc_transaction_pool::{BasicPool, FullPool}; +use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use sp_keystore::KeystorePtr; +use substrate_prometheus_endpoint::Registry; + +use crate::rpc::{create_full, FullDeps}; + +pub struct ParachainNativeExecutor; + +impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor { + type ExtendHostFunctions = HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + native_version() + } +} + +type ParachainExecutor = NativeElseWasmExecutor; +type ParachainClient = TFullClient; +type ParachainBackend = TFullBackend; +type ParachainBlockImport = TParachainBlockImport, ParachainBackend>; + +#[allow(clippy::type_complexity)] +pub fn new_partial( + config: &Configuration, +) -> Result< + PartialComponents< + ParachainClient, + ParachainBackend, + (), + DefaultImportQueue, + FullPool, + (ParachainBlockImport, Option, Option), + >, + sc_service::Error, +> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let executor = sc_service::new_native_or_wasm_executor(config); + + let (client, backend, keystore_container, task_manager) = new_full_parts::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let import_queue = build_import_queue( + client.clone(), + block_import.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + Ok(PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (block_import, telemetry, telemetry_worker_handle), + }) +} + +#[sc_tracing::logging::prefix_logs_with("Parachain")] +async fn start_node_impl( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc)> { + let parachain_config = prepare_node_config(parachain_config); + + let params = new_partial(¶chain_config)?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + let mut task_manager = params.task_manager; + + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let force_authoring = parachain_config.force_authoring; + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = sc_network::config::FullNetworkConfiguration::new(¶chain_config.network); + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + net_config, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + }) + .await?; + + if parachain_config.offchain_worker.enabled { + use futures::FutureExt; + + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-work", + sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { + runtime_api_provider: client.clone(), + keystore: Some(params.keystore_container.keystore()), + offchain_db: backend.offchain_storage(), + transaction_pool: Some(OffchainTransactionPoolFactory::new(transaction_pool.clone())), + network_provider: network.clone(), + is_validator: parachain_config.role.is_authority(), + enable_http_requests: false, + custom_extensions: move |_| vec![], + }) + .run(client.clone(), task_manager.spawn_handle()) + .boxed(), + ); + } + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + + Box::new(move |deny_unsafe, _| { + let deps = FullDeps { + client: client.clone(), + pool: transaction_pool.clone(), + deny_unsafe, + }; + + create_full(deps).map_err(Into::into) + }) + }; + + spawn_tasks(SpawnTasksParams { + rpc_builder, + sync_service: sync_service.clone(), + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend, + network: network.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + print_hwbench(&hwbench); + if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && validator { + log::warn!("⚠️ The hardware does not meet the minimal requirements for role 'Authority'."); + } + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let sync = sync_service.clone(); + Arc::new(move |hash, data| sync.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + if validator { + let parachain_consensus = build_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + sync_service.clone(), + params.keystore_container.keystore(), + force_authoring, + para_id, + )?; + + let spawner = task_manager.spawn_handle(); + let params = StartCollatorParams { + para_id, + block_status: client.clone(), + announce_block, + client: client.clone(), + task_manager: &mut task_manager, + relay_chain_interface, + sync_service: sync_service.clone(), + spawner, + parachain_consensus, + import_queue: import_queue_service, + collator_key: collator_key.expect("Command line arguments do not allow this. qed"), + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle), + }; + + start_collator(params).await?; + } else { + let params = StartFullNodeParams { + client: client.clone(), + announce_block, + task_manager: &mut task_manager, + para_id, + relay_chain_interface, + sync_service, + relay_chain_slot_duration, + import_queue: import_queue_service, + recovery_handle: Box::new(overseer_handle), + }; + + start_full_node(params)?; + } + + start_network.start_network(); + + Ok((task_manager, client)) +} + +fn build_import_queue( + client: Arc, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> { + let slot_duration = slot_duration(&*client)?; + + import_queue::(ImportQueueParams { + block_import, + client, + create_inherent_data_providers: move |_, _| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + registry: config.prometheus_registry(), + spawner: &task_manager.spawn_essential_handle(), + telemetry, + }) + .map_err(Into::into) +} + +#[allow(clippy::too_many_arguments)] +fn build_consensus( + client: Arc, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>, + sync_oracle: Arc>, + keystore: KeystorePtr, + force_authoring: bool, + para_id: ParaId, +) -> Result>, sc_service::Error> { + let slot_duration = slot_duration(&*client)?; + + let proposer_factory = ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let params = BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = + ParachainInherentData::create_at(relay_parent, &relay_chain_interface, &validation_data, para_id) + .await; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + let parachain_inherent = parachain_inherent + .ok_or_else(|| Box::::from("Failed to create parachain inherent"))?; + Ok((slot, timestamp, parachain_inherent)) + } + }, + block_import, + para_client: client, + backoff_authoring_blocks: Option::<()>::None, + sync_oracle, + keystore, + force_authoring, + slot_duration, + block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), + max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), + telemetry, + }; + + Ok(AuraConsensus::build::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + _, + >(params)) +} + +pub async fn start_parachain_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc)> { + start_node_impl(parachain_config, polkadot_config, collator_options, para_id, hwbench).await +} diff --git a/dip-template/pallets/pallet-postit/Cargo.toml b/dip-template/pallets/pallet-postit/Cargo.toml new file mode 100644 index 000000000..dbfc82136 --- /dev/null +++ b/dip-template/pallets/pallet-postit/Cargo.toml @@ -0,0 +1,40 @@ +[package] +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true +name = "pallet-postit" +description = "Simple pallet to store on-chain comments, replies, and likes." + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# External dependencies +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} + +#External dependencies +frame-support.workspace = true +frame-system.workspace = true +sp-runtime.workspace = true +sp-std.workspace = true + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks" +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/dip-template/pallets/pallet-postit/src/lib.rs b/dip-template/pallets/pallet-postit/src/lib.rs new file mode 100644 index 000000000..f0697f78d --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/lib.rs @@ -0,0 +1,185 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod post; +pub mod traits; + +pub use pallet::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + + use super::*; + + use frame_support::{ + pallet_prelude::{DispatchResult, *}, + traits::EnsureOrigin, + BoundedVec, + }; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::Hash; + use sp_std::fmt::Debug; + + use crate::{ + post::{Comment, Post}, + traits::GetUsername, + }; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + pub type BoundedTextOf = BoundedVec::MaxTextLength>; + pub type PostOf = Post<::Hash, BoundedTextOf, ::Username>; + pub type CommentOf = Comment<::Hash, BoundedTextOf, ::Username>; + + #[pallet::config] + pub trait Config: frame_system::Config { + type MaxTextLength: Get; + type OriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::OriginSuccess>; + type OriginSuccess: GetUsername; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type Username: Encode + Decode + TypeInfo + MaxEncodedLen + Clone + PartialEq + Debug + Default; + } + + #[pallet::storage] + #[pallet::getter(fn posts)] + pub type Posts = StorageMap<_, Twox64Concat, ::Hash, PostOf>; + + #[pallet::storage] + #[pallet::getter(fn comments)] + pub type Comments = StorageMap<_, Twox64Concat, ::Hash, CommentOf>; + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + NewPost { + post_id: T::Hash, + author: T::Username, + }, + NewComment { + resource_id: T::Hash, + comment_id: T::Hash, + author: T::Username, + }, + NewLike { + resource_id: T::Hash, + liker: T::Username, + }, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(1_000)] + pub fn post(origin: OriginFor, text: BoundedTextOf) -> DispatchResult { + let success_origin = T::OriginCheck::ensure_origin(origin)?; + let author = success_origin.username().map_err(DispatchError::Other)?; + let post_id = T::Hashing::hash( + (&frame_system::Pallet::::block_number(), &author, &text) + .encode() + .as_slice(), + ); + let post = PostOf::::from_text_and_author(text, author.clone()); + Posts::::insert(post_id, post); + Self::deposit_event(Event::NewPost { post_id, author }); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(1_000)] + pub fn comment(origin: OriginFor, resource_id: T::Hash, text: BoundedTextOf) -> DispatchResult { + let success_origin = T::OriginCheck::ensure_origin(origin)?; + let author = success_origin.username().map_err(DispatchError::Other)?; + let comment_id = T::Hashing::hash( + (&frame_system::Pallet::::block_number(), &author, &text) + .encode() + .as_slice(), + ); + Posts::::try_mutate(resource_id, |post| { + if let Some(post) = post { + post.comments + .try_push(comment_id) + .expect("Failed to add comment to post."); + Ok(()) + } else { + Err(()) + } + }) + .or_else(|_| { + Comments::::try_mutate(resource_id, |comment| { + if let Some(comment) = comment { + comment + .details + .comments + .try_push(comment_id) + .expect("Failed to add comment to comment."); + Ok(()) + } else { + Err(()) + } + }) + }) + .map_err(|_| DispatchError::Other("No post or comment with provided ID found."))?; + let comment = CommentOf::::from_post_id_text_and_author(resource_id, text, author.clone()); + Comments::::insert(comment_id, comment); + Self::deposit_event(Event::NewComment { + resource_id, + comment_id, + author, + }); + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(1_000)] + pub fn like(origin: OriginFor, resource_id: T::Hash) -> DispatchResult { + let success_origin = T::OriginCheck::ensure_origin(origin)?; + let liker = success_origin.username().map_err(DispatchError::Other)?; + Posts::::try_mutate(resource_id, |post| { + if let Some(post) = post { + post.likes.try_push(liker.clone()).expect("Failed to add like to post."); + Ok(()) + } else { + Err(()) + } + }) + .or_else(|_| { + Comments::::try_mutate(resource_id, |comment| { + if let Some(comment) = comment { + comment + .details + .likes + .try_push(liker.clone()) + .expect("Failed to add like to comment."); + Ok(()) + } else { + Err(()) + } + }) + }) + .map_err(|_| DispatchError::Other("No post or comment with provided ID found."))?; + Self::deposit_event(Event::NewLike { resource_id, liker }); + Ok(()) + } + } +} diff --git a/dip-template/pallets/pallet-postit/src/post.rs b/dip-template/pallets/pallet-postit/src/post.rs new file mode 100644 index 000000000..49fd158fc --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/post.rs @@ -0,0 +1,55 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{traits::ConstU32, BoundedVec}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, Default)] +pub struct Post { + pub author: Username, + pub text: Text, + pub likes: BoundedVec>, + pub comments: BoundedVec>, +} + +impl Post { + pub(crate) fn from_text_and_author(text: Text, author: Username) -> Self { + Self { + text, + author, + likes: BoundedVec::default(), + comments: BoundedVec::default(), + } + } +} + +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, Default)] +pub struct Comment { + pub details: Post, + pub in_response_to: Id, +} + +impl Comment { + pub(crate) fn from_post_id_text_and_author(in_response_to: Id, text: Text, author: Username) -> Self { + Self { + in_response_to, + details: Post::from_text_and_author(text, author), + } + } +} diff --git a/dip-template/pallets/pallet-postit/src/traits.rs b/dip-template/pallets/pallet-postit/src/traits.rs new file mode 100644 index 000000000..d3c1a2b9a --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/traits.rs @@ -0,0 +1,23 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub trait GetUsername { + type Username; + + fn username(&self) -> Result; +} diff --git a/dip-template/runtimes/dip-consumer/Cargo.toml b/dip-template/runtimes/dip-consumer/Cargo.toml new file mode 100644 index 000000000..f6b7d428d --- /dev/null +++ b/dip-template/runtimes/dip-consumer/Cargo.toml @@ -0,0 +1,141 @@ +[package] +authors.workspace = true +description = "Parachain runtime template for the KILT Decentralized Identity Provider (DIP) consumer." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "dip-consumer-runtime-template" +readme.workspace = true +repository.workspace = true +version.workspace = true + +[build-dependencies] +substrate-wasm-builder.workspace = true + +[dependencies] +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} + +# DIP +dip-provider-runtime-template.workspace = true +did.workspace = true +kilt-dip-primitives.workspace = true +pallet-did-lookup.workspace = true +pallet-dip-consumer.workspace = true +pallet-postit.workspace = true +pallet-relay-store.workspace = true +runtime-common.workspace = true + +# Substrate +frame-executive.workspace = true +frame-support.workspace = true +frame-system.workspace = true +frame-system-rpc-runtime-api.workspace = true +pallet-aura.workspace = true +pallet-authorship.workspace = true +pallet-balances.workspace = true +pallet-session.workspace = true +pallet-sudo.workspace = true +pallet-timestamp.workspace = true +pallet-transaction-payment.workspace = true +pallet-transaction-payment-rpc-runtime-api.workspace = true +pallet-utility.workspace = true +polkadot-parachain.workspace = true +sp-api.workspace = true +sp-block-builder.workspace = true +sp-consensus-aura.workspace = true +sp-core.workspace = true +sp-inherents.workspace = true +sp-offchain.workspace = true +sp-runtime.workspace = true +sp-session.workspace = true +sp-std.workspace = true +sp-transaction-pool.workspace = true +sp-version.workspace = true +sp-weights.workspace = true + +# Cumulus +cumulus-pallet-aura-ext.workspace = true +cumulus-pallet-dmp-queue.workspace = true +cumulus-pallet-parachain-system.workspace = true +cumulus-primitives-core.workspace = true +cumulus-primitives-timestamp.workspace = true +cumulus-primitives-utility.workspace = true +pallet-collator-selection.workspace = true +parachain-info.workspace = true + +# Benchmarks +frame-benchmarking = {workspace = true, optional = true} +frame-system-benchmarking = {workspace = true, optional = true} +hex-literal = {workspace = true, optional = true} + +[features] +default = [ + "std", +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "dip-provider-runtime-template/std", + "did/std", + "kilt-dip-primitives/std", + "pallet-did-lookup/std", + "pallet-dip-consumer/std", + "pallet-postit/std", + "pallet-relay-store/std", + "runtime-common/std", + "frame-executive/std", + "frame-support/std", + "frame-system/std", + "frame-system-rpc-runtime-api/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-session/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-utility/std", + "polkadot-parachain/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-weights/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "pallet-collator-selection/std", + "parachain-info/std" +] + +runtime-benchmarks = [ + "dip-provider-runtime-template/runtime-benchmarks", + "kilt-dip-primitives/runtime-benchmarks", + "pallet-dip-consumer/runtime-benchmarks", + "pallet-relay-store/runtime-benchmarks", + "runtime-common/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "hex-literal" +] diff --git a/dip-template/runtimes/dip-consumer/build.rs b/dip-template/runtimes/dip-consumer/build.rs new file mode 100644 index 000000000..a39438283 --- /dev/null +++ b/dip-template/runtimes/dip-consumer/build.rs @@ -0,0 +1,27 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs new file mode 100644 index 000000000..00868b902 --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -0,0 +1,156 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; +use dip_provider_runtime_template::{AccountId as ProviderAccountId, Runtime as ProviderRuntime}; +use frame_support::traits::Contains; +use frame_system::EnsureSigned; +use kilt_dip_primitives::{ + traits::DipCallOriginFilter, KiltVersionedParachainVerifier, RelayStateRootsViaRelayStorePallet, +}; +use pallet_dip_consumer::traits::IdentityProofVerifier; +use sp_core::ConstU32; +use sp_runtime::traits::BlakeTwo256; + +use crate::{weights, AccountId, DidIdentifier, Runtime, RuntimeCall, RuntimeOrigin}; + +pub type MerkleProofVerifierOutput = >::VerificationResult; +/// The verifier logic assumes the provider is a sibling KILT parachain, and +/// that a KILT subject can provide DIP proof that reveal at most 10 DID keys +/// and 10 linked accounts (defaults provided by the +/// `KiltVersionedParachainVerifier` type). Calls that do not pass the +/// [`DipCallFilter`] will be discarded early on in the verification process. +pub type ProofVerifier = KiltVersionedParachainVerifier< + ProviderRuntime, + ConstU32<2_000>, + RelayStateRootsViaRelayStorePallet, + BlakeTwo256, + DipCallFilter, +>; + +impl pallet_dip_consumer::Config for Runtime { + type DipCallOriginFilter = PreliminaryDipOriginFilter; + // Any signed origin can submit a cross-chain DIP tx, since subject + // authentication (and optional binding to the tx submitter) is performed in the + // DIP proof verification step. + type DispatchOriginCheck = EnsureSigned; + type Identifier = DidIdentifier; + // Local identity info contains a simple `u128` representing a nonce. This means + // that two cross-chain operations targeting the same chain and with the same + // nonce cannot be both successfully evaluated. + type LocalIdentityInfo = u128; + type ProofVerifier = ProofVerifier; + type RuntimeCall = RuntimeCall; + type RuntimeOrigin = RuntimeOrigin; + type WeightInfo = weights::pallet_dip_consumer::WeightInfo; +} + +/// A preliminary DID call filter that only allows dispatching of extrinsics +/// from the [`pallet_postit::Pallet`] pallet. +pub struct PreliminaryDipOriginFilter; + +impl Contains for PreliminaryDipOriginFilter { + #[cfg(not(feature = "runtime-benchmarks"))] + fn contains(t: &RuntimeCall) -> bool { + matches!( + t, + RuntimeCall::PostIt { .. } + | RuntimeCall::Utility(pallet_utility::Call::batch { .. }) + | RuntimeCall::Utility(pallet_utility::Call::batch_all { .. }) + | RuntimeCall::Utility(pallet_utility::Call::force_batch { .. }) + ) + } + + #[cfg(feature = "runtime-benchmarks")] + fn contains(_t: &RuntimeCall) -> bool { + true + } +} + +/// Calls to the [`pallet_postit::Pallet`] pallet or batches containing only +/// calls to the [`pallet_postit::Pallet`] pallet will go through if authorized +/// by a DID's authentication key. Everything else will fail. +fn derive_verification_key_relationship(call: &RuntimeCall) -> Option { + match call { + RuntimeCall::PostIt { .. } => Some(DidVerificationKeyRelationship::Authentication), + RuntimeCall::Utility(pallet_utility::Call::batch { calls }) => single_key_relationship(calls.iter()).ok(), + RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => single_key_relationship(calls.iter()).ok(), + RuntimeCall::Utility(pallet_utility::Call::force_batch { calls }) => single_key_relationship(calls.iter()).ok(), + _ => None, + } +} + +// Taken and adapted from `impl +// did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall` +// in Spiritnet/Peregrine runtime. +fn single_key_relationship<'a>( + calls: impl Iterator, +) -> Result { + let mut calls = calls.peekable(); + let first_call_relationship = calls + .peek() + .and_then(|k| derive_verification_key_relationship(k)) + .ok_or(())?; + calls + .map(derive_verification_key_relationship) + .try_fold(first_call_relationship, |acc, next| { + if next == Some(acc) { + Ok(acc) + } else { + Err(()) + } + }) +} + +/// Errors generated by calls that do not pass the filter. +pub enum DipCallFilterError { + /// The call cannot be dispatched with the provided origin. + BadOrigin, + /// The call could be dispatched with the provided origin, but it has been + /// authorized with the wrong DID key. + WrongVerificationRelationship, +} + +/// A call filter that requires calls to the [`pallet_postit::Pallet`] pallet to +/// be authorized with a DID signature generated with a key of a given +/// verification relationship. +pub struct DipCallFilter; + +impl DipCallOriginFilter for DipCallFilter { + type Error = DipCallFilterError; + type OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship); + type Success = (); + + // Accepts only a DipOrigin for the DidLookup pallet calls. + fn check_call_origin_info(call: &RuntimeCall, info: &Self::OriginInfo) -> Result { + let key_relationship = + single_key_relationship([call].into_iter()).map_err(|_| DipCallFilterError::BadOrigin)?; + if info.1 == key_relationship { + Ok(()) + } else { + Err(DipCallFilterError::WrongVerificationRelationship) + } + } +} + +impl pallet_relay_store::Config for Runtime { + // The pallet stores the last 100 relaychain state roots, making state proofs + // valid for at most 100 * 6 = 600 seconds. + type MaxRelayBlocksStored = ConstU32<100>; + type WeightInfo = weights::pallet_relay_store::WeightInfo; +} diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs new file mode 100644 index 000000000..06e031d2d --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -0,0 +1,571 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Runtime template of a Decentralized Identity Provider (DIP) consumer, which +//! does not itself include any identity-related pallets, but only the +//! [`pallet_dip_consumer::Pallet`] pallet (configured to work with the +//! [`dip_provider_runtime_template::Runtime`] template runtime), the +//! [`pallet_relay_store::Pallet`] pallet to keep track of finalized relaychain +//! state roots, and the example [`pallet_postit::Pallet`], which allows any +//! entity that can be identified with a username (e.g., a web3name carried over +//! from the provider chain) to post a message on chain, reply to another +//! on-chain message (including another reply), or like a message and/or any of +//! its replies. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "256"] + +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use dip_provider_runtime_template::Web3Name; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +use cumulus_pallet_parachain_system::{ + register_validate_block, ParachainSetCode, RelayChainStateProof, RelayNumberStrictlyIncreases, +}; +use cumulus_primitives_core::CollationInfo; +use cumulus_primitives_timestamp::InherentDataProvider; +use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + parameter_types, + traits::{ConstU32, ConstU64, ConstU8, Everything}, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, + IdentityFee, Weight, + }, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + ChainContext, EnsureRoot, +}; +use pallet_balances::AccountData; +use pallet_collator_selection::IdentityCollator; +use pallet_session::{FindAccountFromAuthorIndex, PeriodicSessions}; +use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; +use sp_api::impl_runtime_apis; +use sp_consensus_aura::SlotDuration; +use sp_core::{crypto::KeyTypeId, ConstBool, ConstU128, ConstU16, OpaqueMetadata}; +use sp_inherents::{CheckInherentsResult, InherentData}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, OpaqueKeys}, + transaction_validity::{TransactionSource, TransactionValidity}, + AccountId32, ApplyExtrinsicResult, MultiSignature, OpaqueExtrinsic, +}; +use sp_std::{prelude::*, time::Duration}; +use sp_version::RuntimeVersion; + +mod dip; +mod origin_adapter; +mod weights; +pub use crate::{dip::*, origin_adapter::*}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +#[cfg(feature = "std")] +use sp_version::NativeVersion; + +pub type AccountId = AccountId32; +pub type Address = MultiAddress; +pub type Balance = u128; +pub type Block = generic::Block; +pub type BlockNumber = u32; +pub type DidIdentifier = AccountId; +pub type Hasher = BlakeTwo256; +pub type Hash = sp_core::H256; +pub type Header = generic::Header; +pub type Nonce = u32; +pub type Signature = MultiSignature; + +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type Executive = frame_executive::Executive, Runtime, AllPalletsWithSystem>; +pub type NodeBlock = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +pub const MILLISECS_PER_BLOCK: u64 = 12000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; + +pub const UNIT: Balance = 1_000_000_000_000; +pub const MILLIUNIT: Balance = UNIT / 1_000; + +construct_runtime!( + pub enum Runtime + { + // System + System: frame_system = 0, + ParachainSystem: cumulus_pallet_parachain_system = 1, + Timestamp: pallet_timestamp = 2, + ParachainInfo: parachain_info = 3, + Sudo: pallet_sudo = 4, + Utility: pallet_utility = 5, + + // Money + Balances: pallet_balances = 10, + TransactionPayment: pallet_transaction_payment = 11, + + // Collators + Authorship: pallet_authorship = 20, + CollatorSelection: pallet_collator_selection = 21, + Session: pallet_session = 22, + Aura: pallet_aura = 23, + AuraExt: cumulus_pallet_aura_ext = 24, + + // PostIt + PostIt: pallet_postit = 30, + + // DIP + DipConsumer: pallet_dip_consumer = 40, + RelayStore: pallet_relay_store = 41, + } +); + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("dip-consumer-runtime-template"), + impl_name: create_runtime_str!("dip-consumer-runtime-template"), + authoring_version: 1, + spec_version: 11100, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents(block: &Block, relay_state_proof: &RelayChainStateProof) -> CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + + let inherent_data = + InherentDataProvider::from_relay_chain_slot_and_duration(relay_chain_slot, Duration::from_secs(6)) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + + inherent_data.check_extrinsics(block) + } +} + +register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + CheckInherents = CheckInherents, +} + +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( + WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), + cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, +); + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); +} + +pub const SS58_PREFIX: u16 = 101; + +impl frame_system::Config for Runtime { + type AccountData = AccountData; + type AccountId = AccountId; + type BaseCallFilter = Everything; + type BlockHashCount = ConstU32<256>; + type BlockLength = RuntimeBlockLength; + type Block = Block; + type BlockWeights = RuntimeBlockWeights; + type DbWeight = RocksDbWeight; + type Hash = Hash; + type Hashing = BlakeTwo256; + type Lookup = AccountIdLookup; + type MaxConsumers = ConstU32<16>; + type Nonce = u32; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = ParachainSetCode; + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16; + type SystemWeightInfo = weights::frame_system::WeightInfo; + type Version = Version; +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type DmpMessageHandler = (); + type OnSystemEvent = (); + type OutboundXcmpMessageSource = (); + type ReservedDmpWeight = (); + type ReservedXcmpWeight = (); + type RuntimeEvent = RuntimeEvent; + type SelfParaId = ParachainInfo; + type XcmpMessageHandler = (); +} + +impl pallet_timestamp::Config for Runtime { + type MinimumPeriod = ConstU64<{ MILLISECS_PER_BLOCK / 2 }>; + type Moment = u64; + type OnTimestampSet = Aura; + type WeightInfo = (); +} + +impl parachain_info::Config for Runtime {} + +impl pallet_sudo::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +impl pallet_utility::Config for Runtime { + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; + +impl pallet_balances::Config for Runtime { + type AccountStore = System; + type Balance = Balance; + type DustRemoval = (); + type ExistentialDeposit = ConstU128; + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<50>; + type MaxHolds = ConstU32<50>; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type WeightInfo = (); +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = CurrencyAdapter; + type FeeMultiplierUpdate = (); + type LengthToFee = IdentityFee; + type OperationalFeeMultiplier = ConstU8<1>; + type RuntimeEvent = RuntimeEvent; + type WeightToFee = IdentityFee; +} + +impl pallet_authorship::Config for Runtime { + type EventHandler = (CollatorSelection,); + type FindAuthor = FindAccountFromAuthorIndex; +} + +parameter_types! { + pub const PotId: PalletId = PalletId(*b"PotStake"); +} + +impl pallet_collator_selection::Config for Runtime { + type Currency = Balances; + type PotId = PotId; + type KickThreshold = ConstU32<{ 6 * HOURS }>; + type MaxCandidates = ConstU32<1_000>; + type MaxInvulnerables = ConstU32<100>; + type MinEligibleCollators = ConstU32<5>; + type RuntimeEvent = RuntimeEvent; + type UpdateOrigin = EnsureRoot; + type ValidatorId = AccountId; + type ValidatorIdOf = IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = (); +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +impl pallet_session::Config for Runtime { + type Keys = SessionKeys; + type NextSessionRotation = PeriodicSessions, ConstU32<0>>; + type RuntimeEvent = RuntimeEvent; + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = CollatorSelection; + type ShouldEndSession = PeriodicSessions, ConstU32<0>>; + type ValidatorId = AccountId; + type ValidatorIdOf = IdentityCollator; + type WeightInfo = (); +} + +impl pallet_aura::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<100_000>; +} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl pallet_postit::Config for Runtime { + type MaxTextLength = ConstU32<160>; + type OriginCheck = EnsureDipOriginAdapter; + type OriginSuccess = DipOriginAdapter; + type RuntimeEvent = RuntimeEvent; + type Username = Web3Name; +} + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_benchmarking::define_benchmarks!( + [frame_system, SystemBench::] + [pallet_dip_consumer, DipConsumer] + [pallet_relay_store, RelayStore] + ); +} + +impl_runtime_apis! { + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> SlotDuration { + SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Aura::authorities().into_inner() + } + } + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: InherentData, + ) -> CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Nonce { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime { + fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); + Ok(()) + } + + fn verify_set_code() { + System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); + } + } + + use frame_support::traits::WhitelistedStorageKeys; + let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } +} diff --git a/dip-template/runtimes/dip-consumer/src/origin_adapter.rs b/dip-template/runtimes/dip-consumer/src/origin_adapter.rs new file mode 100644 index 000000000..18d720c1f --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/origin_adapter.rs @@ -0,0 +1,63 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{AccountId, DidIdentifier, MerkleProofVerifierOutput, RuntimeOrigin, Web3Name}; +use frame_support::traits::EnsureOrigin; +use pallet_dip_consumer::{DipOrigin, EnsureDipOrigin}; +use pallet_postit::traits::GetUsername; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; + +/// An origin adapter which is used to make sure that a given [`DipOrigin`] +/// contains, among other things, a web3name. If a pallet extrinsic that +/// requires this origin is called with a DIP proof that does not revealed the +/// web3name linked to the subject, the extrinsic will fail with a `BadOrigin` +/// error. +pub struct EnsureDipOriginAdapter; + +impl EnsureOrigin for EnsureDipOriginAdapter { + type Success = DipOriginAdapter; + + fn try_origin(o: RuntimeOrigin) -> Result { + EnsureDipOrigin::try_origin(o).map(DipOriginAdapter) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + EnsureDipOrigin::::try_successful_origin() + } +} + +/// A wrapper around a [`DipOrigin`] that makes sure the origin has a web3name, +/// or else the origin is invalid. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct DipOriginAdapter(DipOrigin); + +impl GetUsername for DipOriginAdapter { + type Username = Web3Name; + + fn username(&self) -> Result { + self.0 + .details + .web3_name + .as_ref() + .map(|leaf| leaf.web3_name.clone()) + .ok_or("No username for the subject.") + } +} diff --git a/dip-template/runtimes/dip-consumer/src/weights/frame_system.rs b/dip-template/runtimes/dip-consumer/src/weights/frame_system.rs new file mode 100644 index 000000000..3c04d0f21 --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/weights/frame_system.rs @@ -0,0 +1,193 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `frame_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-consumer-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=frame-system +// --extrinsic=* +// --output=./dip-template/runtimes/dip-consumer/src/weights/frame_system.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `frame_system`. +pub struct WeightInfo(PhantomData); +impl frame_system::WeightInfo for WeightInfo { + /// The range of component `b` is `[0, 3932160]`. + fn remark(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_378_000 picoseconds. + Weight::from_parts(90_413_067, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 3 + .saturating_add(Weight::from_parts(196, 0).saturating_mul(b.into())) + } + /// The range of component `b` is `[0, 3932160]`. + fn remark_with_event(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_818_000 picoseconds. + Weight::from_parts(4_882_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 15 + .saturating_add(Weight::from_parts(1_874, 0).saturating_mul(b.into())) + } + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + fn set_heap_pages() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 5_882_000 picoseconds. + Weight::from_parts(6_631_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `ParachainSystem::UpgradeRestrictionSignal` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingValidationCode` (r:1 w:1) + /// Proof: `ParachainSystem::PendingValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::NewValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::NewValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::DidSetValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::DidSetValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_code() -> Weight { + // Proof Size summary in bytes: + // Measured: `119` + // Estimated: `1604` + // Minimum execution time: 141_893_625_000 picoseconds. + Weight::from_parts(162_618_687_000, 0) + .saturating_add(Weight::from_parts(0, 1604)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `i` is `[0, 1000]`. + fn set_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_512_000 picoseconds. + Weight::from_parts(2_972_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 7_153 + .saturating_add(Weight::from_parts(1_100_784, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `i` is `[0, 1000]`. + fn kill_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_526_000 picoseconds. + Weight::from_parts(67_203_020, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 8_216 + .saturating_add(Weight::from_parts(391_130, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `p` is `[0, 1000]`. + fn kill_prefix(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `73 + p * (69 ±0)` + // Estimated: `66 + p * (70 ±0)` + // Minimum execution time: 2_821_000 picoseconds. + Weight::from_parts(9_760_367, 0) + .saturating_add(Weight::from_parts(0, 66)) + // Standard Error: 14_170 + .saturating_add(Weight::from_parts(886_262, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_set_heap_pages() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 1485 + ); + } + #[test] + fn test_set_code() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 1604 + ); + } + #[test] + fn test_kill_prefix() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 66 + ); + } +} diff --git a/dip-template/runtimes/dip-consumer/src/weights/mod.rs b/dip-template/runtimes/dip-consumer/src/weights/mod.rs new file mode 100644 index 000000000..a0fbf6b5f --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/weights/mod.rs @@ -0,0 +1,21 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub mod frame_system; +pub mod pallet_dip_consumer; +pub mod pallet_relay_store; diff --git a/dip-template/runtimes/dip-consumer/src/weights/pallet_dip_consumer.rs b/dip-template/runtimes/dip-consumer/src/weights/pallet_dip_consumer.rs new file mode 100644 index 000000000..625c63b1c --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/weights/pallet_dip_consumer.rs @@ -0,0 +1,83 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `pallet_dip_consumer` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-consumer-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=pallet-dip-consumer +// --extrinsic=* +// --output=./dip-template/runtimes/dip-consumer/src/weights/pallet_dip_consumer.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_dip_consumer`. +pub struct WeightInfo(PhantomData); +impl pallet_dip_consumer::WeightInfo for WeightInfo { + /// Storage: `DipConsumer::IdentityEntries` (r:1 w:1) + /// Proof: `DipConsumer::IdentityEntries` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `RelayStore::LatestRelayHeads` (r:1 w:0) + /// Proof: `RelayStore::LatestRelayHeads` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `66` + // Estimated: `3521` + // Minimum execution time: 88_110_000 picoseconds. + Weight::from_parts(89_742_000, 0) + .saturating_add(Weight::from_parts(0, 3521)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_dispatch_as() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 3521 + ); + } +} diff --git a/dip-template/runtimes/dip-consumer/src/weights/pallet_relay_store.rs b/dip-template/runtimes/dip-consumer/src/weights/pallet_relay_store.rs new file mode 100644 index 000000000..ae8300999 --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/weights/pallet_relay_store.rs @@ -0,0 +1,83 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `pallet_relay_store` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-consumer-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=pallet-relay-store +// --extrinsic=* +// --output=./dip-template/runtimes/dip-consumer/src/weights/pallet_relay_store.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_relay_store`. +pub struct WeightInfo(PhantomData); +impl pallet_relay_store::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `RelayStore::LatestBlockHeights` (r:1 w:1) + /// Proof: `RelayStore::LatestBlockHeights` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `RelayStore::LatestRelayHeads` (r:0 w:2) + /// Proof: `RelayStore::LatestRelayHeads` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn on_finalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `540` + // Estimated: `2025` + // Minimum execution time: 9_067_000 picoseconds. + Weight::from_parts(9_467_000, 0) + .saturating_add(Weight::from_parts(0, 2025)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_on_finalize() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 2025 + ); + } +} diff --git a/dip-template/runtimes/dip-provider/Cargo.toml b/dip-template/runtimes/dip-provider/Cargo.toml new file mode 100644 index 000000000..63b4302ff --- /dev/null +++ b/dip-template/runtimes/dip-provider/Cargo.toml @@ -0,0 +1,147 @@ +[package] +authors.workspace = true +description = "Parachain runtime template for the KILT Decentralized Identity Provider (DIP) provider." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "dip-provider-runtime-template" +readme.workspace = true +repository.workspace = true +version.workspace = true + +[build-dependencies] +substrate-wasm-builder.workspace = true + +[dependencies] +log.workspace = true +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} + +# DIP +did.workspace = true +kilt-support.workspace = true +kilt-dip-primitives.workspace = true +kilt-runtime-api-did.workspace = true +kilt-runtime-api-dip-provider.workspace = true +pallet-deposit-storage.workspace = true +pallet-did-lookup.workspace = true +pallet-dip-provider.workspace = true +pallet-web3-names.workspace = true +runtime-common.workspace = true + +# Substrate +frame-executive.workspace = true +frame-support.workspace = true +frame-system.workspace = true +frame-system-rpc-runtime-api.workspace = true +pallet-aura.workspace = true +pallet-authorship.workspace = true +pallet-balances.workspace = true +pallet-session.workspace = true +pallet-sudo.workspace = true +pallet-timestamp.workspace = true +pallet-transaction-payment.workspace = true +pallet-transaction-payment-rpc-runtime-api.workspace = true +pallet-utility.workspace = true +sp-api.workspace = true +sp-block-builder.workspace = true +sp-consensus-aura.workspace = true +sp-core.workspace = true +sp-inherents.workspace = true +sp-offchain.workspace = true +sp-runtime.workspace = true +sp-session.workspace = true +sp-std.workspace = true +sp-transaction-pool.workspace = true +sp-version.workspace = true +sp-weights.workspace = true + +# Cumulus +cumulus-pallet-aura-ext.workspace = true +cumulus-pallet-dmp-queue.workspace = true +cumulus-pallet-parachain-system.workspace = true +cumulus-primitives-core.workspace = true +cumulus-primitives-timestamp.workspace = true +cumulus-primitives-utility.workspace = true +pallet-collator-selection.workspace = true +parachain-info.workspace = true + +# Benchmarks +frame-benchmarking = {workspace = true, optional = true} +frame-system-benchmarking = {workspace = true, optional = true} +hex-literal = {workspace = true, optional = true} + +[features] +default = [ + "std", +] +std = [ + "log/std", + "parity-scale-codec/std", + "scale-info/std", + "did/std", + "kilt-support/std", + "kilt-dip-primitives/std", + "kilt-runtime-api-did/std", + "kilt-runtime-api-dip-provider/std", + "pallet-deposit-storage/std", + "pallet-did-lookup/std", + "pallet-dip-provider/std", + "pallet-web3-names/std", + "runtime-common/std", + "frame-executive/std", + "frame-support/std", + "frame-system/std", + "frame-system-rpc-runtime-api/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-session/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-utility/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-weights/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "pallet-collator-selection/std", + "parachain-info/std", + "frame-benchmarking?/std", +] +runtime-benchmarks = [ + "did/runtime-benchmarks", + "kilt-dip-primitives/runtime-benchmarks", + "pallet-deposit-storage/runtime-benchmarks", + "pallet-did-lookup/runtime-benchmarks", + "pallet-dip-provider/runtime-benchmarks", + "pallet-web3-names/runtime-benchmarks", + "runtime-common/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "hex-literal" +] diff --git a/dip-template/runtimes/dip-provider/build.rs b/dip-template/runtimes/dip-provider/build.rs new file mode 100644 index 000000000..a39438283 --- /dev/null +++ b/dip-template/runtimes/dip-provider/build.rs @@ -0,0 +1,27 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs new file mode 100644 index 000000000..5564abc13 --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -0,0 +1,226 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::{DidRawOrigin, EnsureDidOrigin, KeyIdOf}; +use frame_system::EnsureSigned; +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_provider::IdentityCommitmentVersion; +use parity_scale_codec::{Decode, Encode}; +use runtime_common::dip::{ + did::{LinkedDidInfoProvider, LinkedDidInfoProviderError}, + merkle::{DidMerkleProofError, DidMerkleRootGenerator}, +}; +use scale_info::TypeInfo; +use sp_core::ConstU32; +use sp_std::vec::Vec; + +use crate::{ + deposit::{DepositHooks, DepositNamespaces}, + weights, AccountId, Balances, DidIdentifier, Runtime, RuntimeEvent, RuntimeHoldReason, +}; + +const MAX_LINKED_ACCOUNTS: u32 = 20; + +pub mod runtime_api { + use super::*; + + /// Parameters for a DIP proof request. + #[derive(Encode, Decode, TypeInfo)] + pub struct DipProofRequest { + /// The subject identifier for which to generate the DIP proof. + pub(crate) identifier: DidIdentifier, + /// The DIP version. + pub(crate) version: IdentityCommitmentVersion, + /// The DID key IDs of the subject's DID Document to reveal in the DIP + /// proof. + pub(crate) keys: Vec>, + /// The list of accounts linked to the subject's DID to reveal in the + /// DIP proof. + pub(crate) accounts: Vec, + /// A flag indicating whether the web3name claimed by the DID subject + /// should revealed in the DIP proof. + pub(crate) should_include_web3_name: bool, + } + + #[derive(Encode, Decode, TypeInfo)] + pub enum DipProofError { + IdentityProvider(LinkedDidInfoProviderError), + MerkleProof(DidMerkleProofError), + } +} + +pub mod deposit { + use super::*; + + use crate::{Balance, UNIT}; + + use frame_support::traits::Get; + use pallet_deposit_storage::{ + traits::DepositStorageHooks, DepositEntryOf, DepositKeyOf, FixedDepositCollectorViaDepositsPallet, + }; + use parity_scale_codec::MaxEncodedLen; + use sp_core::{ConstU128, RuntimeDebug}; + + #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug)] + pub enum DepositNamespaces { + DipProvider, + } + + /// The namespace to use in the [`pallet_deposit_storage::Pallet`] to store + /// all deposits related to DIP commitments. + pub struct DipProviderDepositNamespace; + + impl Get for DipProviderDepositNamespace { + fn get() -> DepositNamespaces { + DepositNamespaces::DipProvider + } + } + + /// The amount of tokens locked for each identity commitment. + pub const DEPOSIT_AMOUNT: Balance = 2 * UNIT; + + /// The additional logic to execute whenever a deposit is removed by its + /// owner directly via the [`pallet_deposit_storage::Pallet`] pallet. + pub type DepositCollectorHooks = FixedDepositCollectorViaDepositsPallet< + DipProviderDepositNamespace, + ConstU128, + (DidIdentifier, IdentityCommitmentVersion), + >; + + pub enum CommitmentDepositRemovalHookError { + DecodeKey, + Internal, + } + + impl From for u16 { + fn from(value: CommitmentDepositRemovalHookError) -> Self { + match value { + CommitmentDepositRemovalHookError::DecodeKey => 0, + CommitmentDepositRemovalHookError::Internal => u16::MAX, + } + } + } + + /// The logic to execute whenever an identity commitment is generated and + /// stored in the [`pallet_dip_provider::Pallet`] pallet. + /// + /// Upon storing and removing identity commitments, this hook will reserve + /// or release deposits from the [`pallet_deposit_storage::Pallet`] pallet. + pub struct DepositHooks; + + impl DepositStorageHooks for DepositHooks { + type Error = CommitmentDepositRemovalHookError; + + fn on_deposit_reclaimed( + _namespace: &::Namespace, + key: &DepositKeyOf, + deposit: DepositEntryOf, + ) -> Result<(), Self::Error> { + let (identifier, commitment_version) = <(DidIdentifier, IdentityCommitmentVersion)>::decode(&mut &key[..]) + .map_err(|_| CommitmentDepositRemovalHookError::DecodeKey)?; + pallet_dip_provider::Pallet::::delete_identity_commitment_storage_entry( + &identifier, + // Deposit owner is the only one authorized to remove the deposit. + &deposit.deposit.owner, + commitment_version, + ) + .map_err(|_| { + log::error!( + "Should not fail to remove commitment for identifier {:#?} and version {commitment_version}", + identifier + ); + CommitmentDepositRemovalHookError::Internal + })?; + Ok(()) + } + } + + #[cfg(feature = "runtime-benchmarks")] + pub struct PalletDepositStorageBenchmarkHooks; + + #[cfg(feature = "runtime-benchmarks")] + impl pallet_deposit_storage::traits::BenchmarkHooks for PalletDepositStorageBenchmarkHooks { + fn pre_reclaim_deposit() -> ( + ::AccountId, + ::Namespace, + sp_runtime::BoundedVec::MaxKeyLength>, + ) { + let submitter = AccountId::from([100u8; 32]); + let namespace = DepositNamespaces::DipProvider; + let did_identifier = DidIdentifier::from([200u8; 32]); + let commitment_version = 0u16; + let key: DepositKeyOf = (did_identifier.clone(), 0) + .encode() + .try_into() + .expect("Should not fail to create a key for a DIP commitment."); + + pallet_dip_provider::IdentityCommitments::::insert( + &did_identifier, + commitment_version, + ::Hash::default(), + ); + + assert!( + pallet_dip_provider::IdentityCommitments::::get(did_identifier, commitment_version).is_some() + ); + + (submitter, namespace, key) + } + + fn post_reclaim_deposit() { + let did_identifier = DidIdentifier::from([200u8; 32]); + let commitment_version = 0u16; + assert!( + pallet_dip_provider::IdentityCommitments::::get(did_identifier, commitment_version).is_none() + ); + } + } +} + +impl pallet_deposit_storage::Config for Runtime { + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHooks = deposit::PalletDepositStorageBenchmarkHooks; + // Any signed origin can submit the tx, which will go through only if the + // deposit payer matches the signed origin. + type CheckOrigin = EnsureSigned; + // The balances pallet is used to reserve/unreserve tokens. + type Currency = Balances; + type DepositHooks = DepositHooks; + type MaxKeyLength = ConstU32<256>; + type Namespace = DepositNamespaces; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type WeightInfo = weights::pallet_deposit_storage::WeightInfo; +} + +impl pallet_dip_provider::Config for Runtime { + // Only DID origins can submit the commitment identity tx, which will go through + // only if the DID in the origin matches the identifier specified in the tx. + type CommitOriginCheck = EnsureDidOrigin; + type CommitOrigin = DidRawOrigin; + type Identifier = DidIdentifier; + // The identity commitment is defined as the Merkle root of the linked identity + // info, as specified by the [`LinkedDidInfoProvider`]. + type IdentityCommitmentGenerator = DidMerkleRootGenerator; + // Identity info is defined as the collection of DID keys, linked accounts, and + // the optional web3name of a given DID subject. + type IdentityProvider = LinkedDidInfoProvider; + type ProviderHooks = deposit::DepositCollectorHooks; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_dip_provider::WeightInfo; +} diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs new file mode 100644 index 000000000..8a083b92b --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -0,0 +1,746 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Runtime template of a Decentralized Identity Provider (DIP) provider, which +//! includes, beyond system pallets, [`did::Pallet`], +//! [`pallet_web3_names::Pallet`], and [`pallet_did_lookup::Pallet`] pallets, as +//! well as the [`pallet_dip_provider::Pallet`] pallet and the +//! [`pallet_deposit_storage::Pallet`] pallet. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "256"] + +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_web3_names::web3_name::AsciiWeb3Name; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +use cumulus_pallet_parachain_system::{ + register_validate_block, ParachainSetCode, RelayChainStateProof, RelayNumberStrictlyIncreases, +}; +use cumulus_primitives_core::CollationInfo; +use cumulus_primitives_timestamp::InherentDataProvider; +use did::{DidRawOrigin, EnsureDidOrigin}; +use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + parameter_types, + traits::{ConstU32, ConstU64, ConstU8, Everything}, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, + IdentityFee, Weight, + }, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + ChainContext, EnsureRoot, +}; +use pallet_balances::AccountData; +use pallet_collator_selection::IdentityCollator; +use pallet_dip_provider::{traits::IdentityProvider, IdentityProviderOf}; +use pallet_session::{FindAccountFromAuthorIndex, PeriodicSessions}; +use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; +use runtime_common::dip::merkle::{CompleteMerkleProof, DidMerkleProofOf, DidMerkleRootGenerator}; +use sp_api::impl_runtime_apis; +use sp_consensus_aura::SlotDuration; +use sp_core::{crypto::KeyTypeId, ConstBool, ConstU128, ConstU16, OpaqueMetadata}; +use sp_inherents::{CheckInherentsResult, InherentData}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, OpaqueKeys}, + transaction_validity::{TransactionSource, TransactionValidity}, + AccountId32, ApplyExtrinsicResult, MultiSignature, OpaqueExtrinsic, +}; +use sp_std::{prelude::*, time::Duration}; +use sp_version::RuntimeVersion; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +#[cfg(feature = "std")] +use sp_version::NativeVersion; + +mod dip; +mod weights; +pub use crate::dip::*; + +pub type AccountId = AccountId32; +pub type Address = MultiAddress; +pub type Balance = u128; +pub type Block = generic::Block; +pub type BlockNumber = u32; +pub type DidIdentifier = AccountId; +pub type Hash = sp_core::H256; +pub type Header = generic::Header; +pub type Nonce = u32; +pub type Signature = MultiSignature; + +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type Executive = frame_executive::Executive, Runtime, AllPalletsWithSystem>; +pub type NodeBlock = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +pub const MILLISECS_PER_BLOCK: u64 = 12000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; + +pub const UNIT: Balance = 1_000_000_000_000; +pub const MILLIUNIT: Balance = UNIT / 1_000; + +construct_runtime!( + pub enum Runtime + { + // System + System: frame_system = 0, + ParachainSystem: cumulus_pallet_parachain_system = 1, + Timestamp: pallet_timestamp = 2, + ParachainInfo: parachain_info = 3, + Sudo: pallet_sudo = 4, + Utility: pallet_utility = 5, + + // Money + Balances: pallet_balances = 10, + TransactionPayment: pallet_transaction_payment = 11, + + // Collators + Authorship: pallet_authorship = 20, + CollatorSelection: pallet_collator_selection = 21, + Session: pallet_session = 22, + Aura: pallet_aura = 23, + AuraExt: cumulus_pallet_aura_ext = 24, + + // DID + Did: did = 30, + DidLookup: pallet_did_lookup = 31, + Web3Names: pallet_web3_names = 32, + + // DIP + DepositStorage: pallet_deposit_storage = 40, + DipProvider: pallet_dip_provider = 41, + } +); + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("dip-provider-runtime-template"), + impl_name: create_runtime_str!("dip-provider-runtime-template"), + authoring_version: 1, + spec_version: 11100, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents(block: &Block, relay_state_proof: &RelayChainStateProof) -> CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + + let inherent_data = + InherentDataProvider::from_relay_chain_slot_and_duration(relay_chain_slot, Duration::from_secs(6)) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + + inherent_data.check_extrinsics(block) + } +} + +register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + CheckInherents = CheckInherents, +} + +// Same as official KILT prefix. +pub const SS58_PREFIX: u16 = 38; +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( + WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), + cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, +); + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); +} + +impl frame_system::Config for Runtime { + type AccountData = AccountData; + type AccountId = AccountId; + type BaseCallFilter = Everything; + type BlockHashCount = ConstU32<256>; + type BlockLength = RuntimeBlockLength; + type Block = Block; + type BlockWeights = RuntimeBlockWeights; + type DbWeight = RocksDbWeight; + type Hash = Hash; + type Hashing = BlakeTwo256; + type Lookup = AccountIdLookup; + type MaxConsumers = ConstU32<16>; + type Nonce = u32; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = ParachainSetCode; + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16; + type SystemWeightInfo = weights::frame_system::WeightInfo; + type Version = Version; +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type DmpMessageHandler = (); + type OnSystemEvent = (); + type OutboundXcmpMessageSource = (); + type ReservedDmpWeight = (); + type ReservedXcmpWeight = (); + type RuntimeEvent = RuntimeEvent; + type SelfParaId = ParachainInfo; + type XcmpMessageHandler = (); +} + +impl pallet_timestamp::Config for Runtime { + type MinimumPeriod = ConstU64<{ MILLISECS_PER_BLOCK / 2 }>; + type Moment = u64; + type OnTimestampSet = Aura; + type WeightInfo = (); +} + +impl parachain_info::Config for Runtime {} + +impl pallet_sudo::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +impl pallet_utility::Config for Runtime { + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; + +impl pallet_balances::Config for Runtime { + type AccountStore = System; + type Balance = Balance; + type DustRemoval = (); + type ExistentialDeposit = ConstU128; + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<50>; + type MaxHolds = ConstU32<50>; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type WeightInfo = (); +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = CurrencyAdapter; + type FeeMultiplierUpdate = (); + type LengthToFee = IdentityFee; + type OperationalFeeMultiplier = ConstU8<1>; + type RuntimeEvent = RuntimeEvent; + type WeightToFee = IdentityFee; +} + +impl pallet_authorship::Config for Runtime { + type EventHandler = (CollatorSelection,); + type FindAuthor = FindAccountFromAuthorIndex; +} + +parameter_types! { + pub const PotId: PalletId = PalletId(*b"PotStake"); +} + +impl pallet_collator_selection::Config for Runtime { + type Currency = Balances; + type PotId = PotId; + type KickThreshold = ConstU32<{ 6 * HOURS }>; + type MaxCandidates = ConstU32<1_000>; + type MaxInvulnerables = ConstU32<100>; + type MinEligibleCollators = ConstU32<5>; + type RuntimeEvent = RuntimeEvent; + type UpdateOrigin = EnsureRoot; + type ValidatorId = AccountId; + type ValidatorIdOf = IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = (); +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +impl pallet_session::Config for Runtime { + type Keys = SessionKeys; + type NextSessionRotation = PeriodicSessions, ConstU32<0>>; + type RuntimeEvent = RuntimeEvent; + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = CollatorSelection; + type ShouldEndSession = PeriodicSessions, ConstU32<0>>; + type ValidatorId = AccountId; + type ValidatorIdOf = IdentityCollator; + type WeightInfo = (); +} + +impl pallet_aura::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<100_000>; +} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { + fn derive_verification_key_relationship(&self) -> did::DeriveDidCallKeyRelationshipResult { + Ok(did::DidVerificationKeyRelationship::Authentication) + } + + #[cfg(feature = "runtime-benchmarks")] + fn get_call_for_did_call_benchmark() -> Self { + RuntimeCall::System(frame_system::Call::remark { + remark: b"test-remark".to_vec(), + }) + } +} + +parameter_types! { + #[derive(Debug, Clone, Eq, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 50; + #[derive(Debug, Clone, Eq, PartialEq, TypeInfo, Encode, Decode)] + pub const MaxNewKeyAgreementKeys: u32 = 50; +} + +impl did::Config for Runtime { + type BalanceMigrationManager = (); + type BaseDeposit = ConstU128; + type Currency = Balances; + type DidIdentifier = DidIdentifier; + type EnsureOrigin = EnsureDidOrigin; + type Fee = ConstU128; + type FeeCollector = (); + type KeyDeposit = ConstU128; + type MaxBlocksTxValidity = ConstU32; + type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxNumberOfServicesPerDid = ConstU32<1>; + type MaxNumberOfTypesPerService = ConstU32<1>; + type MaxNumberOfUrlsPerService = ConstU32<1>; + type MaxPublicKeysPerDid = ConstU32<53>; + type MaxServiceIdLength = ConstU32<100>; + type MaxServiceTypeLength = ConstU32<100>; + type MaxServiceUrlLength = ConstU32<100>; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type OriginSuccess = DidRawOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeOrigin = RuntimeOrigin; + type ServiceEndpointDeposit = ConstU128; + type WeightInfo = weights::did::WeightInfo; +} + +impl pallet_did_lookup::Config for Runtime { + type BalanceMigrationManager = (); + type Currency = Balances; + type Deposit = ConstU128; + type DidIdentifier = DidIdentifier; + type EnsureOrigin = EnsureDidOrigin; + type OriginSuccess = DidRawOrigin; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type WeightInfo = weights::pallet_did_lookup::WeightInfo; +} + +pub type Web3Name = AsciiWeb3Name; + +impl pallet_web3_names::Config for Runtime { + type BalanceMigrationManager = (); + type BanOrigin = EnsureRoot; + type Currency = Balances; + type Deposit = ConstU128; + type MaxNameLength = ConstU32<32>; + type MinNameLength = ConstU32<3>; + type OriginSuccess = DidRawOrigin; + type OwnerOrigin = EnsureDidOrigin; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type Web3Name = Web3Name; + type Web3NameOwner = DidIdentifier; + type WeightInfo = weights::pallet_web3_names::WeightInfo; +} + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_benchmarking::define_benchmarks!( + [frame_system, SystemBench::] + [did, Did] + [pallet_did_lookup, DidLookup] + [pallet_web3_names, Web3Names] + [pallet_deposit_storage, DepositStorage] + [pallet_dip_provider, DipProvider] + ); +} + +impl_runtime_apis! { + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> SlotDuration { + SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Aura::authorities().into_inner() + } + } + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: InherentData, + ) -> CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Nonce { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + impl kilt_runtime_api_did::Did< + Block, + DidIdentifier, + AccountId, + LinkableAccountId, + Balance, + Hash, + BlockNumber + > for Runtime { + fn query_by_web3_name(name: Vec) -> Option + > { + let name: pallet_web3_names::web3_name::AsciiWeb3Name = name.try_into().ok()?; + pallet_web3_names::Owner::::get(&name) + .and_then(|owner_info| { + did::Did::::get(&owner_info.owner).map(|details| (owner_info, details)) + }) + .map(|(owner_info, details)| { + let accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix( + &owner_info.owner, + ).collect(); + let service_endpoints = did::ServiceEndpoints::::iter_prefix(&owner_info.owner).map(|e| From::from(e.1)).collect(); + + kilt_runtime_api_did::RawDidLinkedInfo{ + identifier: owner_info.owner, + w3n: Some(name.into()), + accounts, + service_endpoints, + details: details.into(), + } + }) + } + + fn query_by_account(account: LinkableAccountId) -> Option< + kilt_runtime_api_did::RawDidLinkedInfo< + DidIdentifier, + AccountId, + LinkableAccountId, + Balance, + Hash, + BlockNumber + > + > { + pallet_did_lookup::ConnectedDids::::get(account) + .and_then(|owner_info| { + did::Did::::get(&owner_info.did).map(|details| (owner_info, details)) + }) + .map(|(connection_record, details)| { + let w3n = pallet_web3_names::Names::::get(&connection_record.did).map(Into::into); + let accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(&connection_record.did).collect(); + let service_endpoints = did::ServiceEndpoints::::iter_prefix(&connection_record.did).map(|e| From::from(e.1)).collect(); + + kilt_runtime_api_did::RawDidLinkedInfo { + identifier: connection_record.did, + w3n, + accounts, + service_endpoints, + details: details.into(), + } + }) + } + + fn query(did: DidIdentifier) -> Option< + kilt_runtime_api_did::RawDidLinkedInfo< + DidIdentifier, + AccountId, + LinkableAccountId, + Balance, + Hash, + BlockNumber + > + > { + let details = did::Did::::get(&did)?; + let w3n = pallet_web3_names::Names::::get(&did).map(Into::into); + let accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(&did).collect(); + let service_endpoints = did::ServiceEndpoints::::iter_prefix(&did).map(|e| From::from(e.1)).collect(); + + Some(kilt_runtime_api_did::RawDidLinkedInfo { + identifier: did, + w3n, + accounts, + service_endpoints, + details: details.into(), + }) + } + } + + impl kilt_runtime_api_dip_provider::DipProvider>, runtime_api::DipProofError> for Runtime { + fn generate_proof(request: runtime_api::DipProofRequest) -> Result>, runtime_api::DipProofError> { + let identity_details = IdentityProviderOf::::retrieve(&request.identifier).map_err(runtime_api::DipProofError::IdentityProvider)?; + + DidMerkleRootGenerator::::generate_proof(&identity_details, request.version, request.keys.iter(), request.should_include_web3_name, request.accounts.iter()).map_err(runtime_api::DipProofError::MerkleProof) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime { + fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); + Ok(()) + } + + fn verify_set_code() { + System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); + } + } + + use frame_support::traits::WhitelistedStorageKeys; + let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } +} diff --git a/dip-template/runtimes/dip-provider/src/weights/did.rs b/dip-template/runtimes/dip-provider/src/weights/did.rs new file mode 100644 index 000000000..7557791b9 --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/did.rs @@ -0,0 +1,1217 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `did` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-provider-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=did +// --extrinsic=* +// --output=./dip-template/runtimes/dip-provider/src/weights/did.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `did`. +pub struct WeightInfo(PhantomData); +impl did::WeightInfo for WeightInfo { + /// Storage: Did DidBlacklist (r:1 w:0) + /// Proof: Did DidBlacklist (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:0 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:0 w:25) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + /// The range of component `c` is `[1, 25]`. + fn create_ed25519_keys(n: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1131` + // Estimated: `6204` + // Minimum execution time: 179_404_000 picoseconds. + Weight::from_parts(170_230_985, 0) + .saturating_add(Weight::from_parts(0, 6204)) + // Standard Error: 40_649 + .saturating_add(Weight::from_parts(296_994, 0).saturating_mul(n.into())) + // Standard Error: 15_716 + .saturating_add(Weight::from_parts(10_509_026, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + } + /// Storage: Did DidBlacklist (r:1 w:0) + /// Proof: Did DidBlacklist (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:0 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:0 w:25) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + /// The range of component `c` is `[1, 25]`. + fn create_sr25519_keys(n: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1131` + // Estimated: `6204` + // Minimum execution time: 181_049_000 picoseconds. + Weight::from_parts(161_298_980, 0) + .saturating_add(Weight::from_parts(0, 6204)) + // Standard Error: 36_193 + .saturating_add(Weight::from_parts(1_411_802, 0).saturating_mul(n.into())) + // Standard Error: 13_993 + .saturating_add(Weight::from_parts(11_432_937, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + } + /// Storage: Did DidBlacklist (r:1 w:0) + /// Proof: Did DidBlacklist (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:0 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:0 w:25) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + /// The range of component `c` is `[1, 25]`. + fn create_ecdsa_keys(n: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1131` + // Estimated: `6204` + // Minimum execution time: 164_997_000 picoseconds. + Weight::from_parts(143_724_779, 0) + .saturating_add(Weight::from_parts(0, 6204)) + // Standard Error: 46_012 + .saturating_add(Weight::from_parts(1_689_629, 0).saturating_mul(n.into())) + // Standard Error: 17_790 + .saturating_add(Weight::from_parts(9_993_575, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + } + /// Storage: Did DidEndpointsCount (r:1 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:25 w:25) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Did DidBlacklist (r:0 w:1) + /// Proof: Did DidBlacklist (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// The range of component `c` is `[1, 25]`. + fn delete(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `969 + c * (105 ±0)` + // Estimated: `5777 + c * (3090 ±0)` + // Minimum execution time: 53_190_000 picoseconds. + Weight::from_parts(54_199_033, 0) + .saturating_add(Weight::from_parts(0, 5777)) + // Standard Error: 4_988 + .saturating_add(Weight::from_parts(1_376_408, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 3090).saturating_mul(c.into())) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:25 w:25) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Did DidBlacklist (r:0 w:1) + /// Proof: Did DidBlacklist (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// The range of component `c` is `[1, 25]`. + fn reclaim_deposit(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `969 + c * (105 ±0)` + // Estimated: `5777 + c * (3090 ±0)` + // Minimum execution time: 55_729_000 picoseconds. + Weight::from_parts(56_557_707, 0) + .saturating_add(Weight::from_parts(0, 5777)) + // Standard Error: 4_643 + .saturating_add(Weight::from_parts(1_397_138, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 3090).saturating_mul(c.into())) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + fn submit_did_call_ed25519_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `352` + // Estimated: `5777` + // Minimum execution time: 76_132_000 picoseconds. + Weight::from_parts(76_814_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + fn submit_did_call_sr25519_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `352` + // Estimated: `5777` + // Minimum execution time: 77_295_000 picoseconds. + Weight::from_parts(78_438_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + fn submit_did_call_ecdsa_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `353` + // Estimated: `5777` + // Minimum execution time: 64_288_000 picoseconds. + Weight::from_parts(65_482_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_ed25519_authentication_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2170` + // Estimated: `5777` + // Minimum execution time: 67_708_000 picoseconds. + Weight::from_parts(70_147_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_sr25519_authentication_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2170` + // Estimated: `5777` + // Minimum execution time: 68_784_000 picoseconds. + Weight::from_parts(70_860_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_ecdsa_authentication_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2107` + // Estimated: `5777` + // Minimum execution time: 68_261_000 picoseconds. + Weight::from_parts(69_565_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_ed25519_delegation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2038` + // Estimated: `5777` + // Minimum execution time: 67_556_000 picoseconds. + Weight::from_parts(69_662_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_sr25519_delegation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2165` + // Estimated: `5777` + // Minimum execution time: 67_837_000 picoseconds. + Weight::from_parts(69_180_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_ecdsa_delegation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2173` + // Estimated: `5777` + // Minimum execution time: 68_540_000 picoseconds. + Weight::from_parts(69_956_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_ed25519_delegation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2104` + // Estimated: `5777` + // Minimum execution time: 65_127_000 picoseconds. + Weight::from_parts(66_929_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_sr25519_delegation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2104` + // Estimated: `5777` + // Minimum execution time: 64_797_000 picoseconds. + Weight::from_parts(65_517_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_ecdsa_delegation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2173` + // Estimated: `5777` + // Minimum execution time: 65_807_000 picoseconds. + Weight::from_parts(67_122_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_ed25519_attestation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2105` + // Estimated: `5777` + // Minimum execution time: 68_688_000 picoseconds. + Weight::from_parts(69_835_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_sr25519_attestation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2137` + // Estimated: `5777` + // Minimum execution time: 67_241_000 picoseconds. + Weight::from_parts(68_767_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn set_ecdsa_attestation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2177` + // Estimated: `5777` + // Minimum execution time: 66_623_000 picoseconds. + Weight::from_parts(68_381_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_ed25519_attestation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2137` + // Estimated: `5777` + // Minimum execution time: 64_750_000 picoseconds. + Weight::from_parts(67_215_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_sr25519_attestation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2132` + // Estimated: `5777` + // Minimum execution time: 65_858_000 picoseconds. + Weight::from_parts(67_393_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_ecdsa_attestation_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2112` + // Estimated: `5777` + // Minimum execution time: 64_552_000 picoseconds. + Weight::from_parts(66_076_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn add_ed25519_key_agreement_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2026` + // Estimated: `5777` + // Minimum execution time: 67_691_000 picoseconds. + Weight::from_parts(69_179_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn add_sr25519_key_agreement_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `1966` + // Estimated: `5777` + // Minimum execution time: 67_454_000 picoseconds. + Weight::from_parts(69_136_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn add_ecdsa_key_agreement_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2062` + // Estimated: `5777` + // Minimum execution time: 66_065_000 picoseconds. + Weight::from_parts(68_090_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_ed25519_key_agreement_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2104` + // Estimated: `5777` + // Minimum execution time: 64_706_000 picoseconds. + Weight::from_parts(67_009_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_sr25519_key_agreement_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2170` + // Estimated: `5777` + // Minimum execution time: 65_290_000 picoseconds. + Weight::from_parts(67_110_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_ecdsa_key_agreement_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `2107` + // Estimated: `5777` + // Minimum execution time: 65_011_000 picoseconds. + Weight::from_parts(67_020_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:1 w:1) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn add_service_endpoint() -> Weight { + // Proof Size summary in bytes: + // Measured: `1504` + // Estimated: `5777` + // Minimum execution time: 75_496_000 picoseconds. + Weight::from_parts(76_809_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did ServiceEndpoints (r:1 w:1) + /// Proof: Did ServiceEndpoints (max_values: None, max_size: Some(615), added: 3090, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:1) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn remove_service_endpoint() -> Weight { + // Proof Size summary in bytes: + // Measured: `2154` + // Estimated: `5777` + // Minimum execution time: 74_014_000 picoseconds. + Weight::from_parts(75_355_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: Did Did (r:1 w:0) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// The range of component `l` is `[1, 5242880]`. + fn signature_verification_sr25519(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1626` + // Estimated: `5777` + // Minimum execution time: 63_042_000 picoseconds. + Weight::from_parts(41_623_028, 0) + .saturating_add(Weight::from_parts(0, 5777)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(4_301, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: Did Did (r:1 w:0) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// The range of component `l` is `[1, 5242880]`. + fn signature_verification_ed25519(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1626` + // Estimated: `5777` + // Minimum execution time: 61_831_000 picoseconds. + Weight::from_parts(38_865_643, 0) + .saturating_add(Weight::from_parts(0, 5777)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(2_522, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: Did Did (r:1 w:0) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// The range of component `l` is `[1, 5242880]`. + fn signature_verification_ecdsa(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1627` + // Estimated: `5777` + // Minimum execution time: 50_295_000 picoseconds. + Weight::from_parts(27_300_442, 0) + .saturating_add(Weight::from_parts(0, 5777)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_153, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn change_deposit_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `822` + // Estimated: `5777` + // Minimum execution time: 73_863_000 picoseconds. + Weight::from_parts(76_051_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn update_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `888` + // Estimated: `5777` + // Minimum execution time: 45_375_000 picoseconds. + Weight::from_parts(46_464_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + + /// Storage: Did Did (r:1 w:0) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `353` + // Estimated: `5777` + // Minimum execution time: 186_836_000 picoseconds. + Weight::from_parts(189_377_000, 0) + .saturating_add(Weight::from_parts(0, 5777)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: Did DidBlacklist (r:1 w:0) + /// Proof: Did DidBlacklist (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Did Did (r:1 w:1) + /// Proof: Did Did (max_values: None, max_size: Some(2312), added: 4787, mode: MaxEncodedLen) + /// Storage: Did DidEndpointsCount (r:1 w:0) + /// Proof: Did DidEndpointsCount (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(949), added: 3424, mode: MaxEncodedLen) + fn create_from_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `999` + // Estimated: `6204` + // Minimum execution time: 1_008_739_000 picoseconds. + Weight::from_parts(1_020_810_000, 0) + .saturating_add(Weight::from_parts(0, 6204)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_create_ed25519_keys() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 6204 + ); + } + #[test] + fn test_create_sr25519_keys() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 6204 + ); + } + #[test] + fn test_create_ecdsa_keys() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 6204 + ); + } + #[test] + fn test_delete() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_reclaim_deposit() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_submit_did_call_ed25519_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_submit_did_call_sr25519_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_submit_did_call_ecdsa_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_ed25519_authentication_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_sr25519_authentication_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_ecdsa_authentication_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_ed25519_delegation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_sr25519_delegation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_ecdsa_delegation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_ed25519_delegation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_sr25519_delegation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_ecdsa_delegation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_ed25519_attestation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_sr25519_attestation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_set_ecdsa_attestation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_ed25519_attestation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_sr25519_attestation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_ecdsa_attestation_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_add_ed25519_key_agreement_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_add_sr25519_key_agreement_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_add_ecdsa_key_agreement_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_ed25519_key_agreement_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_sr25519_key_agreement_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_ecdsa_key_agreement_key() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_add_service_endpoint() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_remove_service_endpoint() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_signature_verification_sr25519() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_signature_verification_ed25519() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_signature_verification_ecdsa() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_change_deposit_owner() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_update_deposit() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + + #[test] + fn test_dispatch_as() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 5777 + ); + } + #[test] + fn test_create_from_account() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 6204 + ); + } +} diff --git a/dip-template/runtimes/dip-provider/src/weights/frame_system.rs b/dip-template/runtimes/dip-provider/src/weights/frame_system.rs new file mode 100644 index 000000000..3e821789c --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/frame_system.rs @@ -0,0 +1,193 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `frame_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-provider-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=frame-system +// --extrinsic=* +// --output=./dip-template/runtimes/dip-provider/src/weights/frame_system.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `frame_system`. +pub struct WeightInfo(PhantomData); +impl frame_system::WeightInfo for WeightInfo { + /// The range of component `b` is `[0, 3932160]`. + fn remark(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_320_000 picoseconds. + Weight::from_parts(1_367_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(223, 0).saturating_mul(b.into())) + } + /// The range of component `b` is `[0, 3932160]`. + fn remark_with_event(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_819_000 picoseconds. + Weight::from_parts(4_960_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(b.into())) + } + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + fn set_heap_pages() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 2_633_000 picoseconds. + Weight::from_parts(2_766_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `ParachainSystem::UpgradeRestrictionSignal` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingValidationCode` (r:1 w:1) + /// Proof: `ParachainSystem::PendingValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::NewValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::NewValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::DidSetValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::DidSetValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_code() -> Weight { + // Proof Size summary in bytes: + // Measured: `119` + // Estimated: `1604` + // Minimum execution time: 89_656_515_000 picoseconds. + Weight::from_parts(92_710_625_000, 0) + .saturating_add(Weight::from_parts(0, 1604)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `i` is `[0, 1000]`. + fn set_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_379_000 picoseconds. + Weight::from_parts(1_438_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_236 + .saturating_add(Weight::from_parts(591_504, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `i` is `[0, 1000]`. + fn kill_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_377_000 picoseconds. + Weight::from_parts(1_419_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 526 + .saturating_add(Weight::from_parts(413_184, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `p` is `[0, 1000]`. + fn kill_prefix(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `64 + p * (69 ±0)` + // Estimated: `65 + p * (70 ±0)` + // Minimum execution time: 2_657_000 picoseconds. + Weight::from_parts(2_737_000, 0) + .saturating_add(Weight::from_parts(0, 65)) + // Standard Error: 793 + .saturating_add(Weight::from_parts(806_524, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_set_heap_pages() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 1485 + ); + } + #[test] + fn test_set_code() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 1604 + ); + } + #[test] + fn test_kill_prefix() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 65 + ); + } +} diff --git a/dip-template/runtimes/dip-provider/src/weights/mod.rs b/dip-template/runtimes/dip-provider/src/weights/mod.rs new file mode 100644 index 000000000..22be9a259 --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/mod.rs @@ -0,0 +1,24 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub mod did; +pub mod frame_system; +pub mod pallet_deposit_storage; +pub mod pallet_did_lookup; +pub mod pallet_dip_provider; +pub mod pallet_web3_names; diff --git a/dip-template/runtimes/dip-provider/src/weights/pallet_deposit_storage.rs b/dip-template/runtimes/dip-provider/src/weights/pallet_deposit_storage.rs new file mode 100644 index 000000000..e675d6ec0 --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/pallet_deposit_storage.rs @@ -0,0 +1,85 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `pallet_deposit_storage` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-provider-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=pallet-deposit-storage +// --extrinsic=* +// --output=./dip-template/runtimes/dip-provider/src/weights/pallet_deposit_storage.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_deposit_storage`. +pub struct WeightInfo(PhantomData); +impl pallet_deposit_storage::WeightInfo for WeightInfo { + /// Storage: `DepositStorage::Deposits` (r:1 w:1) + /// Proof: `DepositStorage::Deposits` (`max_values`: None, `max_size`: Some(325), added: 2800, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `DipProvider::IdentityCommitments` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + fn reclaim_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `443` + // Estimated: `4414` + // Minimum execution time: 39_267_000 picoseconds. + Weight::from_parts(39_811_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_reclaim_deposit() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } +} diff --git a/dip-template/runtimes/dip-provider/src/weights/pallet_did_lookup.rs b/dip-template/runtimes/dip-provider/src/weights/pallet_did_lookup.rs new file mode 100644 index 000000000..4a9366ad6 --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/pallet_did_lookup.rs @@ -0,0 +1,321 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `pallet_did_lookup` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-provider-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=pallet-did-lookup +// --extrinsic=* +// --output=./dip-template/runtimes/dip-provider/src/weights/pallet_did_lookup.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_did_lookup`. +pub struct WeightInfo(PhantomData); +impl pallet_did_lookup::WeightInfo for WeightInfo { + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:2) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn associate_account_multisig_sr25519() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 115_816_000 picoseconds. + Weight::from_parts(150_087_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:2) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn associate_account_multisig_ed25519() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 119_599_000 picoseconds. + Weight::from_parts(175_393_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:2) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn associate_account_multisig_ecdsa() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 119_023_000 picoseconds. + Weight::from_parts(176_847_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:2) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn associate_eth_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `377` + // Estimated: `4414` + // Minimum execution time: 115_485_000 picoseconds. + Weight::from_parts(170_435_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:2) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn associate_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 70_488_000 picoseconds. + Weight::from_parts(75_207_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:1) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn remove_sender_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 37_873_000 picoseconds. + Weight::from_parts(40_493_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:0 w:1) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + fn remove_account_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 38_071_000 picoseconds. + Weight::from_parts(39_343_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:2 w:2) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn change_deposit_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `493` + // Estimated: `7838` + // Minimum execution time: 64_007_000 picoseconds. + Weight::from_parts(66_141_000, 0) + .saturating_add(Weight::from_parts(0, 7838)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `DidLookup::ConnectedDids` (r:1 w:1) + /// Proof: `DidLookup::ConnectedDids` (`max_values`: None, `max_size`: Some(129), added: 2604, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn update_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `390` + // Estimated: `4414` + // Minimum execution time: 58_458_000 picoseconds. + Weight::from_parts(59_907_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_associate_account_multisig_sr25519() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_associate_account_multisig_ed25519() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_associate_account_multisig_ecdsa() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_associate_eth_account() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_associate_sender() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_remove_sender_association() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_remove_account_association() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_change_deposit_owner() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 7838 + ); + } + #[test] + fn test_update_deposit() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } +} diff --git a/dip-template/runtimes/dip-provider/src/weights/pallet_dip_provider.rs b/dip-template/runtimes/dip-provider/src/weights/pallet_dip_provider.rs new file mode 100644 index 000000000..ad46d99eb --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/pallet_dip_provider.rs @@ -0,0 +1,125 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `pallet_dip_provider` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-provider-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=pallet-dip-provider +// --extrinsic=* +// --output=./dip-template/runtimes/dip-provider/src/weights/pallet_dip_provider.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_dip_provider`. +pub struct WeightInfo(PhantomData); +impl pallet_dip_provider::WeightInfo for WeightInfo { + /// Storage: `Did::Did` (r:1 w:0) + /// Proof: `Did::Did` (`max_values`: None, `max_size`: Some(1447), added: 3922, mode: `MaxEncodedLen`) + /// Storage: `Did::DidBlacklist` (r:1 w:0) + /// Proof: `Did::DidBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Names` (r:1 w:0) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:0) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:21 w:0) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + /// Storage: `DipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `DipProvider::IdentityCommitments` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `DepositStorage::Deposits` (r:1 w:1) + /// Proof: `DepositStorage::Deposits` (`max_values`: None, `max_size`: Some(325), added: 2800, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn commit_identity() -> Weight { + // Proof Size summary in bytes: + // Measured: `3190` + // Estimated: `55002` + // Minimum execution time: 236_589_000 picoseconds. + Weight::from_parts(266_691_000, 0) + .saturating_add(Weight::from_parts(0, 55002)) + .saturating_add(T::DbWeight::get().reads(29)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `DipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `DipProvider::IdentityCommitments` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `DepositStorage::Deposits` (r:1 w:1) + /// Proof: `DepositStorage::Deposits` (`max_values`: None, `max_size`: Some(325), added: 2800, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn delete_identity_commitment() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `4414` + // Minimum execution time: 51_471_000 picoseconds. + Weight::from_parts(56_814_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_commit_identity() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 55002 + ); + } + #[test] + fn test_delete_identity_commitment() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } +} diff --git a/dip-template/runtimes/dip-provider/src/weights/pallet_web3_names.rs b/dip-template/runtimes/dip-provider/src/weights/pallet_web3_names.rs new file mode 100644 index 000000000..e489a91e5 --- /dev/null +++ b/dip-template/runtimes/dip-provider/src/weights/pallet_web3_names.rs @@ -0,0 +1,265 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for `pallet_web3_names` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/dip-provider-node-template +// benchmark +// pallet +// --template=.maintain/runtime-weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --pallet=pallet-web3-names +// --extrinsic=* +// --output=./dip-template/runtimes/dip-provider/src/weights/pallet_web3_names.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_web3_names`. +pub struct WeightInfo(PhantomData); +impl pallet_web3_names::WeightInfo for WeightInfo { + /// Storage: `Web3Names::Names` (r:1 w:1) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:1) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Banned` (r:1 w:0) + /// Proof: `Web3Names::Banned` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// The range of component `n` is `[3, 32]`. + fn claim(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `4414` + // Minimum execution time: 113_246_000 picoseconds. + Weight::from_parts(132_782_588, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Web3Names::Names` (r:1 w:1) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:1) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn release_by_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `428` + // Estimated: `4414` + // Minimum execution time: 101_512_000 picoseconds. + Weight::from_parts(111_009_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Web3Names::Owner` (r:1 w:1) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Names` (r:0 w:1) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// The range of component `n` is `[3, 32]`. + fn reclaim_deposit(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `324 + n * (1 ±0)` + // Estimated: `4414` + // Minimum execution time: 36_756_000 picoseconds. + Weight::from_parts(94_263_229, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Web3Names::Banned` (r:1 w:1) + /// Proof: `Web3Names::Banned` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:1) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Names` (r:0 w:1) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// The range of component `n` is `[3, 32]`. + fn ban(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `324 + n * (1 ±0)` + // Estimated: `4414` + // Minimum execution time: 36_341_000 picoseconds. + Weight::from_parts(44_569_163, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Web3Names::Banned` (r:1 w:1) + /// Proof: `Web3Names::Banned` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// The range of component `n` is `[3, 32]`. + fn unban(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `47 + n * (1 ±0)` + // Estimated: `3514` + // Minimum execution time: 8_620_000 picoseconds. + Weight::from_parts(9_336_817, 0) + .saturating_add(Weight::from_parts(0, 3514)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Web3Names::Names` (r:1 w:0) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:1) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:2 w:2) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn change_deposit_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `531` + // Estimated: `7838` + // Minimum execution time: 60_074_000 picoseconds. + Weight::from_parts(61_305_000, 0) + .saturating_add(Weight::from_parts(0, 7838)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Web3Names::Owner` (r:1 w:1) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(133), added: 2608, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn update_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `357` + // Estimated: `4414` + // Minimum execution time: 55_049_000 picoseconds. + Weight::from_parts(55_580_000, 0) + .saturating_add(Weight::from_parts(0, 4414)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_claim() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_release_by_owner() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_reclaim_deposit() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_ban() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } + #[test] + fn test_unban() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 3514 + ); + } + #[test] + fn test_change_deposit_owner() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 7838 + ); + } + #[test] + fn test_update_deposit() { + assert!( + ::BlockWeights::get() + .per_class + .get(frame_support::dispatch::DispatchClass::Normal) + .max_extrinsic + .unwrap_or_else(::max_value) + .proof_size() + > 4414 + ); + } +} diff --git a/pallets/ctype/src/lib.rs b/pallets/ctype/src/lib.rs index a4c27d8f6..5936cd558 100644 --- a/pallets/ctype/src/lib.rs +++ b/pallets/ctype/src/lib.rs @@ -94,7 +94,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - type EnsureOrigin: EnsureOrigin<::RuntimeOrigin, Success = Self::OriginSuccess>; + type EnsureOrigin: EnsureOrigin; type OverarchingOrigin: EnsureOrigin<::RuntimeOrigin>; type OriginSuccess: CallSources, CtypeCreatorOf>; type RuntimeEvent: From> + IsType<::RuntimeEvent>; diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index f7046b6ae..586f41525 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -191,6 +191,13 @@ impl From for DidSignature { } } +#[cfg(feature = "runtime-benchmarks")] +impl kilt_support::traits::GetWorstCase for DidSignature { + fn worst_case(_context: Context) -> Self { + Self::Sr25519(sp_core::sr25519::Signature::from_raw([0u8; 64])) + } +} + pub trait DidVerifiableIdentifier { /// Allows a verifiable identifier to verify a signature it produces and /// return the public key diff --git a/pallets/did/src/origin.rs b/pallets/did/src/origin.rs index 92919482f..e5ac0ba53 100644 --- a/pallets/did/src/origin.rs +++ b/pallets/did/src/origin.rs @@ -18,7 +18,7 @@ use frame_support::{ codec::{Decode, Encode}, - traits::EnsureOrigin, + traits::{EnsureOrigin, EnsureOriginWithArg}, }; use kilt_support::traits::CallSources; use parity_scale_codec::MaxEncodedLen; @@ -66,6 +66,38 @@ where } } +impl EnsureOriginWithArg + for EnsureDidOrigin +where + OuterOrigin: Into, OuterOrigin>> + + From> + + Clone, + DidIdentifier: PartialEq + Clone, + AccountId: Clone + Decode, +{ + type Success = DidRawOrigin; + + fn try_origin(o: OuterOrigin, a: &DidIdentifier) -> Result { + let did_origin: DidRawOrigin = o.clone().into()?; + if did_origin.id == *a { + Ok(did_origin) + } else { + Err(o) + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &DidIdentifier) -> Result { + let zero_account_id = AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"); + + Ok(OuterOrigin::from(DidRawOrigin { + id: a.clone(), + submitter: zero_account_id, + })) + } +} + impl CallSources for DidRawOrigin { diff --git a/pallets/pallet-deposit-storage/Cargo.toml b/pallets/pallet-deposit-storage/Cargo.toml new file mode 100644 index 000000000..1865c4ea8 --- /dev/null +++ b/pallets/pallet-deposit-storage/Cargo.toml @@ -0,0 +1,61 @@ +[package] +authors.workspace = true +description = "Stores all deposits under a single pallet, with suport for namespacing different deposit contexts." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-deposit-storage" +readme.workspace = true +repository.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +pallet-balances = {workspace = true, features = ["std"]} +sp-io = {workspace = true, features = ["std"]} +sp-keystore = {workspace = true, features = ["std"]} + +[dependencies] +# Substrate dependencies +frame-support.workspace = true +frame-system.workspace = true +kilt-support.workspace = true +log.workspace = true +pallet-dip-provider.workspace = true +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} +sp-runtime.workspace = true +sp-std.workspace = true + +# Benchmarking +frame-benchmarking = {workspace = true, optional = true} +pallet-balances = {workspace = true, optional = true} + +[features] +default = ["std"] +std = [ + "frame-support/std", + "frame-system/std", + "kilt-support/std", + "log/std", + "pallet-dip-provider/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", + "frame-benchmarking?/std", + "pallet-balances?/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "kilt-support/runtime-benchmarks", + "pallet-dip-provider/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", +] +try-runtime = [] diff --git a/pallets/pallet-deposit-storage/src/benchmarking.rs b/pallets/pallet-deposit-storage/src/benchmarking.rs new file mode 100644 index 000000000..eb69d6a6f --- /dev/null +++ b/pallets/pallet-deposit-storage/src/benchmarking.rs @@ -0,0 +1,85 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_benchmarking::v2::*; + +#[benchmarks( + where + T: Config + pallet_balances::Config, +)] +mod benchmarks { + use frame_support::traits::fungible::Mutate; + use frame_system::RawOrigin; + use kilt_support::Deposit; + use sp_runtime::SaturatedConversion; + + use crate::{traits::BenchmarkHooks, Call, Config, DepositEntryOf, Deposits, HoldReason, Pallet}; + + use super::*; + + const KILT: u128 = 10u128.pow(15); + + #[benchmark] + fn reclaim_deposit() { + let (submitter, namespace, key) = T::BenchmarkHooks::pre_reclaim_deposit(); + + assert!(Deposits::::get(&namespace, &key).is_none()); + + let entry = DepositEntryOf:: { + deposit: Deposit { + amount: KILT.saturated_into(), + owner: submitter.clone(), + }, + reason: ::RuntimeHoldReason::from(HoldReason::Deposit), + }; + + let amount = KILT * 100; + + as Mutate<::AccountId>>::set_balance( + &submitter, + amount.saturated_into(), + ); + + Pallet::::add_deposit(namespace.clone(), key.clone(), entry).expect("Creating Deposit should not fail."); + + assert!(Deposits::::get(&namespace, &key).is_some()); + + let origin = RawOrigin::Signed(submitter); + let cloned_namespace = namespace.clone(); + let cloned_key = key.clone(); + + #[extrinsic_call] + Pallet::::reclaim_deposit(origin, cloned_namespace, cloned_key); + + assert!(Deposits::::get(&namespace, &key).is_none()); + + T::BenchmarkHooks::post_reclaim_deposit(); + } + + #[cfg(test)] + mod benchmarks_tests { + use crate::Pallet; + use frame_benchmarking::impl_benchmark_test_suite; + + impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().build_with_keystore(), + crate::mock::TestRuntime, + ); + } +} diff --git a/pallets/pallet-deposit-storage/src/default_weights.rs b/pallets/pallet-deposit-storage/src/default_weights.rs new file mode 100644 index 000000000..6d0618067 --- /dev/null +++ b/pallets/pallet-deposit-storage/src/default_weights.rs @@ -0,0 +1,73 @@ + +//! Autogenerated weights for pallet_deposit_storage +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-24 +//! STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/kilt-parachain +// benchmark +// pallet +// --pallet +// pallet-deposit-storage +// --extrinsic +// * +// --template +// ./.maintain/weight-template.hbs +// --output +// ./pallets/pallet-deposit-storage/src/defaul_weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_deposit_storage. +pub trait WeightInfo { + fn reclaim_deposit() -> Weight; +} + +/// Weights for pallet_deposit_storage using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `StorageDeposit::Deposits` (r:1 w:1) + /// Proof: `StorageDeposit::Deposits` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(132), added: 2607, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn reclaim_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `907` + // Estimated: `4414` + // Minimum execution time: 704_964 nanoseconds. + Weight::from_parts(1_003_107_000, 4414) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: `StorageDeposit::Deposits` (r:1 w:1) + /// Proof: `StorageDeposit::Deposits` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(132), added: 2607, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(949), added: 3424, mode: `MaxEncodedLen`) + fn reclaim_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `907` + // Estimated: `4414` + // Minimum execution time: 704_964 nanoseconds. + Weight::from_parts(1_003_107_000, 4414) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} diff --git a/pallets/pallet-deposit-storage/src/deposit.rs b/pallets/pallet-deposit-storage/src/deposit.rs new file mode 100644 index 000000000..927300aad --- /dev/null +++ b/pallets/pallet-deposit-storage/src/deposit.rs @@ -0,0 +1,179 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{ + sp_runtime::DispatchError, + traits::{ + fungible::{hold::Mutate, Inspect}, + tokens::Precision, + }, +}; +use kilt_support::Deposit; +use pallet_dip_provider::{traits::ProviderHooks as DipProviderHooks, IdentityCommitmentOf, IdentityCommitmentVersion}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::traits::Get; +use sp_std::marker::PhantomData; + +use crate::{BalanceOf, Config, Error, HoldReason, Pallet}; + +/// Details associated to an on-chain deposit. +#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, TypeInfo, MaxEncodedLen)] +pub struct DepositEntry { + /// The [`Deposit`] entry. + pub deposit: Deposit, + /// The `Reason` for the deposit. + pub reason: Reason, +} + +/// Type implementing the [`DipProviderHooks`] hooks trait by taking a deposit +/// whenever an identity commitment is stored, and releasing the deposit +/// whenever an identity commitment is removed. +pub struct FixedDepositCollectorViaDepositsPallet( + PhantomData<(DepositsNamespace, FixedDepositAmount, DepositKey)>, +); + +pub enum FixedDepositCollectorViaDepositsPalletError { + DepositAlreadyTaken, + DepositNotFound, + FailedToHold, + FailedToRelease, + Internal, +} + +impl From for u16 { + fn from(value: FixedDepositCollectorViaDepositsPalletError) -> Self { + match value { + FixedDepositCollectorViaDepositsPalletError::DepositAlreadyTaken => 0, + FixedDepositCollectorViaDepositsPalletError::DepositNotFound => 1, + FixedDepositCollectorViaDepositsPalletError::FailedToHold => 2, + FixedDepositCollectorViaDepositsPalletError::FailedToRelease => 3, + FixedDepositCollectorViaDepositsPalletError::Internal => u16::MAX, + } + } +} + +impl DipProviderHooks + for FixedDepositCollectorViaDepositsPallet +where + Runtime: pallet_dip_provider::Config + Config, + DepositsNamespace: Get, + FixedDepositAmount: Get>, + DepositKey: From<(Runtime::Identifier, IdentityCommitmentVersion)> + Encode, +{ + type Error = u16; + + fn on_identity_committed( + identifier: &Runtime::Identifier, + submitter: &Runtime::AccountId, + _commitment: &IdentityCommitmentOf, + version: IdentityCommitmentVersion, + ) -> Result<(), Self::Error> { + let namespace = DepositsNamespace::get(); + let key = DepositKey::from((identifier.clone(), version)) + .encode() + .try_into() + .map_err(|_| { + log::error!( + "Failed to convert tuple ({:#?}, {version}) to BoundedVec with max length {}", + identifier, + Runtime::MaxKeyLength::get() + ); + FixedDepositCollectorViaDepositsPalletError::Internal + })?; + let deposit_entry = DepositEntry { + deposit: Deposit { + amount: FixedDepositAmount::get(), + owner: submitter.clone(), + }, + reason: HoldReason::Deposit.into(), + }; + Pallet::::add_deposit(namespace, key, deposit_entry).map_err(|e| match e { + pallet_error if pallet_error == DispatchError::from(Error::::DepositExisting) => { + FixedDepositCollectorViaDepositsPalletError::DepositAlreadyTaken + } + _ => { + log::error!( + "Error {:#?} should not be generated inside `on_identity_committed` hook.", + e + ); + FixedDepositCollectorViaDepositsPalletError::Internal + } + })?; + Ok(()) + } + + fn on_commitment_removed( + identifier: &Runtime::Identifier, + _submitter: &Runtime::AccountId, + _commitment: &IdentityCommitmentOf, + version: pallet_dip_provider::IdentityCommitmentVersion, + ) -> Result<(), Self::Error> { + let namespace = DepositsNamespace::get(); + let key = (identifier, version).encode().try_into().map_err(|_| { + log::error!( + "Failed to convert tuple ({:#?}, {version}) to BoundedVec with max length {}", + identifier, + Runtime::MaxKeyLength::get() + ); + FixedDepositCollectorViaDepositsPalletError::Internal + })?; + Pallet::::remove_deposit(&namespace, &key, None).map_err(|e| match e { + pallet_error if pallet_error == DispatchError::from(Error::::DepositNotFound) => { + FixedDepositCollectorViaDepositsPalletError::DepositNotFound + } + _ => { + log::error!( + "Error {:#?} should not be generated inside `on_commitment_removed` hook.", + e + ); + FixedDepositCollectorViaDepositsPalletError::Internal + } + })?; + Ok(()) + } +} + +// Taken from dip_support logic, not to make that pub +pub(crate) fn reserve_deposit>( + account: Account, + deposit_amount: Currency::Balance, + reason: &Currency::Reason, +) -> Result, DispatchError> { + Currency::hold(reason, &account, deposit_amount)?; + Ok(Deposit { + owner: account, + amount: deposit_amount, + }) +} + +// Taken from dip_support logic, not to make that pub +pub(crate) fn free_deposit>( + deposit: &Deposit, + reason: &Currency::Reason, +) -> Result<>::Balance, DispatchError> { + let result = Currency::release(reason, &deposit.owner, deposit.amount, Precision::BestEffort); + debug_assert!( + result == Ok(deposit.amount), + "Released deposit amount does not match with expected amount. Expected: {:?}, Released amount: {:?} Error: {:?}", + deposit.amount, + result.ok(), + result.err(), + ); + result +} diff --git a/pallets/pallet-deposit-storage/src/lib.rs b/pallets/pallet-deposit-storage/src/lib.rs new file mode 100644 index 000000000..0043f9eed --- /dev/null +++ b/pallets/pallet-deposit-storage/src/lib.rs @@ -0,0 +1,226 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Pallet to store namespaced deposits for the configured `Currency`. It allows +//! the original payer of a deposit to claim it back, triggering a hook to +//! optionally perform related actions somewhere else in the runtime. +//! Each deposit is identified by a namespace and a key. There cannot be two +//! equal keys under the same namespace, but the same key can be present under +//! different namespaces. + +#![cfg_attr(not(feature = "std"), no_std)] + +mod default_weights; +mod deposit; +pub mod traits; + +#[cfg(test)] +mod mock; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +pub use crate::{ + default_weights::WeightInfo, deposit::FixedDepositCollectorViaDepositsPallet, pallet::*, + traits::NoopDepositStorageHooks, +}; + +#[frame_support::pallet] +pub mod pallet { + use crate::{ + default_weights::WeightInfo, + deposit::{free_deposit, reserve_deposit, DepositEntry}, + traits::DepositStorageHooks, + }; + + use super::*; + + use frame_support::{ + pallet_prelude::*, + traits::{ + fungible::{hold::Mutate, Inspect}, + EnsureOrigin, + }, + }; + use frame_system::pallet_prelude::*; + use parity_scale_codec::FullCodec; + use scale_info::TypeInfo; + use sp_runtime::DispatchError; + use sp_std::fmt::Debug; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + pub type AccountIdOf = ::AccountId; + pub type BalanceOf = <::Currency as Inspect>>::Balance; + pub type DepositKeyOf = BoundedVec::MaxKeyLength>; + pub type DepositEntryOf = DepositEntry, BalanceOf, ::RuntimeHoldReason>; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The maximum length of keys. + #[pallet::constant] + type MaxKeyLength: Get; + + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHooks: crate::traits::BenchmarkHooks; + /// The origin check, returning an `AccountId` upon completion, for who + /// can reclaim a deposit. + type CheckOrigin: EnsureOrigin; + /// The currency from which deposits are to be taken. + type Currency: Mutate; + /// Additional logic to execute whenever a new deposit a created or a + /// deposit is released. + type DepositHooks: DepositStorageHooks; + /// The type of a deposit namespace. + type Namespace: Parameter + MaxEncodedLen; + /// The aggregated `Event` type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The aggregated `HoldReason` type. + type RuntimeHoldReason: From + Clone + PartialEq + Debug + FullCodec + MaxEncodedLen + TypeInfo; + type WeightInfo: WeightInfo; + } + + /// The hold reasons for deposits taken by the pallet. + #[pallet::composite_enum] + pub enum HoldReason { + Deposit, + } + + #[pallet::error] + pub enum Error { + /// The deposit with the provided key was not found within the specified + /// namespace. + DepositNotFound, + /// A deposit with the provided key already exists within the specified + /// namespace. + DepositExisting, + /// The origin was not authorized to perform the operation on the + /// specified deposit entry. + Unauthorized, + /// The external hook failed. + Hook(u16), + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A new deposit has been reserved and stored. + DepositAdded { + /// The deposit namespace. + namespace: T::Namespace, + /// The deposit key. + key: DepositKeyOf, + /// The deposit details. + deposit_entry: DepositEntryOf, + }, + /// A deposit has been released and deleted from storage. + DepositReclaimed { + /// The deposit namespace. + namespace: T::Namespace, + /// The deposit key. + key: DepositKeyOf, + /// The deposit details. + deposit_entry: DepositEntryOf, + }, + } + + /// Storage of all deposits. Its first key is a namespace, and the second + /// one the deposit key. Its value includes the details associated to a + /// deposit instance. + #[pallet::storage] + #[pallet::getter(fn deposits)] + pub(crate) type Deposits = + StorageDoubleMap<_, Twox64Concat, ::Namespace, Twox64Concat, DepositKeyOf, DepositEntryOf>; + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + /// Reclaim a deposit that was previously taken. If there is no deposit + /// with the given key under the given namespace, it returns an error. + /// If a deposit exists, the deposit hooks are invoked after the deposit + /// has been removed from the pallet storage. + #[pallet::call_index(0)] + #[pallet::weight({ + ::WeightInfo::reclaim_deposit() + })] + pub fn reclaim_deposit(origin: OriginFor, namespace: T::Namespace, key: DepositKeyOf) -> DispatchResult { + let dispatcher = T::CheckOrigin::ensure_origin(origin)?; + + let deposit = Self::remove_deposit(&namespace, &key, Some(&dispatcher))?; + T::DepositHooks::on_deposit_reclaimed(&namespace, &key, deposit).map_err(|e| Error::::Hook(e.into()))?; + Ok(()) + } + } + + impl Pallet { + /// Add a deposit identified by the given key under the given namespace. + /// If there is already a deposit entry for the same key under the same + /// namespace, it returns an error. It also returns an error if the + /// deposit cannot be reserved on the pallet's `Currency`. + pub fn add_deposit(namespace: T::Namespace, key: DepositKeyOf, entry: DepositEntryOf) -> DispatchResult { + Deposits::::try_mutate(&namespace, &key, |deposit_entry| match deposit_entry { + Some(_) => Err(DispatchError::from(Error::::DepositExisting)), + None => { + reserve_deposit::, T::Currency>( + entry.deposit.owner.clone(), + entry.deposit.amount, + &entry.reason, + )?; + Self::deposit_event(Event::::DepositAdded { + namespace: namespace.clone(), + key: key.clone(), + deposit_entry: entry.clone(), + }); + *deposit_entry = Some(entry); + Ok(()) + } + })?; + Ok(()) + } + + /// Remove and release a deposit identified by the given key under the + /// given namespace. If there is no deposit with under the provided + /// namespace with the provided key, it returns an error. It also + /// returns an error if the deposit cannot be released on the pallet's + /// `Currency`. + pub fn remove_deposit( + namespace: &T::Namespace, + key: &DepositKeyOf, + expected_owner: Option<&AccountIdOf>, + ) -> Result, DispatchError> { + let existing_entry = Deposits::::take(namespace, key).ok_or(Error::::DepositNotFound)?; + if let Some(expected_owner) = expected_owner { + ensure!( + existing_entry.deposit.owner == *expected_owner, + Error::::Unauthorized + ); + } + free_deposit::, T::Currency>(&existing_entry.deposit, &existing_entry.reason)?; + Self::deposit_event(Event::::DepositReclaimed { + namespace: namespace.clone(), + key: key.clone(), + deposit_entry: existing_entry.clone(), + }); + Ok(existing_entry) + } + } +} diff --git a/pallets/pallet-deposit-storage/src/mock.rs b/pallets/pallet-deposit-storage/src/mock.rs new file mode 100644 index 000000000..f53c2ae31 --- /dev/null +++ b/pallets/pallet-deposit-storage/src/mock.rs @@ -0,0 +1,129 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{ + construct_runtime, parameter_types, + sp_runtime::{ + testing::H256, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, + }, + traits::{ConstU16, ConstU32, ConstU64, Everything}, +}; +use frame_system::{mocking::MockBlock, EnsureSigned}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; + +use crate::{self as storage_deposit_pallet, NoopDepositStorageHooks}; + +pub(crate) type Balance = u128; + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug, Default)] +pub enum DepositNamespaces { + #[default] + ExampleNameSpaces, +} + +construct_runtime!( + pub struct TestRuntime { + System: frame_system, + StorageDepositPallet: storage_deposit_pallet, + Balances: pallet_balances, + } +); + +impl frame_system::Config for TestRuntime { + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId32; + type BaseCallFilter = Everything; + type Block = MockBlock; + type BlockHashCount = ConstU64<256>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<1>; + type SystemWeightInfo = (); + type Version = (); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 500; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; + pub const MaxHolds: u32 = 50; + pub const MaxFreezes: u32 = 50; +} + +impl pallet_balances::Config for TestRuntime { + type FreezeIdentifier = RuntimeFreezeReason; + type RuntimeHoldReason = RuntimeHoldReason; + type MaxFreezes = MaxFreezes; + type MaxHolds = MaxHolds; + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; +} + +impl crate::Config for TestRuntime { + type CheckOrigin = EnsureSigned; + type Currency = Balances; + type DepositHooks = NoopDepositStorageHooks; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type MaxKeyLength = ConstU32<256>; + type Namespace = DepositNamespaces; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHooks = (); + type WeightInfo = (); +} + +#[derive(Default)] +pub(crate) struct ExtBuilder; + +impl ExtBuilder { + pub fn _build(self) -> sp_io::TestExternalities { + sp_io::TestExternalities::default() + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn build_with_keystore(self) -> sp_io::TestExternalities { + let mut ext = self._build(); + let keystore = sp_keystore::testing::MemoryKeystore::new(); + ext.register_extension(sp_keystore::KeystoreExt(sp_std::sync::Arc::new(keystore))); + ext + } +} diff --git a/pallets/pallet-deposit-storage/src/traits.rs b/pallets/pallet-deposit-storage/src/traits.rs new file mode 100644 index 000000000..fb0270e76 --- /dev/null +++ b/pallets/pallet-deposit-storage/src/traits.rs @@ -0,0 +1,90 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{Config, DepositEntryOf, DepositKeyOf}; + +/// A trait to configure additional custom logic whenever a deposit-related +/// operation takes place. +pub trait DepositStorageHooks +where + Runtime: Config, +{ + type Error: Into; + + /// Called by the pallet whenever a deposit for a given namespace and key is + /// removed. + fn on_deposit_reclaimed( + namespace: &Runtime::Namespace, + key: &DepositKeyOf, + deposit: DepositEntryOf, + ) -> Result<(), Self::Error>; +} + +/// Dummy implementation of the [`DepositStorageHooks`] trait that does a noop. +pub struct NoopDepositStorageHooks; + +impl DepositStorageHooks for NoopDepositStorageHooks +where + Runtime: Config, +{ + type Error = u16; + + fn on_deposit_reclaimed( + _namespace: &Runtime::Namespace, + _key: &DepositKeyOf, + _deposit: DepositEntryOf, + ) -> Result<(), Self::Error> { + Ok(()) + } +} + +// Could be expanded to include traits to set up stuff before all benchmarks, +// and before each benchmark case specifically. +#[cfg(feature = "runtime-benchmarks")] +pub trait BenchmarkHooks +where + Runtime: Config, +{ + fn pre_reclaim_deposit() -> ( + Runtime::AccountId, + Runtime::Namespace, + sp_runtime::BoundedVec, + ); + fn post_reclaim_deposit(); +} + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHooks for () +where + Runtime: Config, + Runtime::AccountId: From<[u8; 32]>, + Runtime::Namespace: Default, +{ + fn pre_reclaim_deposit() -> ( + Runtime::AccountId, + Runtime::Namespace, + sp_runtime::BoundedVec, + ) { + ( + Runtime::AccountId::from([100u8; 32]), + Runtime::Namespace::default(), + sp_runtime::BoundedVec::default(), + ) + } + fn post_reclaim_deposit() {} +} diff --git a/pallets/pallet-dip-consumer/Cargo.toml b/pallets/pallet-dip-consumer/Cargo.toml new file mode 100644 index 000000000..ac4758d3f --- /dev/null +++ b/pallets/pallet-dip-consumer/Cargo.toml @@ -0,0 +1,57 @@ +[package] +authors.workspace = true +description = "Pallet enabling receiving identity information from providers via the pallet-dip-provider pallet." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-dip-consumer" +readme = "README.md" +repository.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +sp-io = {workspace = true, features = ["std"]} +sp-keystore = {workspace = true, features = ["std"]} +sp-runtime = {workspace = true, features = ["std"]} + +[dependencies] +cfg-if.workspace = true +frame-support.workspace = true +frame-system.workspace = true +kilt-support.workspace = true +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} +sp-core.workspace = true +sp-std.workspace = true + +# Benchmarks +frame-benchmarking = {workspace = true, optional = true} +sp-runtime = {workspace = true, optional = true} + +[features] +default = [ "std" ] + +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "kilt-support/runtime-benchmarks", + "frame-benchmarking", + "sp-runtime/runtime-benchmarks", +] +std = [ + "frame-support/std", + "frame-system/std", + "kilt-support/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-core/std", + "sp-std/std", + "frame-benchmarking?/std", + "sp-runtime?/std", +] + +try-runtime = [] diff --git a/pallets/pallet-dip-consumer/README.md b/pallets/pallet-dip-consumer/README.md new file mode 100644 index 000000000..e19a811d0 --- /dev/null +++ b/pallets/pallet-dip-consumer/README.md @@ -0,0 +1,60 @@ +# Decentralized Identity Provider (DIP) provider consumer pallet + +This pallet is a core component of the Decentralized Identity Provider protocol. +It enables entities with an identity on a connected Substrate-based chain (provider) to use those identities on the chain this pallet is deployed (consumers) without requiring those entities to set up a new identity locally. +A consumer chain is *connected* to a provider if there is a way for the consumer chain to verify state proofs about parts of the state of the provider chain. + +A cross-chain transaction with DIP assumes the entity submitting the transaction has already generated a cross-chain identity commitment on the provider chain, by interacting with the DIP provider pallet on the provider chain. +With a generated identity commitment, a cross-chain transaction flow for a generic entity `A` works as follows: + +1. `A` generates a state proof proving the state of the identity commitment on the provider chain. +2. `A` generates any additional information required for an identity proof to be successfully verified by the consumer runtime. +3. `A`, using their account `AccC` on the consumer chain, calls the `dispatch_as` extrinsic by providing its identifier on the provider chain, the generated proof, and the `Call` to be dispatched on the consumer chain. + 1. This pallet verifies if the proof is correct, if not it returns an error. + 2. This pallet dispatches the provided `Call` with a new origin created by this pallet, returning any errors the dispatch action returns. The origin contains the information revealed in the proof, the identifier of the acting subject and the account `AccC` dispatching the transaction. + +The pallet is agnostic over the chain-specific definition of *identity proof verifier* and *identifier*, although, when deployed, they must be configured to respect the definition of identity and identity commitment established by the provider this pallet is linked to. + +For instance, if the provider establishes that an identity commitment is a Merkle root of a set of public keys, an identity proof for the consumer will most likely be a Merkle proof revealing a subset of those keys. +Similarly, if the provider defines an identity commitment as some ZK-commitment, the respective identity proof on the consumer chain will be a ZK-proof verifying the validity of the commitment and therefore of the revealed information. + +For identifiers, if the provider establishes that an identifier is a public key, the same definition must be used in the consumer pallet. +Other definitions for an identifier, such as a simple integer or a [Decentralized Identifier (DID)](https://www.w3.org/TR/did-core/), must also be configured in the same way. + +The pallet allows the consumer runtime to define some `LocalIdentityInfo` associated with each identifier, which the pallet's proof verifier can access and optionally modify upon proof verification. +Any changes made to the `LocalIdentityInfo` will be persisted if the identity proof is verified correctly and the extrinsic executed successfully. + +If the consumer does not need to store anything in addition to the information an identity proof conveys, they can use an empty tuple `()` for the local identity info. +Another example could be the use of signatures, which requires a nonce to avoid replay protections. +In this case, a numeric type such as a `u64` or a `u128` could be used, and increased by the proof verifier when validating each new cross-chain transaction proof. + +## The `Config` trait + +Being chain-agnostic, most of the runtime configurations must be passed to the pallet's `Config` trait. +Nevertheless, most of the types provided must reflect the definition of identity and identity commitment that the identity provider chain has established. +The trait has the following components: + +* `type DipCallOriginFilter: Contains>`: A preliminary filter that checks whether a provided `Call` accepts a DIP origin or not. If a call such as a system call does not accept a DIP origin, there is no need to verify the identity proof, hence the execution can bail out early. This does not guarantee that the dispatch call will succeed, but rather than it will mostly not fail with a `BadOrigin` error. +* `type DispatchOriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::AccountId>`: The origin check on the `dispatch_as` extrinsic to verify that the caller is authorized to call the extrinsic. If successful, the check must return a `AccountId` as defined by the consumer runtime. +* `type Identifier: Parameter + MaxEncodedLen`: The type of a subject identifier. This must match the definition of `Identifier` the identity provider has defined in their deployment of the provider pallet. +* `type LocalIdentityInfo: FullCodec + TypeInfo + MaxEncodedLen`: Any additional information that must be available only to the provider runtime that is required to provide additional context when verifying a cross-chain identity proof. +* `type ProofVerifier: IdentityProofVerifier`: The core component of this pallet. It takes care of validating an identity proof and optionally update any `LocalIdentityInfo`. It also defines, via its associated type, the structure of the identity proof that must be passed to the `dispatch_as` extrinsic. Although not directly, the proof structure depends on the information that goes into the identity commitment on the provider chain, as that defines what information can be revealed as part of the commitment proof. Additional info to satisfy requirements according to the `LocalIdentityInfo` (e.g., a signature) must also be provided in the proof. +* `type RuntimeCall: Parameter + Dispatchable::RuntimeOrigin>`: The aggregated `Call` type. +* `type RuntimeOrigin: From> + From<::RuntimeOrigin>`: The aggregated `Origin` type, which must include the origin exposed by this pallet. + +## Storage + +The pallet contains a single storage element, the `IdentityEntries` map. +It maps from a subject `Identifier` to an instance of `LocalIdentityInfo`. + +This information is updated by the proof verifier whenever a new cross-chain transaction and its proof is submitted. + +## Origin + +Because the pallet allows other `Call`s to be dispatched after an identity proof has been verified, it also exposes a `Origin` that can be used for those calls that require indeed a call to be DIP-authorized. + +The origin is created after the identity proof has been successfully verified by the proof verifier, and it includes the identifier of the subject, the address of the tx submitter, and the result returned by the proof verifier upon successful verification. + +## Calls (bullet numbers represent each call's encoded index) + +0. `pub fn dispatch_as(origin: OriginFor, identifier: T::Identifier, proof: IdentityProofOf, call: Box>) -> DispatchResult`: Try to dispatch a new local call only if it passes all the DIP requirements. Specifically, the call will be dispatched if it passes the preliminary `DipCallOriginFilter` and if the proof verifier returns an `Ok(verification_result)` value. The value is then added to the `DipOrigin` and passed down as the origin for the specified `Call`. If the whole execution terminates successfully, any changes applied to the `LocalIdentityInfo` by the proof verifier are persisted to the pallet storage. diff --git a/pallets/pallet-dip-consumer/src/benchmarking.rs b/pallets/pallet-dip-consumer/src/benchmarking.rs new file mode 100644 index 000000000..78782b4d0 --- /dev/null +++ b/pallets/pallet-dip-consumer/src/benchmarking.rs @@ -0,0 +1,85 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{traits::IdentityProofVerifier, Call, Config, IdentityEntries, Pallet}; +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; +use kilt_support::{ + benchmark::IdentityContext, + traits::{GetWorstCase, Instanciate}, +}; + +#[benchmarks( + where + T::AccountId: Instanciate, + T::Identifier: Instanciate, + <::ProofVerifier as IdentityProofVerifier>::Proof: GetWorstCase>, + ::RuntimeCall: From>, +)] +mod benchmarks { + + use super::*; + + type IdentityContextOf = + IdentityContext<::Identifier, ::AccountId>; + + #[benchmark] + fn dispatch_as() { + let submitter = T::AccountId::new(1); + let subject = T::Identifier::new(1); + + let context = IdentityContext:: { + did: subject.clone(), + submitter: submitter.clone(), + }; + + assert!(IdentityEntries::::get(&subject).is_none()); + + let origin = RawOrigin::Signed(submitter); + + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + + let boxed_call = Box::from(call); + + let proof = <<::ProofVerifier as IdentityProofVerifier>::Proof as GetWorstCase< + IdentityContextOf, + >>::worst_case(context); + + let origin = ::RuntimeOrigin::from(origin); + + #[extrinsic_call] + Pallet::::dispatch_as( + origin as ::RuntimeOrigin, + subject, + proof, + boxed_call, + ); + } + + #[cfg(test)] + mod benchmarks_tests { + use crate::Pallet; + use frame_benchmarking::impl_benchmark_test_suite; + + impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().build_with_keystore(), + crate::mock::TestRuntime, + ); + } +} diff --git a/pallets/pallet-dip-consumer/src/default_weights.rs b/pallets/pallet-dip-consumer/src/default_weights.rs new file mode 100644 index 000000000..f425e7da3 --- /dev/null +++ b/pallets/pallet-dip-consumer/src/default_weights.rs @@ -0,0 +1,65 @@ + +//! Autogenerated weights for pallet_dip_consumer +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-23 +//! STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/kilt-parachain +// benchmark +// pallet +// --pallet +// pallet-dip-consumer +// --extrinsic +// * +// --template +// ./.maintain/weight-template.hbs +// --output +// ./pallets/pallet-dip-consumer/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_dip_consumer. +pub trait WeightInfo { + fn dispatch_as() -> Weight; +} + +/// Weights for pallet_dip_consumer using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `PalletDipConsumer::IdentityEntries` (r:1 w:1) + /// Proof: `PalletDipConsumer::IdentityEntries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 127_413 nanoseconds. + Weight::from_parts(129_497_000, 3612) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: `PalletDipConsumer::IdentityEntries` (r:1 w:1) + /// Proof: `PalletDipConsumer::IdentityEntries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 127_413 nanoseconds. + Weight::from_parts(129_497_000, 3612) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/pallets/pallet-dip-consumer/src/lib.rs b/pallets/pallet-dip-consumer/src/lib.rs new file mode 100644 index 000000000..ea6125d7b --- /dev/null +++ b/pallets/pallet-dip-consumer/src/lib.rs @@ -0,0 +1,189 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![cfg_attr(not(feature = "std"), no_std)] +#![doc = include_str!("../README.md")] + +pub mod traits; + +mod default_weights; + +#[cfg(test)] +pub mod mock; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +mod origin; + +pub use crate::{default_weights::WeightInfo, origin::*, pallet::*, traits::SuccessfulProofVerifier}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + use frame_support::{ + dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, + pallet_prelude::*, + traits::{Contains, EnsureOriginWithArg}, + Twox64Concat, + }; + use frame_system::pallet_prelude::*; + use parity_scale_codec::{FullCodec, MaxEncodedLen}; + use scale_info::TypeInfo; + use sp_std::boxed::Box; + + use crate::traits::IdentityProofVerifier; + + pub type IdentityProofOf = <::ProofVerifier as IdentityProofVerifier>::Proof; + pub type RuntimeCallOf = ::RuntimeCall; + pub type VerificationResultOf = <::ProofVerifier as IdentityProofVerifier>::VerificationResult; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// A preliminary filter that checks whether a provided `Call` accepts a + /// DIP origin or not. If a call such as a system call does not accept a + /// DIP origin, there is no need to verify the identity proof, hence the + /// execution can bail out early. This does not guarantee that the + /// dispatch call will succeed, but rather than it will mostly not fail + /// with a `BadOrigin` error. + type DipCallOriginFilter: Contains>; + /// The origin check on the `dispatch_as` extrinsic to verify that the + /// caller is authorized to call the extrinsic. If successful, the check + /// must return a `AccountId` as defined by the consumer runtime. + type DispatchOriginCheck: EnsureOriginWithArg< + ::RuntimeOrigin, + Self::Identifier, + Success = Self::AccountId, + >; + /// The type of a subject identifier. This must match the definition of + /// `Identifier` the identity provider has defined in their deployment + /// of the provider pallet. + type Identifier: Parameter + MaxEncodedLen; + /// Any additional information that must be available only to the + /// provider runtime that is required to provide additional context when + /// verifying a cross-chain identity proof. + type LocalIdentityInfo: FullCodec + TypeInfo + MaxEncodedLen; + /// The core component of this pallet. It takes care of validating an + /// identity proof and optionally update any `LocalIdentityInfo`. It + /// also defines, via its associated type, the structure of the identity + /// proof that must be passed to the `dispatch_as` extrinsic. Although + /// not directly, the proof structure depends on the information that + /// goes into the identity commitment on the provider chain, as that + /// defines what information can be revealed as part of the commitment + /// proof. Additional info to satisfy requirements according to the + /// `LocalIdentityInfo` (e.g., a signature) must also be provided in the + /// proof. + type ProofVerifier: IdentityProofVerifier; + /// The aggregated `Call` type. + type RuntimeCall: Parameter + + Dispatchable::RuntimeOrigin> + + GetDispatchInfo; + /// The aggregated `Origin` type, which must include the origin exposed + /// by this pallet. + type RuntimeOrigin: From> + From<::RuntimeOrigin>; + type WeightInfo: WeightInfo; + } + + /// The pallet contains a single storage element, the `IdentityEntries` map. + /// It maps from a subject `Identifier` to an instance of + /// `LocalIdentityInfo`. + #[pallet::storage] + #[pallet::getter(fn identity_proofs)] + pub(crate) type IdentityEntries = + StorageMap<_, Twox64Concat, ::Identifier, ::LocalIdentityInfo>; + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::error] + pub enum Error { + /// The identity proof provided could not be successfully verified. + InvalidProof(u16), + /// The specified call is filtered by the DIP call origin filter. + Filtered, + } + + /// The origin is created after the identity proof has been successfully + /// verified by the proof verifier, and it includes the identifier of the + /// subject, the address of the tx submitter, and the result returned by the + /// proof verifier upon successful verification. + #[pallet::origin] + pub type Origin = + DipOrigin<::Identifier, ::AccountId, VerificationResultOf>; + + #[pallet::call] + impl Pallet { + /// Try to dispatch a new local call only if it passes all the DIP + /// requirements. Specifically, the call will be dispatched if it passes + /// the preliminary `DipCallOriginFilter` and if the proof verifier + /// returns a `Ok(verification_result)` value. The value is then added + /// to the `DipOrigin` and passed down as the origin for the specified + /// `Call`. If the whole execution terminates successfully, any changes + /// applied to the `LocalIdentityInfo` by the proof verifier are + /// persisted to the pallet storage. + #[pallet::call_index(0)] + #[pallet::weight({ + let extrinsic_weight = ::WeightInfo::dispatch_as(); + let call_weight = call.get_dispatch_info().weight; + extrinsic_weight.saturating_add(call_weight) + })] + pub fn dispatch_as( + origin: OriginFor, + identifier: T::Identifier, + proof: IdentityProofOf, + call: Box>, + ) -> DispatchResultWithPostInfo { + let submitter = T::DispatchOriginCheck::ensure_origin(origin, &identifier)?; + ensure!(T::DipCallOriginFilter::contains(&*call), Error::::Filtered); + let proof_verification_result = IdentityEntries::::try_mutate(&identifier, |identity_entry| { + T::ProofVerifier::verify_proof_for_call_against_details( + &*call, + &identifier, + &submitter, + identity_entry, + proof, + ) + .map_err(|e| Error::::InvalidProof(e.into())) + })?; + let did_origin: DipOrigin< + T::Identifier, + T::AccountId, + >::VerificationResult, + > = DipOrigin { + identifier, + account_address: submitter, + details: proof_verification_result, + }; + + // TODO: Maybe find a nicer way to exclude the call dispatched from the + // benchmarks while making sure the call is actually dispatched and passes any + // filters the consumer proof verifier has set. + cfg_if::cfg_if! { + if #[cfg(not(feature = "runtime-benchmark"))] { + call.dispatch(did_origin.into()) + } else { + ().into() + } + } + } + } +} diff --git a/pallets/pallet-dip-consumer/src/mock.rs b/pallets/pallet-dip-consumer/src/mock.rs new file mode 100644 index 000000000..07d418625 --- /dev/null +++ b/pallets/pallet-dip-consumer/src/mock.rs @@ -0,0 +1,99 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{ + construct_runtime, + sp_runtime::{ + testing::H256, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, + }, + traits::{ConstU16, ConstU32, ConstU64, Contains, Everything}, +}; +use frame_system::{mocking::MockBlock, EnsureSigned}; + +use crate::traits::SuccessfulProofVerifier; + +construct_runtime!( + pub struct TestRuntime { + System: frame_system, + DipConsumer: crate, + } +); + +impl frame_system::Config for TestRuntime { + type AccountData = (); + type AccountId = AccountId32; + type BaseCallFilter = Everything; + type Block = MockBlock; + type BlockHashCount = ConstU64<256>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<1>; + type SystemWeightInfo = (); + type Version = (); +} + +pub struct CallFilter; + +impl Contains for CallFilter { + fn contains(t: &RuntimeCall) -> bool { + matches!(t, RuntimeCall::System { .. }) + } +} + +impl crate::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type ProofVerifier = SuccessfulProofVerifier; + type LocalIdentityInfo = u128; + type Identifier = AccountId32; + type DispatchOriginCheck = EnsureSigned; + type DipCallOriginFilter = CallFilter; + type WeightInfo = (); +} + +#[derive(Default)] +pub(crate) struct ExtBuilder; + +impl ExtBuilder { + pub fn _build(self) -> sp_io::TestExternalities { + sp_io::TestExternalities::default() + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn build_with_keystore(self) -> sp_io::TestExternalities { + let mut ext = self._build(); + let keystore = sp_keystore::testing::MemoryKeystore::new(); + ext.register_extension(sp_keystore::KeystoreExt(sp_std::sync::Arc::new(keystore))); + ext + } +} diff --git a/pallets/pallet-dip-consumer/src/origin.rs b/pallets/pallet-dip-consumer/src/origin.rs new file mode 100644 index 000000000..5281b2591 --- /dev/null +++ b/pallets/pallet-dip-consumer/src/origin.rs @@ -0,0 +1,94 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{traits::EnsureOrigin, RuntimeDebug}; +use kilt_support::traits::CallSources; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_std::marker::PhantomData; + +/// An origin passed down to the to-be-dispatched `Call` upon successful DIP +/// proof verification. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct DipOrigin { + /// The subject identifier which is performing the DIP operation. + pub identifier: Identifier, + /// The local account address of the tx submitter. + pub account_address: AccountId, + /// Details returned by the proof verifier upon successful proof + /// verification. + pub details: Details, +} + +/// Implementation of the `EnsureOrigin` trait verifying that a given origin is +/// a `DipOrigin`. +pub struct EnsureDipOrigin(PhantomData<(Identifier, AccountId, Details)>); + +#[cfg(not(feature = "runtime-benchmarks"))] +impl EnsureOrigin + for EnsureDipOrigin +where + OuterOrigin: From> + + Into, OuterOrigin>>, +{ + type Success = DipOrigin; + + fn try_origin(o: OuterOrigin) -> Result { + o.into() + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl EnsureOrigin + for EnsureDipOrigin +where + OuterOrigin: From> + + Into, OuterOrigin>>, + // Additional trait bounds only valid when benchmarking + Identifier: From<[u8; 32]>, + AccountId: From<[u8; 32]>, + Details: Default, +{ + type Success = DipOrigin; + + fn try_origin(o: OuterOrigin) -> Result { + o.into() + } + + fn try_successful_origin() -> Result { + Ok(OuterOrigin::from(DipOrigin { + identifier: Identifier::from([0u8; 32]), + account_address: AccountId::from([0u8; 32]), + details: Default::default(), + })) + } +} + +impl CallSources for DipOrigin +where + Identifier: Clone, + AccountId: Clone, +{ + fn sender(&self) -> AccountId { + self.account_address.clone() + } + + fn subject(&self) -> Identifier { + self.identifier.clone() + } +} diff --git a/pallets/pallet-dip-consumer/src/traits.rs b/pallets/pallet-dip-consumer/src/traits.rs new file mode 100644 index 000000000..bfc0bedee --- /dev/null +++ b/pallets/pallet-dip-consumer/src/traits.rs @@ -0,0 +1,71 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::Parameter; + +use crate::{Config, RuntimeCallOf}; + +/// A trait to verify a given DIP identity proof. The trait depends on the +/// runtime definition of the consumer pallet's `Identifier` and of the system +/// pallet's `AccountId`. The type of proof expected and the type returned upon +/// successful verification is defined as an associated type. +pub trait IdentityProofVerifier +where + Runtime: Config, +{ + /// The error returned upon failed DIP proof verification. + type Error: Into; + /// The accepted type for a DIP identity proof. + type Proof: Parameter; + /// The type returned upon successful DIP proof verification. + type VerificationResult; + + /// Verify a given DIP proof given the calling context, including the call + /// being dispatched, the DIP subject dispatching it, the account submitting + /// the DIP tx, and the identity details of the DIP subject as stored in the + /// consumer pallet. + fn verify_proof_for_call_against_details( + call: &RuntimeCallOf, + subject: &Runtime::Identifier, + submitter: &Runtime::AccountId, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result; +} + +/// Dummy implementation of the [`IdentityProofVerifier`] trait which always +/// returns `Ok(())`. +pub struct SuccessfulProofVerifier; +impl IdentityProofVerifier for SuccessfulProofVerifier +where + Runtime: Config, +{ + type Error = u16; + type Proof = (); + type VerificationResult = (); + + fn verify_proof_for_call_against_details( + _call: &RuntimeCallOf, + _subject: &Runtime::Identifier, + _submitter: &Runtime::AccountId, + _identity_details: &mut Option, + _proof: Self::Proof, + ) -> Result { + Ok(()) + } +} diff --git a/pallets/pallet-dip-provider/Cargo.toml b/pallets/pallet-dip-provider/Cargo.toml new file mode 100644 index 000000000..6e284e0d1 --- /dev/null +++ b/pallets/pallet-dip-provider/Cargo.toml @@ -0,0 +1,60 @@ +[package] +authors.workspace = true +description = "Pallet enabling to send some form of identity information to a specified destination." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-dip-provider" +readme = "README.md" +repository.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +kilt-support = {workspace = true, features = ["std", "mock", "try-runtime"]} +sp-io = {workspace = true, features = ["std"]} +sp-keystore = {workspace = true, features = ["std"]} +sp-runtime = {workspace = true, features = ["std"]} + +[dependencies] +did.workspace = true +frame-support.workspace = true +frame-system.workspace = true +kilt-support.workspace = true +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} +sp-core.workspace = true +sp-std.workspace = true + +# Benchmarks +frame-benchmarking = {workspace = true, optional = true} +sp-runtime = {workspace = true, optional = true} + +[features] +default = [ "std" ] + +runtime-benchmarks = [ + "did/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "kilt-support/runtime-benchmarks", + "frame-benchmarking", + "sp-runtime/runtime-benchmarks", +] +std = [ + "did/std", + "frame-support/std", + "frame-system/std", + "kilt-support/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-core/std", + "sp-std/std", + "frame-benchmarking?/std", + "sp-runtime?/std", +] + +try-runtime = [ "did/try-runtime", "kilt-support/try-runtime" ] diff --git a/pallets/pallet-dip-provider/README.md b/pallets/pallet-dip-provider/README.md new file mode 100644 index 000000000..0b384009e --- /dev/null +++ b/pallets/pallet-dip-provider/README.md @@ -0,0 +1,50 @@ +# Decentralized Identity Provider (DIP) provider pallet + +This pallet is a core component of the Decentralized Identity Provider protocol. +It enables a Substrate-based chain (provider) to bridge the identities of its users to other connected chains (consumers) trustlessly. +A consumer chain is *connected* to a provider if there is a way for the consumer chain to verify state proofs about parts of the state of the provider chain. + +The pallet is agnostic over the chain-specific definition of *identity*, and delegates the definition of it to the provider chain's runtime. + +What the pallet stores are *identity commitments*, which are opaque byte blobs put in the pallet storage and on which the cross-chain identity bridging protocol can be built. +As for identities, the definition of an identity commitment must be provided by the runtime and is therefore provider-specific. +Naturally, this definition must be made available to consumers willing to integrate the identities living on the provider chain. + +Because providers and consumers evolve at different speeds, identity commitments are versioned. +This allows the provider chain to upgrade to a newer commitment scheme, while still giving its users the possibility to use the old version, if the chains on which they want to use their identity does not yet support the new scheme. + +Identity commitments can be replaced (e.g., if something in the identity info changes), or removed altogether by the identity subject. +After removal, the identity becomes unusable cross-chain, although it will still continue to exist on the provider chain and will be usable for local operations. + +## The `Config` trait + +Being chain-agnostic, most of the runtime configurations must be passed to the pallet's `Config` trait. Specifically: + +* `type CommitOriginCheck: EnsureOrigin`: The check ensuring a given runtime origin is allowed to generate and remove identity commitments. +* `type CommitOrigin: SubmitterInfo`: The resulting origin if `CommitOriginCheck` returns with errors. The origin is not required to be an `AccountId`, but must include information about the `AccountId` of the tx submitter. +* `type Identifier: Parameter + MaxEncodedLen`: The type of an identifier used to retrieve identity information about a subject. +* `type IdentityCommitmentGenerator: IdentityCommitmentGenerator`: The type responsible for generating identity commitments, given the identity information associated to a given `Identifier`. +* `type IdentityProvider: IdentityProvider`: The type responsible for retrieving the information associated to a subject given their identifier. The information can potentially be retrieved from any source, using a combination of on-chain and off-chain solutions. +* `type IdentityProvider: IdentityProvider`: Customizable external logic to handle events in which a new identity commitment is generated or removed. +* `type RuntimeEvent: From> + IsType<::RuntimeEvent>`: The aggregate `Event` type. + +## Storage + +The pallet contains a single storage element, the `IdentityCommitments` double map. +Its first key is the `Identifier` of subjects, while the second key is the commitment version. +The values are identity commitments. + +As mentioned above, a double map allows the same subject to have one commitment for each version supported by the provider, without forcing consumers to upgrade to a new version to support the latest commitment scheme. + +## Events + +The pallet generates two events: a `VersionedIdentityCommitted` and a `VersionedIdentityDeleted`. + +The `VersionedIdentityCommited` is called whenever a new commitment is stored, and contains information about the `Identifier` of the subject, the value of the commitment, and the commitment version. + +Similarly, the `VersionedIdentityDeleted`, is called whenever a commitment is deleted, and contains information about the `Identifier` of the subject and the version of the commitment deleted. + +## Calls (bullet numbers represent each call's encoded index) + +0. `pub fn commit_identity(origin: OriginFor, identifier: T::Identifier, version: Option ) -> DispatchResult`: Generate a new versioned commitment for the subject identified by the provided `Identifier`. If an old commitment for the same version is present, it is overridden. Hooks are called before the new commitment is stored, and optionally before the old one is replaced. +1. `pub fn delete_identity_commitment(origin: OriginFor, identifier: T::Identifier, version: Option) -> DispatchResult`: Delete an identity commitment of a specific version for a specific `Identifier`. If a commitment of the provided version does not exist for the given `Identifier`, an error is returned. Hooks are called after the commitment has been removed. diff --git a/pallets/pallet-dip-provider/src/benchmarking.rs b/pallets/pallet-dip-provider/src/benchmarking.rs new file mode 100644 index 000000000..28a73c5cb --- /dev/null +++ b/pallets/pallet-dip-provider/src/benchmarking.rs @@ -0,0 +1,109 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{traits::IdentityProvider, Call, Config, Pallet}; +use frame_benchmarking::v2::*; +use kilt_support::{ + benchmark::IdentityContext, + traits::{GenerateBenchmarkOrigin, GetWorstCase, Instanciate}, +}; + +#[benchmarks( + where + T::CommitOriginCheck: GenerateBenchmarkOrigin, + T::AccountId: Instanciate, + T::Identifier: Instanciate, + <::IdentityProvider as IdentityProvider>::Success: GetWorstCase> +)] +mod benchmarks { + + type IdentityContextOf = + IdentityContext<::Identifier, ::AccountId>; + + use crate::IdentityOf; + + use super::*; + + #[benchmark] + fn commit_identity() { + let submitter = T::AccountId::new(1); + let subject = T::Identifier::new(1); + let commitment_version = 0; + + let context = IdentityContext:: { + did: subject.clone(), + submitter: submitter.clone(), + }; + + assert!(Pallet::::identity_commitments(&subject, commitment_version).is_none()); + + let origin: T::RuntimeOrigin = T::CommitOriginCheck::generate_origin(submitter, subject.clone()); + + as GetWorstCase>>::worst_case(context); + + let cloned_subject = subject.clone(); + + #[extrinsic_call] + Pallet::::commit_identity(origin as T::RuntimeOrigin, cloned_subject, Some(commitment_version)); + + assert!(Pallet::::identity_commitments(&subject, commitment_version).is_some()); + } + + #[benchmark] + fn delete_identity_commitment() { + let submitter = T::AccountId::new(1); + let subject = T::Identifier::new(1); + let commitment_version = 0; + + let origin: T::RuntimeOrigin = T::CommitOriginCheck::generate_origin(submitter.clone(), subject.clone()); + + let context = IdentityContext:: { + did: subject.clone(), + submitter, + }; + + as GetWorstCase>>::worst_case(context); + let cloned_subject = subject.clone(); + + Pallet::::commit_identity( + origin.clone() as T::RuntimeOrigin, + subject.clone(), + Some(commitment_version), + ) + .expect("Inserting Identity should not fail."); + + assert!(Pallet::::identity_commitments(&subject, commitment_version).is_some()); + + #[extrinsic_call] + Pallet::::delete_identity_commitment(origin as T::RuntimeOrigin, cloned_subject, Some(commitment_version)); + + assert!(Pallet::::identity_commitments(&subject, commitment_version).is_none()); + } + + #[cfg(test)] + mod benchmarks_tests { + use crate::Pallet; + use frame_benchmarking::impl_benchmark_test_suite; + + impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().build_with_keystore(), + crate::mock::TestRuntime, + ); + } +} diff --git a/pallets/pallet-dip-provider/src/default_weights.rs b/pallets/pallet-dip-provider/src/default_weights.rs new file mode 100644 index 000000000..51c54bbe0 --- /dev/null +++ b/pallets/pallet-dip-provider/src/default_weights.rs @@ -0,0 +1,108 @@ + +//! Autogenerated weights for pallet_dip_provider +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-23 +//! STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/kilt-parachain +// benchmark +// pallet +// --pallet +// pallet-dip-provider +// --extrinsic +// * +// --template +// ./.maintain/weight-template.hbs +// --output +// ./pallets/pallet-dip-provider/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_dip_provider. +pub trait WeightInfo { + fn commit_identity() -> Weight; + fn delete_identity_commitment() -> Weight; +} + +/// Weights for pallet_dip_provider using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Did::Did` (r:1 w:0) + /// Proof: `Did::Did` (`max_values`: None, `max_size`: Some(2312), added: 4787, mode: `MaxEncodedLen`) + /// Storage: `Did::DidBlacklist` (r:1 w:0) + /// Proof: `Did::DidBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Names` (r:1 w:0) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:0) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:11 w:0) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + /// Storage: `PalletDipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `PalletDipProvider::IdentityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn commit_identity() -> Weight { + // Proof Size summary in bytes: + // Measured: `2781` + // Estimated: `29282` + // Minimum execution time: 1_244_624 nanoseconds. + Weight::from_parts(1_401_381_000, 29282) + .saturating_add(T::DbWeight::get().reads(16_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PalletDipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `PalletDipProvider::IdentityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn delete_identity_commitment() -> Weight { + // Proof Size summary in bytes: + // Measured: `250` + // Estimated: `3715` + // Minimum execution time: 169_415 nanoseconds. + Weight::from_parts(190_131_000, 3715) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: `Did::Did` (r:1 w:0) + /// Proof: `Did::Did` (`max_values`: None, `max_size`: Some(2312), added: 4787, mode: `MaxEncodedLen`) + /// Storage: `Did::DidBlacklist` (r:1 w:0) + /// Proof: `Did::DidBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Names` (r:1 w:0) + /// Proof: `Web3Names::Names` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Web3Names::Owner` (r:1 w:0) + /// Proof: `Web3Names::Owner` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `DidLookup::ConnectedAccounts` (r:11 w:0) + /// Proof: `DidLookup::ConnectedAccounts` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + /// Storage: `PalletDipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `PalletDipProvider::IdentityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn commit_identity() -> Weight { + // Proof Size summary in bytes: + // Measured: `2781` + // Estimated: `29282` + // Minimum execution time: 1_244_624 nanoseconds. + Weight::from_parts(1_401_381_000, 29282) + .saturating_add(RocksDbWeight::get().reads(16_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `PalletDipProvider::IdentityCommitments` (r:1 w:1) + /// Proof: `PalletDipProvider::IdentityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn delete_identity_commitment() -> Weight { + // Proof Size summary in bytes: + // Measured: `250` + // Estimated: `3715` + // Minimum execution time: 169_415 nanoseconds. + Weight::from_parts(190_131_000, 3715) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs new file mode 100644 index 000000000..aff9f53ef --- /dev/null +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -0,0 +1,219 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![cfg_attr(not(feature = "std"), no_std)] +#![doc = include_str!("../README.md")] + +mod default_weights; +pub mod traits; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[cfg(test)] +mod mock; + +pub use crate::{ + default_weights::WeightInfo, + pallet::*, + traits::{DefaultIdentityCommitmentGenerator, DefaultIdentityProvider, NoopHooks}, +}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + use default_weights::WeightInfo; + use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg}; + use frame_system::pallet_prelude::*; + + use crate::traits::{IdentityCommitmentGenerator, IdentityProvider, ProviderHooks, SubmitterInfo}; + + pub type IdentityCommitmentOf = + <::IdentityCommitmentGenerator as IdentityCommitmentGenerator>::Output; + pub type IdentityProviderOf = ::IdentityProvider; + pub type IdentityOf = <::IdentityProvider as IdentityProvider>::Success; + pub type IdentityCommitmentVersion = u16; + + pub const LATEST_COMMITMENT_VERSION: IdentityCommitmentVersion = 0; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The check ensuring a given runtime origin is allowed to generate and + /// remove identity commitments. + type CommitOriginCheck: EnsureOriginWithArg; + /// The resulting origin if `CommitOriginCheck` returns with errors. The + /// origin is not required to be an `AccountId`, but must include + /// information about the `AccountId` of the tx submitter. + type CommitOrigin: SubmitterInfo; + /// The type of an identifier used to retrieve identity information + /// about a subject. + type Identifier: Parameter + MaxEncodedLen; + /// The type responsible for generating identity commitments, given the + /// identity information associated to a given `Identifier`. + type IdentityCommitmentGenerator: IdentityCommitmentGenerator; + /// The type responsible for retrieving the information associated to a + /// subject given their identifier. The information can potentially be + /// retrieved from any source, using a combination of on-chain and + /// off-chain solutions. + type IdentityProvider: IdentityProvider; + /// Customizable external logic to handle events in which a new identity + /// commitment is generated or removed. + type ProviderHooks: ProviderHooks; + /// The aggregate `Event` type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type WeightInfo: WeightInfo; + } + + /// The pallet contains a single storage element, the `IdentityCommitments` + /// double map. Its first key is the `Identifier` of subjects, while the + /// second key is the commitment version. The values are identity + /// commitments. + #[pallet::storage] + #[pallet::getter(fn identity_commitments)] + pub type IdentityCommitments = StorageDoubleMap< + _, + Twox64Concat, + ::Identifier, + Twox64Concat, + IdentityCommitmentVersion, + IdentityCommitmentOf, + >; + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A new commitment has been stored. + VersionedIdentityCommitted { + /// The identifier of the identity committed. + identifier: T::Identifier, + /// The value of the commitment. + commitment: IdentityCommitmentOf, + /// The version of the commitment. + version: IdentityCommitmentVersion, + }, + /// A commitment has been deleted. + VersionedIdentityDeleted { + /// The identifier of the identity committed. + identifier: T::Identifier, + /// The version of the commitment. + version: IdentityCommitmentVersion, + }, + } + + #[pallet::error] + pub enum Error { + /// The specified commitment cannot be found. + CommitmentNotFound, + /// Error when retrieving the identity details of the provided subject. + IdentityProvider(u16), + /// Error when generating a commitment for the retrieved identity. + IdentityCommitmentGenerator(u16), + /// Error inside the external hook logic. + Hook(u16), + } + + #[pallet::call] + impl Pallet { + /// Generate a new versioned commitment for the subject identified by + /// the provided `Identifier`. If an old commitment for the same version + /// is present, it is overridden. Hooks are called before the new + /// commitment is stored, and optionally before the old one is replaced. + #[pallet::call_index(0)] + #[pallet::weight({ + ::WeightInfo::commit_identity() + })] + pub fn commit_identity( + origin: OriginFor, + identifier: T::Identifier, + version: Option, + ) -> DispatchResult { + let dispatcher = T::CommitOriginCheck::ensure_origin(origin, &identifier) + .map(|e: ::CommitOrigin| e.submitter())?; + + let commitment_version = version.unwrap_or(LATEST_COMMITMENT_VERSION); + let identity = T::IdentityProvider::retrieve(&identifier) + .map_err(|error| Error::::IdentityProvider(error.into()))?; + let commitment = + T::IdentityCommitmentGenerator::generate_commitment(&identifier, &identity, commitment_version) + .map_err(|error| Error::::IdentityCommitmentGenerator(error.into()))?; + + match Self::delete_identity_commitment_storage_entry(&identifier, &dispatcher, commitment_version) { + // Ignore if there was no previous commitment. + Ok(_) | Err(Error::::CommitmentNotFound) => (), + // If a different error is returned, bubble it up. + Err(e) => return Err(e.into()), + }; + + IdentityCommitments::::insert(&identifier, commitment_version, commitment.clone()); + // Call hooks for new commitment. + T::ProviderHooks::on_identity_committed(&identifier, &dispatcher, &commitment, commitment_version) + .map_err(|e| Error::::Hook(e.into()))?; + Self::deposit_event(Event::::VersionedIdentityCommitted { + identifier: identifier.clone(), + commitment, + version: commitment_version, + }); + Ok(()) + } + + /// Delete an identity commitment of a specific version for a specific + /// `Identifier`. If a commitment of the provided version does not exist + /// for the given `Identifier`, an error is returned. Hooks are called + /// after the commitment has been removed. + #[pallet::call_index(1)] + #[pallet::weight({ + ::WeightInfo::delete_identity_commitment() + })] + pub fn delete_identity_commitment( + origin: OriginFor, + identifier: T::Identifier, + version: Option, + ) -> DispatchResult { + let dispatcher = T::CommitOriginCheck::ensure_origin(origin, &identifier) + .map(|e: ::CommitOrigin| e.submitter())?; + let commitment_version = version.unwrap_or(LATEST_COMMITMENT_VERSION); + + Self::delete_identity_commitment_storage_entry(&identifier, &dispatcher, commitment_version)?; + Ok(()) + } + } + + impl Pallet { + pub fn delete_identity_commitment_storage_entry( + identifier: &T::Identifier, + dispatcher: &T::AccountId, + version: IdentityCommitmentVersion, + ) -> Result, Error> { + let commitment = + IdentityCommitments::::take(identifier, version).ok_or(Error::::CommitmentNotFound)?; + T::ProviderHooks::on_commitment_removed(identifier, dispatcher, &commitment, version) + .map_err(|e| Error::::Hook(e.into()))?; + Self::deposit_event(Event::::VersionedIdentityDeleted { + identifier: identifier.clone(), + version, + }); + Ok(commitment) + } + } +} diff --git a/pallets/pallet-dip-provider/src/mock.rs b/pallets/pallet-dip-provider/src/mock.rs new file mode 100644 index 000000000..af57977af --- /dev/null +++ b/pallets/pallet-dip-provider/src/mock.rs @@ -0,0 +1,100 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{ + construct_runtime, + sp_runtime::{ + testing::H256, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, + }, + traits::{ConstU16, ConstU32, ConstU64, Everything}, +}; + +use frame_system::mocking::MockBlock; +use kilt_support::mock::mock_origin::{self as mock_origin, DoubleOrigin, EnsureDoubleOrigin}; + +use crate::{DefaultIdentityCommitmentGenerator, DefaultIdentityProvider, NoopHooks}; + +construct_runtime!( + pub struct TestRuntime { + System: frame_system, + DipProvider: crate, + MockOrigin: mock_origin, + } +); + +impl frame_system::Config for TestRuntime { + type AccountData = (); + type AccountId = AccountId32; + type BaseCallFilter = Everything; + type Block = MockBlock; + type BlockHashCount = ConstU64<256>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<1>; + type SystemWeightInfo = (); + type Version = (); +} + +impl crate::Config for TestRuntime { + type CommitOrigin = DoubleOrigin; + type CommitOriginCheck = EnsureDoubleOrigin; + type Identifier = AccountId32; + type IdentityCommitmentGenerator = DefaultIdentityCommitmentGenerator; + type IdentityProvider = DefaultIdentityProvider; + type ProviderHooks = NoopHooks; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +impl mock_origin::Config for TestRuntime { + type AccountId = ::AccountId; + type RuntimeOrigin = RuntimeOrigin; + type SubjectId = ::Identifier; +} + +#[derive(Default)] +pub(crate) struct ExtBuilder; + +impl ExtBuilder { + pub fn _build(self) -> sp_io::TestExternalities { + sp_io::TestExternalities::default() + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn build_with_keystore(self) -> sp_io::TestExternalities { + let mut ext = self._build(); + let keystore = sp_keystore::testing::MemoryKeystore::new(); + ext.register_extension(sp_keystore::KeystoreExt(sp_std::sync::Arc::new(keystore))); + ext + } +} diff --git a/pallets/pallet-dip-provider/src/traits.rs b/pallets/pallet-dip-provider/src/traits.rs new file mode 100644 index 000000000..760ad5cc4 --- /dev/null +++ b/pallets/pallet-dip-provider/src/traits.rs @@ -0,0 +1,201 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::DidRawOrigin; +use frame_support::sp_runtime::AccountId32; + +use crate::{Config, IdentityCommitmentOf, IdentityCommitmentVersion}; + +pub use identity_provision::*; +pub mod identity_provision { + use super::*; + + use sp_std::marker::PhantomData; + + /// A trait to retrieve identity information for a given identifier. The + /// information can come from a variety of different sources, as this pallet + /// does not impose any restrictions on that. + pub trait IdentityProvider + where + Runtime: Config, + { + type Error: Into; + type Success; + + /// Return the identity information for the identifier, if found. + /// Otherwise, return an error. + fn retrieve(identifier: &Runtime::Identifier) -> Result; + } + + /// Return the `Default` value of the provided `Identity` type if it + /// implements the `Default` trait. + pub struct DefaultIdentityProvider(PhantomData); + + impl IdentityProvider for DefaultIdentityProvider + where + Runtime: Config, + Identity: Default, + { + type Error = u16; + type Success = Identity; + + fn retrieve(_identifier: &Runtime::Identifier) -> Result { + Ok(Identity::default()) + } + } +} + +pub use identity_generation::*; +pub mod identity_generation { + use super::*; + + use crate::IdentityOf; + + use parity_scale_codec::{FullCodec, MaxEncodedLen}; + use scale_info::TypeInfo; + use sp_std::{fmt::Debug, marker::PhantomData}; + + /// A trait to generate an identity commitment of a given version for some + /// identity info retrieved by the [`IdentityProvider`]. + pub trait IdentityCommitmentGenerator + where + Runtime: Config, + Runtime::IdentityProvider: IdentityProvider, + { + type Error: Into; + type Output: Clone + Eq + Debug + TypeInfo + FullCodec + MaxEncodedLen; + + /// Return the identity commitment for the given version and identity + /// information. + fn generate_commitment( + identifier: &Runtime::Identifier, + identity: &IdentityOf, + version: IdentityCommitmentVersion, + ) -> Result; + } + + /// Implement the [`IdentityCommitmentGenerator`] trait by returning the + /// `Default` value for the `Output` type. + pub struct DefaultIdentityCommitmentGenerator(PhantomData); + + impl IdentityCommitmentGenerator for DefaultIdentityCommitmentGenerator + where + Runtime: Config, + Output: Default + Clone + Eq + Debug + TypeInfo + FullCodec + MaxEncodedLen, + { + type Error = u16; + type Output = Output; + + fn generate_commitment( + _identifier: &Runtime::Identifier, + _identity: &IdentityOf, + _version: IdentityCommitmentVersion, + ) -> Result { + Ok(Output::default()) + } + } +} + +/// A trait for types that, among other things, contain information about the +/// submitter of a tx. +pub trait SubmitterInfo { + type Submitter; + + fn submitter(&self) -> Self::Submitter; +} + +impl SubmitterInfo for AccountId32 { + type Submitter = Self; + + fn submitter(&self) -> Self::Submitter { + self.clone() + } +} + +impl SubmitterInfo for DidRawOrigin +where + AccountId: Clone, +{ + type Submitter = AccountId; + + fn submitter(&self) -> Self::Submitter { + self.submitter.clone() + } +} + +#[cfg(any(feature = "runtime-benchmarks", test))] +impl SubmitterInfo for kilt_support::mock::mock_origin::DoubleOrigin +where + AccountId: Clone, +{ + type Submitter = AccountId; + fn submitter(&self) -> Self::Submitter { + self.0.clone() + } +} + +/// Hooks for additional customizable logic to be executed when new identity +/// commitments are stored or old ones are removed. +pub trait ProviderHooks +where + Runtime: Config, +{ + type Error: Into; + + fn on_identity_committed( + identifier: &Runtime::Identifier, + submitter: &Runtime::AccountId, + commitment: &IdentityCommitmentOf, + version: IdentityCommitmentVersion, + ) -> Result<(), Self::Error>; + + fn on_commitment_removed( + identifier: &Runtime::Identifier, + submitter: &Runtime::AccountId, + commitment: &IdentityCommitmentOf, + version: IdentityCommitmentVersion, + ) -> Result<(), Self::Error>; +} + +/// Implement the [`ProviderHooks`] trait with noops. +pub struct NoopHooks; + +impl ProviderHooks for NoopHooks +where + Runtime: Config, +{ + type Error = u16; + + fn on_commitment_removed( + _identifier: &Runtime::Identifier, + _submitter: &Runtime::AccountId, + _commitment: &IdentityCommitmentOf, + _version: IdentityCommitmentVersion, + ) -> Result<(), Self::Error> { + Ok(()) + } + + fn on_identity_committed( + _identifier: &Runtime::Identifier, + _submitter: &Runtime::AccountId, + _commitment: &IdentityCommitmentOf, + _version: IdentityCommitmentVersion, + ) -> Result<(), Self::Error> { + Ok(()) + } +} diff --git a/pallets/pallet-migration/Cargo.toml b/pallets/pallet-migration/Cargo.toml index 378b7baaa..905b0d4a7 100644 --- a/pallets/pallet-migration/Cargo.toml +++ b/pallets/pallet-migration/Cargo.toml @@ -20,12 +20,13 @@ frame-benchmarking = {workspace = true, features = ["std"]} pallet-aura = {workspace = true, features = ["std"]} pallet-timestamp = {workspace = true, features = ["std"]} sp-consensus-aura = {workspace = true, features = ["std"]} +sp-keystore = {workspace = true, features = ["std"]} pallet-session = {workspace = true, features = ["std"]} attestation = {workspace = true, features = ["mock"]} ctype = {workspace = true, features = ["mock"]} -delegation = {workspace = true, features = ["mock"]} -did = {workspace = true, features = ["mock"]} -public-credentials = {workspace = true, features = ["mock"]} +delegation = {workspace = true, features = ["mock"]} +did = {workspace = true, features = ["mock"]} +public-credentials = {workspace = true, features = ["mock"]} [dependencies] # Internal dependencies @@ -36,7 +37,7 @@ pallet-did-lookup.workspace = true pallet-web3-names.workspace = true parachain-staking.workspace = true public-credentials.workspace = true -runtime-common.workspace = true +runtime-common.workspace = true kilt-support.workspace = true ctype = {workspace = true, optional = true} @@ -69,7 +70,7 @@ runtime-benchmarks = [ "pallet-web3-names/runtime-benchmarks", "parachain-staking/runtime-benchmarks", "public-credentials/runtime-benchmarks", - "runtime-common/runtime-benchmarks", + "runtime-common/runtime-benchmarks", "ctype/runtime-benchmarks", "kilt-support/runtime-benchmarks", "pallet-balances/runtime-benchmarks", diff --git a/pallets/pallet-migration/src/benchmarking.rs b/pallets/pallet-migration/src/benchmarking.rs index 68b748cdd..6ced3cd01 100644 --- a/pallets/pallet-migration/src/benchmarking.rs +++ b/pallets/pallet-migration/src/benchmarking.rs @@ -203,7 +203,7 @@ benchmarks! { let sender: AccountIdOf = account("sender", 0, SEED); let attester: ::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; ::MaxEncodedClaimsLength::get() as usize]).expect("Contents should not fail."); let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone()); diff --git a/pallets/pallet-migration/src/mock.rs b/pallets/pallet-migration/src/mock.rs index 2567b1bd8..e07fe2e90 100644 --- a/pallets/pallet-migration/src/mock.rs +++ b/pallets/pallet-migration/src/mock.rs @@ -375,9 +375,9 @@ pub mod runtime { } #[cfg(feature = "runtime-benchmarks")] - impl kilt_support::traits::GetWorstCase for TestSubjectId { + impl kilt_support::traits::GetWorstCase for TestSubjectId { // Only used for benchmark testing, not really relevant. - fn worst_case() -> Self { + fn worst_case(_context: Context) -> Self { crate::mock::TestSubjectId::default() } } diff --git a/pallets/pallet-relay-store/Cargo.toml b/pallets/pallet-relay-store/Cargo.toml new file mode 100644 index 000000000..724b32755 --- /dev/null +++ b/pallets/pallet-relay-store/Cargo.toml @@ -0,0 +1,56 @@ +[package] +authors.workspace = true +description = "Pallet enabling storing finalize relay head data on chain." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-relay-store" +readme = "README.md" +repository.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +cumulus-primitives-core = { workspace = true, features = ["std"] } +sp-io = {workspace = true, features = ["std"]} +sp-keystore = {workspace = true, features = ["std"]} +sp-runtime = {workspace = true, features = ["std"]} + +[dependencies] +cumulus-pallet-parachain-system.workspace = true +frame-support.workspace = true +frame-system.workspace = true +log.workspace = true +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} +sp-core.workspace = true +sp-std.workspace = true + +# Benchmarks +frame-benchmarking = {workspace = true, optional = true} +sp-runtime = {workspace = true, optional = true} + +[features] +default = ["std"] +std = [ + "cumulus-pallet-parachain-system/std", + "frame-support/std", + "frame-system/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-core/std", + "sp-std/std", + "frame-benchmarking?/std", + "sp-runtime?/std", +] +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "frame-benchmarking", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [] diff --git a/pallets/pallet-relay-store/src/benchmarking.rs b/pallets/pallet-relay-store/src/benchmarking.rs new file mode 100644 index 000000000..3520016ba --- /dev/null +++ b/pallets/pallet-relay-store/src/benchmarking.rs @@ -0,0 +1,93 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{Config, Pallet}; +use frame_benchmarking::v2::*; + +#[benchmarks( + where + T: cumulus_pallet_parachain_system::Config +)] +mod benchmarks { + use cumulus_pallet_parachain_system::RelaychainDataProvider; + use sp_core::H256; + use sp_runtime::{ + traits::{BlockNumberProvider, Get}, + BoundedVec, + }; + + use crate::{relay::RelayParentInfo, LatestBlockHeights, LatestRelayHeads}; + + use super::*; + + #[benchmark] + fn on_finalize() { + let max_blocks_stored = T::MaxRelayBlocksStored::get(); + let latest_block_heights: BoundedVec = (1..=max_blocks_stored) + .collect::>() + .try_into() + .expect("Should not fail to build BoundedVec for LatestBlockHeights"); + let latest_block_heads_iter = latest_block_heights.iter().map(|block_height| { + ( + block_height, + RelayParentInfo { + relay_parent_storage_root: H256::default(), + }, + ) + }); + latest_block_heads_iter + .for_each(|(block_height, parent_info)| LatestRelayHeads::::insert(block_height, parent_info)); + LatestBlockHeights::::put(latest_block_heights); + + assert_eq!( + LatestRelayHeads::::iter().count(), + max_blocks_stored as usize, + "The maximum allowed number of blocks should be stored in storage." + ); + + let new_block_number = max_blocks_stored + 1; + frame_system::Pallet::::set_block_number(new_block_number.into()); + RelaychainDataProvider::::set_block_number(new_block_number); + + #[block] + { + Pallet::::on_finalize_internal(new_block_number.into()) + } + + assert!( + LatestBlockHeights::::get().contains(&new_block_number), + "LatestBlockHeights should contain the information about the new block" + ); + assert!( + LatestRelayHeads::::contains_key(new_block_number), + "LatestRelayHeads should contain the information about the new block" + ); + } + + #[cfg(test)] + mod benchmarks_tests { + use crate::Pallet; + use frame_benchmarking::impl_benchmark_test_suite; + + impl_benchmark_test_suite!( + Pallet, + crate::mock::ExtBuilder::default().build_with_keystore(), + crate::mock::TestRuntime, + ); + } +} diff --git a/pallets/pallet-relay-store/src/default_weights.rs b/pallets/pallet-relay-store/src/default_weights.rs new file mode 100644 index 000000000..ab5ae9ce4 --- /dev/null +++ b/pallets/pallet-relay-store/src/default_weights.rs @@ -0,0 +1,92 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Autogenerated weights for pallet_relay_store +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-01 +//! STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/kilt-parachain +// benchmark +// pallet +// --template=.maintain/weight-template.hbs +// --header=HEADER-GPL +// --wasm-execution=compiled +// --heap-pages=4096 +// --steps=50 +// --repeat=20 +// --chain=dev +// --pallet=pallet-relay-store +// --extrinsic=* +// --output=./pallets/pallet-relay-store/src/default_weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_relay_store. +pub trait WeightInfo { + fn on_finalize() -> Weight; +} + +/// Weights for pallet_relay_store using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `RelayStore::LatestBlockHeights` (r:1 w:1) + /// Proof: `RelayStore::LatestBlockHeights` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `RelayStore::LatestRelayHeads` (r:0 w:2) + /// Proof: `RelayStore::LatestRelayHeads` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn on_finalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `577` + // Estimated: `2062` + // Minimum execution time: 132_937 nanoseconds. + Weight::from_parts(146_340_000, 2062) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `RelayStore::LatestBlockHeights` (r:1 w:1) + /// Proof: `RelayStore::LatestBlockHeights` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `RelayStore::LatestRelayHeads` (r:0 w:2) + /// Proof: `RelayStore::LatestRelayHeads` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn on_finalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `577` + // Estimated: `2062` + // Minimum execution time: 132_937 nanoseconds. + Weight::from_parts(146_340_000, 2062) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} diff --git a/pallets/pallet-relay-store/src/lib.rs b/pallets/pallet-relay-store/src/lib.rs new file mode 100644 index 000000000..084f88232 --- /dev/null +++ b/pallets/pallet-relay-store/src/lib.rs @@ -0,0 +1,134 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +//! Pallet to store the last N (configurable) relay chain state roots to be used +//! for cross-chain state proof verification. The pallet relies on the +//! cumulus_parachain_system hook to populate the block `ValidationData` with +//! the latest relay chain state root. + +#![cfg_attr(not(feature = "std"), no_std)] + +mod default_weights; +mod relay; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[cfg(test)] +mod mock; + +pub use crate::{default_weights::WeightInfo, pallet::*}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + use frame_support::{pallet_prelude::*, BoundedVec}; + use frame_system::pallet_prelude::*; + use sp_core::H256; + + use crate::relay::RelayParentInfo; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + /// Maps from a relaychain block height to its related information, + /// including the state root. + #[pallet::storage] + #[pallet::getter(fn latest_relay_head_for_block)] + pub(crate) type LatestRelayHeads = StorageMap<_, Twox64Concat, u32, RelayParentInfo>; + + // TODO: Replace this with a fixed-length array once support for const generics + // is fully supported in Substrate. + /// Storage value complimentary to [`LatestRelayHeads`] implementing a FIFO + /// queue of the last N relay chain blocks info. + #[pallet::storage] + pub(crate) type LatestBlockHeights = + StorageValue<_, BoundedVec, ValueQuery>; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The maximum number of relaychain block details to store. When the + /// limit is reached, oldest blocks are overridden with new ones. + #[pallet::constant] + type MaxRelayBlocksStored: Get; + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::hooks] + impl Hooks> for Pallet + where + T: cumulus_pallet_parachain_system::Config, + { + fn on_initialize(_n: BlockNumberFor) -> Weight { + ::WeightInfo::on_finalize() + } + + fn on_finalize(n: BlockNumberFor) { + Self::on_finalize_internal(n) + } + } + + impl Pallet + where + T: cumulus_pallet_parachain_system::Config, + { + pub(crate) fn on_finalize_internal(_n: BlockNumberFor) { + // Called before the validation data is cleaned in the + // parachain_system::on_finalize hook + let Some(new_validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() else { + return; + }; + let mut latest_block_heights = LatestBlockHeights::::get(); + // Remove old relay block from both storage entries. + if latest_block_heights.is_full() { + let oldest_block_height = latest_block_heights.remove(0); + LatestRelayHeads::::remove(oldest_block_height); + log::trace!( + "Relay block queue full. Removing oldest block at height {:?}", + oldest_block_height + ); + } + // Set the new relay block in storage. + let relay_block_height = new_validation_data.relay_parent_number; + log::trace!( + "Adding new relay block with state root {:#02x?} and number {:?}", + new_validation_data.relay_parent_storage_root, + new_validation_data.relay_parent_number, + ); + let push_res = latest_block_heights.try_push(relay_block_height); + if let Err(err) = push_res { + log::error!( + "Pushing a new relay block to the queue should not fail but it did when adding relay block n. {:?}", + err + ); + } else { + LatestBlockHeights::::set(latest_block_heights); + LatestRelayHeads::::insert( + relay_block_height, + RelayParentInfo { + relay_parent_storage_root: new_validation_data.relay_parent_storage_root, + }, + ); + } + } + } +} diff --git a/pallets/pallet-relay-store/src/mock.rs b/pallets/pallet-relay-store/src/mock.rs new file mode 100644 index 000000000..2aea08ef7 --- /dev/null +++ b/pallets/pallet-relay-store/src/mock.rs @@ -0,0 +1,102 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use cumulus_pallet_parachain_system::{ParachainSetCode, RelayNumberStrictlyIncreases}; +use cumulus_primitives_core::ParaId; +use frame_support::{ + construct_runtime, parameter_types, + sp_runtime::{ + testing::H256, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, + }, + traits::{ConstU16, ConstU32, ConstU64, Everything}, +}; +use frame_system::mocking::MockBlock; + +construct_runtime!( + pub struct TestRuntime { + System: frame_system, + ParachainSystem: cumulus_pallet_parachain_system, + RelayStore: crate, + } +); + +impl frame_system::Config for TestRuntime { + type AccountData = (); + type AccountId = AccountId32; + type BaseCallFilter = Everything; + type Block = MockBlock; + type BlockHashCount = ConstU64<256>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = ParachainSetCode; + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<1>; + type SystemWeightInfo = (); + type Version = (); +} + +parameter_types! { + pub const ParachainId: ParaId = ParaId::new(2_000); +} + +impl cumulus_pallet_parachain_system::Config for TestRuntime { + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type DmpMessageHandler = (); + type OnSystemEvent = (); + type OutboundXcmpMessageSource = (); + type ReservedDmpWeight = (); + type ReservedXcmpWeight = (); + type RuntimeEvent = RuntimeEvent; + type SelfParaId = ParachainId; + type XcmpMessageHandler = (); +} + +impl crate::Config for TestRuntime { + type MaxRelayBlocksStored = ConstU32<5>; + type WeightInfo = (); +} + +#[derive(Default)] +pub(crate) struct ExtBuilder; + +impl ExtBuilder { + pub fn _build(self) -> sp_io::TestExternalities { + sp_io::TestExternalities::default() + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn build_with_keystore(self) -> sp_io::TestExternalities { + let mut ext = self._build(); + let keystore = sp_keystore::testing::MemoryKeystore::new(); + ext.register_extension(sp_keystore::KeystoreExt(sp_std::sync::Arc::new(keystore))); + ext + } +} diff --git a/pallets/pallet-relay-store/src/relay.rs b/pallets/pallet-relay-store/src/relay.rs new file mode 100644 index 000000000..1bca00ba5 --- /dev/null +++ b/pallets/pallet-relay-store/src/relay.rs @@ -0,0 +1,28 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; + +/// Information associated to a relaychain block. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug, MaxEncodedLen)] +pub struct RelayParentInfo { + /// The relaychain block storage root. + pub relay_parent_storage_root: Hash, +} diff --git a/pallets/public-credentials/src/benchmarking.rs b/pallets/public-credentials/src/benchmarking.rs index 1153bdf63..087f2bfec 100644 --- a/pallets/public-credentials/src/benchmarking.rs +++ b/pallets/public-credentials/src/benchmarking.rs @@ -71,7 +71,7 @@ benchmarks! { let sender: T::AccountId = account("sender", 0, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; c as usize]).expect("Contents should not fail."); let creation_op = Box::new(generate_base_public_credential_creation_op::( @@ -98,7 +98,7 @@ benchmarks! { let sender: T::AccountId = account("sender", 0, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; ::MaxEncodedClaimsLength::get() as usize]).expect("Contents should not fail."); let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone()); @@ -127,7 +127,7 @@ benchmarks! { let sender: T::AccountId = account("sender", 0, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; ::MaxEncodedClaimsLength::get() as usize]).expect("Contents should not fail."); let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone()); @@ -156,7 +156,7 @@ benchmarks! { let sender: T::AccountId = account("sender", 0, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; ::MaxEncodedClaimsLength::get() as usize]).expect("Contents should not fail."); let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone()); @@ -185,7 +185,7 @@ benchmarks! { let sender: T::AccountId = account("sender", 0, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; ::MaxEncodedClaimsLength::get() as usize]).expect("Contents should not fail."); let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone()); @@ -216,7 +216,7 @@ benchmarks! { let deposit_owner_new: AccountIdOf = account("caller", 1, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let contents = BoundedVec::try_from(vec![0; ::MaxEncodedClaimsLength::get() as usize]).expect("Contents should not fail."); let origin = ::EnsureOrigin::generate_origin(deposit_owner_old.clone(), attester.clone()); @@ -252,7 +252,7 @@ benchmarks! { let deposit_owner: AccountIdOf = account("caller", 0, SEED); let attester: T::AttesterId = account("attester", 0, SEED); let ctype_hash: T::Hash = T::Hash::default(); - let subject_id = ::SubjectId::worst_case(); + let subject_id = ::SubjectId::worst_case(()); let origin = ::EnsureOrigin::generate_origin(deposit_owner.clone(), attester.clone()); reserve_balance::(&deposit_owner); diff --git a/pallets/public-credentials/src/mock.rs b/pallets/public-credentials/src/mock.rs index 07f53d6e3..3afa5c334 100644 --- a/pallets/public-credentials/src/mock.rs +++ b/pallets/public-credentials/src/mock.rs @@ -247,9 +247,9 @@ pub(crate) mod runtime { } #[cfg(feature = "runtime-benchmarks")] - impl kilt_support::traits::GetWorstCase for TestSubjectId { + impl kilt_support::traits::GetWorstCase for TestSubjectId { // Only used for benchmark testing, not really relevant. - fn worst_case() -> Self { + fn worst_case(_context: Context) -> Self { crate::mock::TestSubjectId::default() } } diff --git a/runtime-api/dip-provider/Cargo.toml b/runtime-api/dip-provider/Cargo.toml new file mode 100644 index 000000000..3ba00df69 --- /dev/null +++ b/runtime-api/dip-provider/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true +name = "kilt-runtime-api-dip-provider" +description = "Runtime APIs for integrating the DIP provider component." + +[dependencies] +# External dependencies +parity-scale-codec.workspace = true + +# Internal dependencies + +# Substrate dependencies +sp-api.workspace = true + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "sp-api/std" +] diff --git a/runtime-api/dip-provider/src/lib.rs b/runtime-api/dip-provider/src/lib.rs new file mode 100644 index 000000000..1b7b8170d --- /dev/null +++ b/runtime-api/dip-provider/src/lib.rs @@ -0,0 +1,33 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![cfg_attr(not(feature = "std"), no_std)] + +use parity_scale_codec::Codec; + +sp_api::decl_runtime_apis! { + /// Runtime API to generate a DIP proof with the provided parameters. + pub trait DipProvider where + ProofRequest: Codec, + Success: Codec, + Error: Codec, + { + /// Generate a DIP proof with the parameters specified in the request. + fn generate_proof(request: ProofRequest) -> Result; + } +} diff --git a/runtimes/common/Cargo.toml b/runtimes/common/Cargo.toml index 79c877c20..a330c99ad 100644 --- a/runtimes/common/Cargo.toml +++ b/runtimes/common/Cargo.toml @@ -22,7 +22,12 @@ scale-info = {workspace = true, features = ["derive"]} smallvec.workspace = true attestation.workspace = true +did.workspace = true kilt-support.workspace = true +kilt-dip-primitives.workspace = true +pallet-did-lookup.workspace = true +pallet-dip-provider.workspace = true +pallet-web3-names.workspace = true parachain-staking.workspace = true public-credentials.workspace = true @@ -44,6 +49,7 @@ sp-core.workspace = true sp-io.workspace = true sp-runtime.workspace = true sp-std.workspace = true +sp-trie.workspace = true # Cumulus dependencies cumulus-primitives-core.workspace = true @@ -54,6 +60,9 @@ xcm-builder.workspace = true xcm-executor.workspace = true xcm.workspace = true +#benchmarking +frame-benchmarking = { workspace = true, optional = true } + [features] default = ["std"] fast-gov = [] @@ -63,6 +72,7 @@ runtime-benchmarks = [ "attestation/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "kilt-dip-primitives/runtime-benchmarks", "kilt-support/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-membership/runtime-benchmarks", @@ -74,27 +84,35 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", ] std = [ "cumulus-pallet-parachain-system/std", "cumulus-pallet-dmp-queue/std", "cumulus-pallet-xcmp-queue/std", "attestation/std", + "did/std", "parity-scale-codec/std", "cumulus-primitives-core/std", "frame-support/std", "frame-system/std", "kilt-asset-dids/std", "kilt-support/std", + "kilt-dip-primitives/std", + "pallet-did-lookup/std", + "pallet-dip-provider/std", + "pallet-web3-names/std", "log/std", "pallet-authorship/std", "pallet-balances/std", "pallet-multisig/std", "pallet-membership/std", + "pallet-multisig/std", "pallet-transaction-payment/std", "pallet-treasury/std", "pallet-tips/std", "parachain-staking/std", + "parity-scale-codec/std", "polkadot-parachain/std", "public-credentials/std", "scale-info/std", @@ -103,9 +121,11 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-trie/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", + "frame-benchmarking?/std", ] try-runtime = [ "cumulus-pallet-parachain-system/try-runtime", diff --git a/runtimes/common/src/assets.rs b/runtimes/common/src/assets.rs index 784bc692d..21368e6ca 100644 --- a/runtimes/common/src/assets.rs +++ b/runtimes/common/src/assets.rs @@ -104,8 +104,8 @@ mod benchmarks { } } - impl kilt_support::traits::GetWorstCase for AssetDid { - fn worst_case() -> Self { + impl kilt_support::traits::GetWorstCase for AssetDid { + fn worst_case(_context: Context) -> Self { // Returns the worst case for an AssetDID, which is represented by the longest // identifier according to the spec. Self::try_from( diff --git a/runtimes/common/src/constants.rs b/runtimes/common/src/constants.rs index a37b989b5..0ad68f6c9 100644 --- a/runtimes/common/src/constants.rs +++ b/runtimes/common/src/constants.rs @@ -166,6 +166,22 @@ pub mod delegation { } } +pub mod deposit_storage { + // Keys is an enum with a single variant (DidIdentifier, + // IdentityCommitmentVersion) which is 32 + 2 = 34 bytes. Adding the + // discriminant byte, it totals to 35 bytes. + pub const MAX_DEPOSIT_PALLET_KEY_LENGTH: u32 = 35; +} + +pub mod dip_provider { + use super::*; + + pub const MAX_LINKED_ACCOUNTS: u32 = 10; + // Commitment are 32-byte hashes. + pub const MAX_COMMITMENT_BYTE_LENGTH: u32 = 32; + pub const COMMITMENT_DEPOSIT: Balance = deposit(1, MAX_COMMITMENT_BYTE_LENGTH); +} + pub mod staking { use super::*; diff --git a/runtimes/common/src/dip/README.md b/runtimes/common/src/dip/README.md new file mode 100644 index 000000000..47664afb0 --- /dev/null +++ b/runtimes/common/src/dip/README.md @@ -0,0 +1,16 @@ +# KILT Decentralized Identity Provider (DIP) provider specification + +Specification of the format of a DIP identity commitment and the expected format of a DIP identity proof for cross-chain transactions using KILT identities. + +## V0 + +The V0 of the KILT DIP Provider specification defines the following components: + +* **Identity details**: What are the pieces of a KILT identity that can be used for cross-chain transactions. V0 defines them to include the following information: + * All `DidKey`s stored under the subject's DID Document. For more details about how these keys are defined, read the [KILT DID pallet](../../../../pallets/did). + * All the `LinkableAccountId`s the DID subject has linked to the DID via the KILT linking pallet. For more details about how on-chain linking works, read the [KILT lookup pallet](../../../../pallets/pallet-did-lookup/). + * (OPTIONAL) The web3name of the DID subject, if present. For more details about how web3names work, read the [KILT web3name pallet](../../../../pallets/pallet-web3-names/). +* **Identity commitment**: Defines how the identity details above are aggregated into a value which will be selectively shared on a consumer chain for a cross-chain transaction. V0 defines the identity commitment as a Merkle root of all the elements above that uses the shame hashing algorithm as the runtime. Using a Merkle root allows the DID subject to generate proof that can selectively disclose different pieces of identity for different operations on different chains providing, among other things, better scalability for cases in which the linked information becomes large. The leaves encoded in the commitment can be of the following type: + * DID key leaf: with leaf name being the key ID, and leaf value being the key details as defined in the `DidPublicKeyDetails` type. + * Linked account leaf: with leaf name being the linked account ID, and leaf value being an empty tuple `()`. + * Web3name leaf: with leaf name being the web3name, and leaf value being the KILT block number in which it was linked to the DID. diff --git a/runtimes/common/src/dip/did.rs b/runtimes/common/src/dip/did.rs new file mode 100644 index 000000000..9056b7990 --- /dev/null +++ b/runtimes/common/src/dip/did.rs @@ -0,0 +1,256 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::did_details::DidDetails; +use frame_support::ensure; +use frame_system::pallet_prelude::BlockNumberFor; +use kilt_dip_primitives::merkle::RevealedWeb3Name; +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_provider::traits::IdentityProvider; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::ConstU32; +use sp_runtime::{BoundedVec, SaturatedConversion}; +use sp_std::vec::Vec; + +#[cfg(feature = "runtime-benchmarks")] +use kilt_support::{benchmark::IdentityContext, traits::GetWorstCase}; + +#[derive(Encode, Decode, TypeInfo, Debug)] +pub enum LinkedDidInfoProviderError { + DidNotFound, + DidDeleted, + TooManyLinkedAccounts, + Internal, +} + +impl From for u16 { + fn from(value: LinkedDidInfoProviderError) -> Self { + match value { + LinkedDidInfoProviderError::DidNotFound => 0, + LinkedDidInfoProviderError::DidDeleted => 1, + LinkedDidInfoProviderError::TooManyLinkedAccounts => 2, + LinkedDidInfoProviderError::Internal => u16::MAX, + } + } +} + +pub type Web3OwnershipOf = + RevealedWeb3Name<::Web3Name, BlockNumberFor>; + +/// Identity information related to a KILT DID relevant for cross-chain +/// transactions via the DIP protocol. +pub struct LinkedDidInfoOf +where + Runtime: did::Config + pallet_web3_names::Config, +{ + /// The DID Document of the subject. + pub did_details: DidDetails, + /// The optional web3name details linked to the subject. + pub web3_name_details: Option>, + /// The list of accounts the subject has previously linked via the linking + /// pallet. + pub linked_accounts: BoundedVec>, +} + +/// Type implementing the [`IdentityProvider`] trait which is responsible for +/// collecting the DID information relevant for DIP cross-chain transactions by +/// interacting with the different pallets involved. +pub struct LinkedDidInfoProvider; + +impl IdentityProvider for LinkedDidInfoProvider +where + Runtime: did::Config::Identifier> + + pallet_web3_names::Config::Identifier> + + pallet_did_lookup::Config::Identifier> + + pallet_dip_provider::Config, +{ + type Error = LinkedDidInfoProviderError; + type Success = LinkedDidInfoOf; + + fn retrieve(identifier: &Runtime::Identifier) -> Result { + ensure!( + did::Pallet::::get_deleted_did(identifier).is_none(), + LinkedDidInfoProviderError::DidDeleted, + ); + let did_details = did::Pallet::::get_did(identifier).ok_or(LinkedDidInfoProviderError::DidNotFound)?; + + let web3_name_details = retrieve_w3n::(identifier)?; + + let linked_accounts = retrieve_linked_accounts::(identifier)?; + + Ok(LinkedDidInfoOf { + did_details, + web3_name_details, + linked_accounts, + }) + } +} + +fn retrieve_w3n( + identifier: &Runtime::Identifier, +) -> Result>, LinkedDidInfoProviderError> +where + Runtime: did::Config::Identifier> + + pallet_web3_names::Config::Identifier> + + pallet_dip_provider::Config, +{ + let Some(web3_name) = pallet_web3_names::Pallet::::names(identifier) else { + return Ok(None); + }; + + let ownership = pallet_web3_names::Pallet::::owner(&web3_name).ok_or_else(|| { + log::error!( + "Inconsistent reverse map pallet_web3_names::owner(web3_name). Cannot find owner for web3name {:#?}", + web3_name + ); + LinkedDidInfoProviderError::Internal + })?; + + Ok(Some(Web3OwnershipOf:: { + web3_name, + claimed_at: ownership.claimed_at, + })) +} + +fn retrieve_linked_accounts( + identifier: &Runtime::Identifier, +) -> Result>, LinkedDidInfoProviderError> +where + Runtime: did::Config::Identifier> + + pallet_did_lookup::Config::Identifier> + + pallet_dip_provider::Config, +{ + // Check if the user has too many linked accounts. If they have more than + // [MAX_LINKED_ACCOUNTS], we throw an error. + let are_linked_accounts_within_limit = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier) + .nth(MAX_LINKED_ACCOUNTS.saturated_into()) + .is_none(); + + ensure!( + are_linked_accounts_within_limit, + LinkedDidInfoProviderError::TooManyLinkedAccounts + ); + + pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier) + .take(MAX_LINKED_ACCOUNTS.saturated_into()) + .collect::>() + .try_into() + // Should never happen since we checked above. + .map_err(|_| LinkedDidInfoProviderError::TooManyLinkedAccounts) +} + +#[cfg(feature = "runtime-benchmarks")] +impl GetWorstCase> + for LinkedDidInfoOf +where + Runtime: did::Config::Identifier> + + pallet_web3_names::Config::Identifier> + + pallet_did_lookup::Config::Identifier> + + pallet_dip_provider::Config + + pallet_balances::Config, + ::AccountId: Into + From, + ::AccountId: AsRef<[u8; 32]> + From<[u8; 32]>, +{ + fn worst_case(context: IdentityContext) -> Self { + use did::{ + did_details::DidVerificationKey, + mock_utils::{generate_base_did_creation_details, get_key_agreement_keys}, + }; + use frame_benchmarking::{vec, Zero}; + use frame_support::traits::fungible::Mutate; + use sp_io::crypto::{ed25519_generate, sr25519_generate}; + use sp_runtime::{traits::Get, KeyTypeId}; + + use crate::constants::KILT; + + // Did Details. + + let submitter = context.submitter; + let did = context.did; + + let amount = KILT * 100; + + // give some money + as Mutate<::AccountId>>::set_balance( + &submitter, + amount.saturated_into(), + ); + + let max_new_keys = ::MaxNewKeyAgreementKeys::get(); + + let new_key_agreement_keys = get_key_agreement_keys::(max_new_keys); + + let mut did_creation_details = generate_base_did_creation_details(did.clone(), submitter.clone()); + + let attestation_key = ed25519_generate(KeyTypeId(*b"0001"), None); + let delegation_key = ed25519_generate(KeyTypeId(*b"0002"), None); + let auth_key = ed25519_generate(KeyTypeId(*b"0003"), None); + did_creation_details.new_attestation_key = Some(DidVerificationKey::from(attestation_key)); + did_creation_details.new_delegation_key = Some(DidVerificationKey::from(delegation_key)); + did_creation_details.new_key_agreement_keys = new_key_agreement_keys; + + let did_details = did::did_details::DidDetails::new_with_creation_details( + did_creation_details, + DidVerificationKey::from(auth_key), + ) + .expect("Creation of DID details should not fail."); + + // add to storage. + did::Pallet::::try_insert_did(did.clone(), did_details.clone(), submitter.clone()) + .expect("Inserting Did should not fail."); + + let max_name_length = ::MaxNameLength::get() + .try_into() + .expect("max name length should not fail."); + + let web3_name_input: BoundedVec::MaxNameLength> = + BoundedVec::try_from(vec![b'1'; max_name_length]).expect("BoundedVec creation should not fail."); + + let web3_name = pallet_web3_names::Web3NameOf::::try_from(web3_name_input.to_vec()) + .expect("Creation of w3n from w3n input should not fail."); + + pallet_web3_names::Pallet::::register_name(web3_name.clone(), did.clone(), submitter.clone()) + .expect("Inserting w3n into storage should not fail."); + + let web3_name_details = Some(RevealedWeb3Name { + web3_name, + claimed_at: BlockNumberFor::::zero(), + }); + + let mut linked_accounts = vec![]; + + (0..MAX_LINKED_ACCOUNTS).for_each(|index| { + let connected_acc = sr25519_generate(KeyTypeId(index.to_be_bytes()), None); + let connected_acc_id: ::AccountId = connected_acc.into(); + let linkable_id: LinkableAccountId = connected_acc_id.into(); + pallet_did_lookup::Pallet::::add_association(submitter.clone(), did.clone(), linkable_id.clone()) + .expect("association should not fail."); + + linked_accounts.push(linkable_id); + }); + + LinkedDidInfoOf { + did_details, + linked_accounts: linked_accounts + .try_into() + .expect("BoundedVec creation of linked accounts should not fail."), + web3_name_details, + } + } +} diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs new file mode 100644 index 000000000..2ab8cb5be --- /dev/null +++ b/runtimes/common/src/dip/merkle.rs @@ -0,0 +1,397 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org +use did::{DidVerificationKeyRelationship, KeyIdOf}; +use frame_support::RuntimeDebug; +use frame_system::pallet_prelude::BlockNumberFor; +use kilt_dip_primitives::merkle::{DidKeyMerkleKey, DidKeyMerkleValue, DidMerkleProof}; +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_provider::{ + traits::{IdentityCommitmentGenerator, IdentityProvider}, + IdentityCommitmentVersion, IdentityOf, +}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_std::{borrow::ToOwned, marker::PhantomData, vec::Vec}; +use sp_trie::{generate_trie_proof, LayoutV1, MemoryDB, TrieDBMutBuilder, TrieHash, TrieMut}; + +use kilt_dip_primitives::merkle::{DidKeyRelationship, RevealedDidMerkleProofLeaf}; + +use crate::dip::did::LinkedDidInfoOf; + +pub type BlindedValue = Vec; +/// Type of the Merkle proof revealing parts of the DIP identity of a given DID +/// subject. +pub type DidMerkleProofOf = DidMerkleProof< + Vec, + RevealedDidMerkleProofLeaf< + KeyIdOf, + ::AccountId, + BlockNumberFor, + ::Web3Name, + LinkableAccountId, + >, +>; + +/// Type of a complete DIP Merkle proof. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct CompleteMerkleProof { + /// The Merkle root. + pub root: Root, + /// The Merkle proof revealing parts of the commitment that verify against + /// the provided root. + pub proof: Proof, +} + +#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo, PartialEq)] +pub enum DidMerkleProofError { + UnsupportedVersion, + KeyNotFound, + LinkedAccountNotFound, + Web3NameNotFound, + Internal, +} + +impl From for u16 { + fn from(value: DidMerkleProofError) -> Self { + match value { + DidMerkleProofError::UnsupportedVersion => 0, + DidMerkleProofError::KeyNotFound => 1, + DidMerkleProofError::LinkedAccountNotFound => 2, + DidMerkleProofError::Web3NameNotFound => 3, + DidMerkleProofError::Internal => u16::MAX, + } + } +} + +pub mod v0 { + use super::*; + + /// Type of a Merkle leaf revealed as part of a DIP Merkle proof. + type ProofLeafOf = RevealedDidMerkleProofLeaf< + KeyIdOf, + ::AccountId, + BlockNumberFor, + ::Web3Name, + LinkableAccountId, + >; + + /// Given the provided DID info, it calculates the Merkle commitment (root) + /// using the provided in-memory DB. + pub(super) fn calculate_root_with_db( + identity: &LinkedDidInfoOf, + db: &mut MemoryDB, + ) -> Result + where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + { + let LinkedDidInfoOf { + did_details, + web3_name_details, + linked_accounts, + } = identity; + let mut trie = TrieHash::>::default(); + let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); + + // Authentication key + let auth_key_details = did_details + .public_keys + .get(&did_details.authentication_key) + .ok_or_else(|| { + log::error!("Authentication key should be part of the public keys."); + DidMerkleProofError::Internal + })?; + let auth_leaf = ProofLeafOf::::DidKey( + DidKeyMerkleKey( + did_details.authentication_key, + DidVerificationKeyRelationship::Authentication.into(), + ), + DidKeyMerkleValue(auth_key_details.clone()), + ); + trie_builder + .insert(auth_leaf.encoded_key().as_slice(), auth_leaf.encoded_value().as_slice()) + .map_err(|_| { + log::error!( + "Failed to insert authentication key in the trie builder. Authentication leaf: {:#?}", + auth_leaf + ); + DidMerkleProofError::Internal + })?; + // Attestation key, if present + if let Some(att_key_id) = did_details.attestation_key { + let att_key_details = did_details.public_keys.get(&att_key_id).ok_or_else(|| { + log::error!("Attestation key should be part of the public keys."); + DidMerkleProofError::Internal + })?; + let att_leaf = ProofLeafOf::::DidKey( + (att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()).into(), + att_key_details.clone().into(), + ); + trie_builder + .insert(att_leaf.encoded_key().as_slice(), att_leaf.encoded_value().as_slice()) + .map_err(|_| { + log::error!( + "Failed to insert attestation key in the trie builder. Attestation leaf: {:#?}", + att_leaf + ); + DidMerkleProofError::Internal + })?; + }; + // Delegation key, if present + if let Some(del_key_id) = did_details.delegation_key { + let del_key_details = did_details.public_keys.get(&del_key_id).ok_or_else(|| { + log::error!("Delegation key should be part of the public keys."); + DidMerkleProofError::Internal + })?; + let del_leaf = ProofLeafOf::::DidKey( + (del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()).into(), + del_key_details.clone().into(), + ); + trie_builder + .insert(del_leaf.encoded_key().as_slice(), del_leaf.encoded_value().as_slice()) + .map_err(|_| { + log::error!( + "Failed to insert delegation key in the trie builder. Delegation leaf: {:#?}", + del_leaf + ); + DidMerkleProofError::Internal + })?; + }; + // Key agreement keys + did_details + .key_agreement_keys + .iter() + .try_for_each(|id| -> Result<(), DidMerkleProofError> { + let key_agreement_details = did_details.public_keys.get(id).ok_or_else(|| { + log::error!("Key agreement key should be part of the public keys."); + DidMerkleProofError::Internal + })?; + let enc_leaf = ProofLeafOf::::DidKey( + (*id, DidKeyRelationship::Encryption).into(), + key_agreement_details.clone().into(), + ); + trie_builder + .insert(enc_leaf.encoded_key().as_slice(), enc_leaf.encoded_value().as_slice()) + .map_err(|_| { + log::error!( + "Failed to insert key agreement key in the trie builder. Key agreement leaf: {:#?}", + enc_leaf + ); + DidMerkleProofError::Internal + })?; + Ok(()) + })?; + + // Linked accounts + linked_accounts + .iter() + .try_for_each(|linked_account| -> Result<(), DidMerkleProofError> { + let linked_account_leaf = + ProofLeafOf::::LinkedAccount(linked_account.clone().into(), ().into()); + trie_builder + .insert( + linked_account_leaf.encoded_key().as_slice(), + linked_account_leaf.encoded_value().as_slice(), + ) + .map_err(|_| { + log::error!( + "Failed to insert linked account in the trie builder. Linked account leaf: {:#?}", + linked_account_leaf + ); + DidMerkleProofError::Internal + })?; + Ok(()) + })?; + + // Web3name, if present + if let Some(web3name_details) = web3_name_details { + let web3_name_leaf = ProofLeafOf::::Web3Name( + web3name_details.web3_name.clone().into(), + web3name_details.claimed_at.into(), + ); + trie_builder + .insert( + web3_name_leaf.encoded_key().as_slice(), + web3_name_leaf.encoded_value().as_slice(), + ) + .map_err(|_| { + log::error!( + "Failed to insert web3name in the trie builder. Web3name leaf: {:#?}", + web3_name_leaf + ); + DidMerkleProofError::Internal + })?; + } + + trie_builder.commit(); + Ok(trie_builder.root().to_owned()) + } + + /// Given the provided DID info, and a set of DID key IDs, account IDs and a + /// web3name, generates a Merkle proof that reveals only the provided + /// identity components. The function fails if no key or account with the + /// specified ID can be found, or if a web3name is requested to be revealed + /// in the proof but is not present in the provided identity details. + pub(super) fn generate_proof<'a, Runtime, K, A, const MAX_LINKED_ACCOUNT: u32>( + identity: &LinkedDidInfoOf, + key_ids: K, + should_include_web3_name: bool, + account_ids: A, + ) -> Result>, DidMerkleProofError> + where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + K: Iterator>, + A: Iterator, + { + let LinkedDidInfoOf { + did_details, + web3_name_details, + linked_accounts, + } = identity; + + let mut db = MemoryDB::default(); + let root = calculate_root_with_db(identity, &mut db)?; + + let mut leaves = key_ids + .map(|key_id| -> Result<_, DidMerkleProofError> { + let key_details = did_details + .public_keys + .get(key_id) + .ok_or(DidMerkleProofError::KeyNotFound)?; + // Create the merkle leaf key depending on the relationship of the key to the + // DID document. + let did_key_merkle_key: DidKeyMerkleKey> = if *key_id == did_details.authentication_key + { + Ok((*key_id, DidVerificationKeyRelationship::Authentication.into()).into()) + } else if Some(*key_id) == did_details.attestation_key { + Ok((*key_id, DidVerificationKeyRelationship::AssertionMethod.into()).into()) + } else if Some(*key_id) == did_details.delegation_key { + Ok((*key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()).into()) + } else if did_details.key_agreement_keys.contains(key_id) { + Ok((*key_id, DidKeyRelationship::Encryption).into()) + } else { + log::error!("Unknown key ID {:#?} retrieved from DID details.", key_id); + Err(DidMerkleProofError::Internal) + }?; + Ok(RevealedDidMerkleProofLeaf::DidKey( + did_key_merkle_key, + key_details.clone().into(), + )) + }) + .chain(account_ids.map(|account_id| -> Result<_, DidMerkleProofError> { + if linked_accounts.contains(account_id) { + Ok(RevealedDidMerkleProofLeaf::LinkedAccount( + account_id.clone().into(), + ().into(), + )) + } else { + Err(DidMerkleProofError::LinkedAccountNotFound) + } + })) + .collect::, _>>()?; + + match (should_include_web3_name, web3_name_details) { + // If web3name should be included and it exists, add to the leaves to be revealed... + (true, Some(web3name_details)) => { + leaves.push(RevealedDidMerkleProofLeaf::Web3Name( + web3name_details.web3_name.clone().into(), + web3name_details.claimed_at.into(), + )); + } + // ...else if web3name should be included and it DOES NOT exist, return an error... + (true, None) => return Err(DidMerkleProofError::Web3NameNotFound), + // ...else (if web3name should NOT be included), skip. + (false, _) => {} + }; + + let encoded_keys: Vec> = leaves.iter().map(|l| l.encoded_key()).collect(); + let proof = + generate_trie_proof::, _, _, _>(&db, root, &encoded_keys).map_err(|_| { + log::error!( + "Failed to generate a merkle proof for the encoded keys: {:#?}", + encoded_keys + ); + DidMerkleProofError::Internal + })?; + Ok(CompleteMerkleProof { + root, + proof: DidMerkleProofOf:: { + blinded: proof, + revealed: leaves.into_iter().collect(), + }, + }) + } + + /// Given the provided DID info, generates a Merkle commitment (root). + pub(super) fn generate_commitment( + identity: &IdentityOf, + ) -> Result + where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config + pallet_dip_provider::Config, + Runtime::IdentityProvider: IdentityProvider>, + { + let mut db = MemoryDB::default(); + calculate_root_with_db(identity, &mut db) + } +} + +/// Type implementing the [`IdentityCommitmentGenerator`] and generating a +/// Merkle root of the provided identity details, according to the description +/// provided in the [README.md](./README.md), +pub struct DidMerkleRootGenerator(PhantomData); + +impl IdentityCommitmentGenerator for DidMerkleRootGenerator +where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config + pallet_dip_provider::Config, + Runtime::IdentityProvider: IdentityProvider>, +{ + type Error = DidMerkleProofError; + type Output = Runtime::Hash; + + fn generate_commitment( + _identifier: &Runtime::Identifier, + identity: &IdentityOf, + version: IdentityCommitmentVersion, + ) -> Result { + match version { + 0 => v0::generate_commitment::(identity), + _ => Err(DidMerkleProofError::UnsupportedVersion), + } + } +} + +impl DidMerkleRootGenerator +where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, +{ + pub fn generate_proof<'a, K, A, const MAX_LINKED_ACCOUNT: u32>( + identity: &LinkedDidInfoOf, + version: IdentityCommitmentVersion, + key_ids: K, + should_include_web3_name: bool, + account_ids: A, + ) -> Result>, DidMerkleProofError> + where + K: Iterator>, + A: Iterator, + { + match version { + 0 => v0::generate_proof(identity, key_ids, should_include_web3_name, account_ids), + _ => Err(DidMerkleProofError::UnsupportedVersion), + } + } +} diff --git a/runtimes/common/src/dip/mod.rs b/runtimes/common/src/dip/mod.rs new file mode 100644 index 000000000..9a578cec0 --- /dev/null +++ b/runtimes/common/src/dip/mod.rs @@ -0,0 +1,24 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![doc = include_str!("./README.md")] + +/// Logic for collecting information related to a KILT DID. +pub mod did; +/// Logic for generating Merkle commitments of a KILT DID identity. +pub mod merkle; diff --git a/runtimes/common/src/lib.rs b/runtimes/common/src/lib.rs index 2c2de7cb6..113c326e8 100644 --- a/runtimes/common/src/lib.rs +++ b/runtimes/common/src/lib.rs @@ -39,7 +39,7 @@ use pallet_balances::Pallet as PalletBalance; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use sp_runtime::{ generic, - traits::{Bounded, IdentifyAccount, Verify}, + traits::{BlakeTwo256, Bounded, IdentifyAccount, Verify}, FixedPointNumber, MultiSignature, Perquintill, SaturatedConversion, }; use sp_std::marker::PhantomData; @@ -47,6 +47,7 @@ use sp_std::marker::PhantomData; pub mod assets; pub mod authorization; pub mod constants; +pub mod dip; pub mod errors; pub mod fees; pub mod migrations; @@ -106,8 +107,10 @@ pub type Amount = i128; /// Nonce of a transaction in the chain. pub type Nonce = u64; +/// Hasher for chain data. +pub type Hasher = BlakeTwo256; /// A hash of some data used by the chain. -pub type Hash = sp_core::H256; +pub type Hash = ::Out; /// Digest item type. pub type DigestItem = generic::DigestItem; diff --git a/runtimes/peregrine/Cargo.toml b/runtimes/peregrine/Cargo.toml index e4ee38502..288f22db5 100644 --- a/runtimes/peregrine/Cargo.toml +++ b/runtimes/peregrine/Cargo.toml @@ -36,9 +36,12 @@ attestation.workspace = true ctype.workspace = true delegation.workspace = true did.workspace = true +kilt-runtime-api-dip-provider.workspace = true kilt-support.workspace = true pallet-configuration.workspace = true +pallet-deposit-storage.workspace = true pallet-did-lookup.workspace = true +pallet-dip-provider.workspace = true pallet-inflation.workspace = true pallet-web3-names.workspace = true pallet-migration.workspace = true @@ -129,7 +132,9 @@ runtime-benchmarks = [ "pallet-collective/runtime-benchmarks", "pallet-configuration/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", + "pallet-deposit-storage/runtime-benchmarks", "pallet-did-lookup/runtime-benchmarks", + "pallet-dip-provider/runtime-benchmarks", "pallet-indices/runtime-benchmarks", "pallet-inflation/runtime-benchmarks", "pallet-membership/runtime-benchmarks", @@ -175,6 +180,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "kilt-runtime-api-did/std", + "kilt-runtime-api-dip-provider/std", "kilt-runtime-api-public-credentials/std", "kilt-runtime-api-staking/std", "kilt-support/std", @@ -186,7 +192,9 @@ std = [ "pallet-collective/std", "pallet-configuration/std", "pallet-democracy/std", + "pallet-deposit-storage/std", "pallet-did-lookup/std", + "pallet-dip-provider/std", "pallet-indices/std", "pallet-inflation/std", "pallet-membership/std", @@ -249,7 +257,9 @@ try-runtime = [ "pallet-collective/try-runtime", "pallet-configuration/try-runtime", "pallet-democracy/try-runtime", + "pallet-deposit-storage/try-runtime", "pallet-did-lookup/try-runtime", + "pallet-dip-provider/try-runtime", "pallet-indices/try-runtime", "pallet-inflation/try-runtime", "pallet-membership/try-runtime", diff --git a/runtimes/peregrine/src/dip/deposit.rs b/runtimes/peregrine/src/dip/deposit.rs new file mode 100644 index 000000000..427645139 --- /dev/null +++ b/runtimes/peregrine/src/dip/deposit.rs @@ -0,0 +1,149 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{DidIdentifier, Runtime}; +use frame_support::traits::Get; +use pallet_deposit_storage::{ + traits::DepositStorageHooks, DepositEntryOf, DepositKeyOf, FixedDepositCollectorViaDepositsPallet, +}; +use pallet_dip_provider::IdentityCommitmentVersion; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use runtime_common::constants::dip_provider::COMMITMENT_DEPOSIT; +use scale_info::TypeInfo; +use sp_core::{ConstU128, RuntimeDebug}; + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug)] +pub enum DepositNamespace { + DipProvider, +} + +/// The namespace to use in the [`pallet_deposit_storage::Pallet`] to store +/// all deposits related to DIP commitments. +pub struct DipProviderDepositNamespace; + +impl Get for DipProviderDepositNamespace { + fn get() -> DepositNamespace { + DepositNamespace::DipProvider + } +} + +/// The various different keys that can be stored in the storage-tracking +/// pallet. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug)] +pub enum DepositKey { + DipProvider { + identifier: DidIdentifier, + version: IdentityCommitmentVersion, + }, +} + +impl From<(DidIdentifier, IdentityCommitmentVersion)> for DepositKey { + fn from((identifier, version): (DidIdentifier, IdentityCommitmentVersion)) -> Self { + Self::DipProvider { identifier, version } + } +} + +/// The additional logic to execute whenever a deposit is removed by its +/// owner directly via the [`pallet_deposit_storage::Pallet`] pallet. +pub type DepositCollectorHooks = + FixedDepositCollectorViaDepositsPallet, DepositKey>; + +pub enum CommitmentDepositRemovalHookError { + DecodeKey, + Internal, +} + +impl From for u16 { + fn from(value: CommitmentDepositRemovalHookError) -> Self { + match value { + CommitmentDepositRemovalHookError::DecodeKey => 0, + CommitmentDepositRemovalHookError::Internal => u16::MAX, + } + } +} + +/// The logic to execute whenever an identity commitment is generated and +/// stored in the [`pallet_dip_provider::Pallet`] pallet. +/// +/// Upon storing and removing identity commitments, this hook will reserve +/// or release deposits from the [`pallet_deposit_storage::Pallet`] pallet. +pub struct DepositHooks; + +impl DepositStorageHooks for DepositHooks { + type Error = CommitmentDepositRemovalHookError; + + fn on_deposit_reclaimed( + _namespace: &::Namespace, + key: &DepositKeyOf, + deposit: DepositEntryOf, + ) -> Result<(), Self::Error> { + let DepositKey::DipProvider { identifier, version } = + DepositKey::decode(&mut &key[..]).map_err(|_| CommitmentDepositRemovalHookError::DecodeKey)?; + pallet_dip_provider::Pallet::::delete_identity_commitment_storage_entry( + &identifier, + // Deposit owner is the only one authorized to remove the deposit. + &deposit.deposit.owner, + version, + ) + .map_err(|_| { + log::error!( + "Should not fail to remove commitment for identifier {:#?} and version {version}", + identifier + ); + CommitmentDepositRemovalHookError::Internal + })?; + Ok(()) + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct PalletDepositStorageBenchmarkHooks; + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_deposit_storage::traits::BenchmarkHooks for PalletDepositStorageBenchmarkHooks { + fn pre_reclaim_deposit() -> ( + ::AccountId, + ::Namespace, + sp_runtime::BoundedVec::MaxKeyLength>, + ) { + let submitter = runtime_common::AccountId::from([100u8; 32]); + let namespace = DepositNamespace::DipProvider; + let did_identifier = DidIdentifier::from([200u8; 32]); + let commitment_version = 0u16; + let key: DepositKeyOf = (did_identifier.clone(), 0) + .encode() + .try_into() + .expect("Should not fail to create a key for a DIP commitment."); + + pallet_dip_provider::IdentityCommitments::::insert( + &did_identifier, + commitment_version, + ::Hash::default(), + ); + + assert!(pallet_dip_provider::IdentityCommitments::::get(did_identifier, commitment_version).is_some()); + + (submitter, namespace, key) + } + + fn post_reclaim_deposit() { + let did_identifier = DidIdentifier::from([200u8; 32]); + let commitment_version = 0u16; + assert!(pallet_dip_provider::IdentityCommitments::::get(did_identifier, commitment_version).is_none()); + } +} diff --git a/runtimes/peregrine/src/dip/mod.rs b/runtimes/peregrine/src/dip/mod.rs new file mode 100644 index 000000000..522def8fd --- /dev/null +++ b/runtimes/peregrine/src/dip/mod.rs @@ -0,0 +1,69 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::{DidRawOrigin, EnsureDidOrigin}; +use frame_system::EnsureSigned; +use runtime_common::{ + constants::{deposit_storage::MAX_DEPOSIT_PALLET_KEY_LENGTH, dip_provider::MAX_LINKED_ACCOUNTS}, + dip::{did::LinkedDidInfoProvider, merkle::DidMerkleRootGenerator}, + AccountId, DidIdentifier, +}; +use sp_core::ConstU32; + +use crate::{ + dip::deposit::{DepositCollectorHooks, DepositHooks, DepositNamespace}, + Balances, Runtime, RuntimeEvent, RuntimeHoldReason, +}; + +pub(crate) mod deposit; +pub(crate) mod runtime_api; + +impl pallet_dip_provider::Config for Runtime { + // Only DID origins can submit the commitment identity tx, which will go through + // only if the DID in the origin matches the identifier specified in the tx. + type CommitOriginCheck = EnsureDidOrigin; + type CommitOrigin = DidRawOrigin; + type Identifier = DidIdentifier; + // The identity commitment is defined as the Merkle root of the linked identity + // info, as specified by the [`LinkedDidInfoProvider`]. + type IdentityCommitmentGenerator = DidMerkleRootGenerator; + // Identity info is defined as the collection of DID keys, linked accounts, and + // the optional web3name of a given DID subject. + type IdentityProvider = LinkedDidInfoProvider; + type ProviderHooks = DepositCollectorHooks; + type RuntimeEvent = RuntimeEvent; + // TODO: Change after benchmarks + type WeightInfo = (); +} + +impl pallet_deposit_storage::Config for Runtime { + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHooks = deposit::PalletDepositStorageBenchmarkHooks; + // Any signed origin can submit the tx, which will go through only if the + // deposit payer matches the signed origin. + type CheckOrigin = EnsureSigned; + // The balances pallet is used to reserve/unreserve tokens. + type Currency = Balances; + type DepositHooks = DepositHooks; + type MaxKeyLength = ConstU32; + type Namespace = DepositNamespace; + type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + // TODO: Change after benchmarks + type WeightInfo = (); +} diff --git a/runtimes/peregrine/src/dip/runtime_api.rs b/runtimes/peregrine/src/dip/runtime_api.rs new file mode 100644 index 000000000..dc240b612 --- /dev/null +++ b/runtimes/peregrine/src/dip/runtime_api.rs @@ -0,0 +1,54 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::KeyIdOf; +use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_provider::IdentityCommitmentVersion; +use parity_scale_codec::{Decode, Encode}; +use runtime_common::{ + dip::{did::LinkedDidInfoProviderError, merkle::DidMerkleProofError}, + DidIdentifier, +}; +use scale_info::TypeInfo; +use sp_std::vec::Vec; + +use crate::Runtime; + +/// Parameters for a DIP proof request. +#[derive(Encode, Decode, TypeInfo)] +pub struct DipProofRequest { + /// The subject identifier for which to generate the DIP proof. + pub(crate) identifier: DidIdentifier, + /// The DIP version. + pub(crate) version: IdentityCommitmentVersion, + /// The DID key IDs of the subject's DID Document to reveal in the DIP + /// proof. + pub(crate) keys: Vec>, + /// The list of accounts linked to the subject's DID to reveal in the + /// DIP proof. + pub(crate) accounts: Vec, + /// A flag indicating whether the web3name claimed by the DID subject + /// should revealed in the DIP proof. + pub(crate) should_include_web3_name: bool, +} + +#[derive(Encode, Decode, TypeInfo)] +pub enum DipProofError { + IdentityProvider(LinkedDidInfoProviderError), + MerkleProof(DidMerkleProofError), +} diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index f92550a3a..fcf76aa16 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -59,6 +59,7 @@ use runtime_common::{ assets::{AssetDid, PublicCredentialsFilter}, authorization::{AuthorizationId, PalletAuthorize}, constants::{self, UnvestedFundsAllowedWithdrawReasons, EXISTENTIAL_DEPOSIT, KILT}, + dip::merkle::{CompleteMerkleProof, DidMerkleProofOf, DidMerkleRootGenerator}, errors::PublicCredentialsApiError, fees::{ToAuthor, WeightToFee}, pallet_id, AccountId, AuthorityId, Balance, BlockHashCount, BlockLength, BlockNumber, BlockWeights, DidIdentifier, @@ -78,6 +79,7 @@ pub use sp_runtime::BuildStorage; #[cfg(test)] mod tests; +mod dip; mod weights; mod xcm_config; @@ -777,8 +779,10 @@ impl InstanceFilter for ProxyType { | RuntimeCall::Ctype(..) | RuntimeCall::Delegation(..) | RuntimeCall::Democracy(..) + | RuntimeCall::DepositStorage(..) | RuntimeCall::Did(..) | RuntimeCall::DidLookup(..) + | RuntimeCall::DipProvider(..) | RuntimeCall::Indices( // Excludes `force_transfer`, and `transfer` pallet_indices::Call::claim { .. } @@ -830,6 +834,7 @@ impl InstanceFilter for ProxyType { | delegation::Call::change_deposit_owner { .. } ) | RuntimeCall::Democracy(..) + // Excludes `DepositStorage` | RuntimeCall::Did( // Excludes `reclaim_deposit` did::Call::add_key_agreement_key { .. } @@ -856,6 +861,7 @@ impl InstanceFilter for ProxyType { | pallet_did_lookup::Call::update_deposit { .. } | pallet_did_lookup::Call::change_deposit_owner { .. } ) + | RuntimeCall::DipProvider(..) | RuntimeCall::Indices(..) | RuntimeCall::Multisig(..) | RuntimeCall::ParachainStaking(..) @@ -1008,6 +1014,8 @@ construct_runtime! { Web3Names: pallet_web3_names = 68, PublicCredentials: public_credentials = 69, Migration: pallet_migration = 70, + DipProvider: pallet_dip_provider = 71, + DepositStorage: pallet_deposit_storage = 72, // Parachains pallets. Start indices at 80 to leave room. @@ -1051,6 +1059,7 @@ impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall RuntimeCall::Attestation { .. } => Ok(did::DidVerificationKeyRelationship::AssertionMethod), RuntimeCall::Ctype { .. } => Ok(did::DidVerificationKeyRelationship::AssertionMethod), RuntimeCall::Delegation { .. } => Ok(did::DidVerificationKeyRelationship::CapabilityDelegation), + RuntimeCall::DipProvider { .. } => Ok(did::DidVerificationKeyRelationship::Authentication), // DID creation is not allowed through the DID proxy. RuntimeCall::Did(did::Call::create { .. }) => Err(did::RelationshipDeriveError::NotCallableByDid), RuntimeCall::Did { .. } => Ok(did::DidVerificationKeyRelationship::Authentication), @@ -1147,6 +1156,8 @@ mod benches { [public_credentials, PublicCredentials] [pallet_xcm, PolkadotXcm] [pallet_migration, Migration] + [pallet_dip_provider, DipProvider] + [pallet_deposit_storage, DepositStorage] [frame_benchmarking::baseline, Baseline::] ); } @@ -1413,6 +1424,16 @@ impl_runtime_apis! { } } + impl kilt_runtime_api_dip_provider::DipProvider>, dip::runtime_api::DipProofError> for Runtime { + fn generate_proof(request: dip::runtime_api::DipProofRequest) -> Result>, dip::runtime_api::DipProofError> { + use pallet_dip_provider::traits::IdentityProvider; + + let identity_details = pallet_dip_provider::IdentityProviderOf::::retrieve(&request.identifier).map_err(dip::runtime_api::DipProofError::IdentityProvider)?; + + DidMerkleRootGenerator::::generate_proof(&identity_details, request.version, request.keys.iter(), request.should_include_web3_name, request.accounts.iter()).map_err(dip::runtime_api::DipProofError::MerkleProof) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( diff --git a/runtimes/peregrine/src/tests.rs b/runtimes/peregrine/src/tests.rs index 5eab813d9..14670bf67 100644 --- a/runtimes/peregrine/src/tests.rs +++ b/runtimes/peregrine/src/tests.rs @@ -17,6 +17,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use frame_support::{traits::Currency, BoundedVec}; +use pallet_dip_provider::IdentityCommitmentOf; use parity_scale_codec::MaxEncodedLen; use did::DeriveDidCallAuthorizationVerificationKeyRelationship; @@ -26,8 +27,10 @@ use pallet_web3_names::{Web3NameOf, Web3OwnershipOf}; use runtime_common::{ constants::{ attestation::MAX_ATTESTATION_BYTE_LENGTH, + deposit_storage::MAX_DEPOSIT_PALLET_KEY_LENGTH, did::{MAX_KEY_LENGTH, MAX_SERVICE_ENDPOINT_BYTE_LENGTH}, did_lookup::MAX_CONNECTION_BYTE_LENGTH, + dip_provider::MAX_COMMITMENT_BYTE_LENGTH, public_credentials::MAX_PUBLIC_CREDENTIAL_STORAGE_LENGTH, web3_names::MAX_NAME_BYTE_LENGTH, MAX_INDICES_BYTE_LENGTH, @@ -35,6 +38,8 @@ use runtime_common::{ AccountId, BlockNumber, }; +use crate::dip::deposit::DepositKey; + use super::{Runtime, RuntimeCall}; #[test] @@ -118,6 +123,19 @@ fn public_credentials_storage_sizes() { ) } +#[test] +fn pallet_deposit_storage_max_key_length() { + assert_eq!(DepositKey::max_encoded_len(), MAX_DEPOSIT_PALLET_KEY_LENGTH as usize) +} + +#[test] +fn pallet_dip_provider_commitment_max_length() { + assert_eq!( + IdentityCommitmentOf::::max_encoded_len(), + MAX_COMMITMENT_BYTE_LENGTH as usize + ) +} + #[test] fn test_derive_did_verification_relation_ctype() { let c1 = RuntimeCall::Ctype(ctype::Call::add { diff --git a/support/src/benchmark.rs b/support/src/benchmark.rs new file mode 100644 index 000000000..b19496912 --- /dev/null +++ b/support/src/benchmark.rs @@ -0,0 +1,23 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +/// Manly used for the DIP benchmarking. The worst case can be created for the +/// did and submitter. +#[derive(Clone)] +pub struct IdentityContext { + pub did: DidIdentifier, + pub submitter: AccountId, +} diff --git a/support/src/lib.rs b/support/src/lib.rs index 758062f92..e156ddc02 100644 --- a/support/src/lib.rs +++ b/support/src/lib.rs @@ -28,3 +28,6 @@ pub mod mock; #[cfg(any(feature = "try-runtime", test))] pub mod test_utils; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmark; diff --git a/support/src/mock.rs b/support/src/mock.rs index df757cfd0..a6b5fdde5 100644 --- a/support/src/mock.rs +++ b/support/src/mock.rs @@ -32,7 +32,10 @@ use sp_runtime::AccountId32; pub mod mock_origin { use sp_std::marker::PhantomData; - use frame_support::{traits::EnsureOrigin, Parameter}; + use frame_support::{ + traits::{EnsureOrigin, EnsureOriginWithArg}, + Parameter, + }; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::AccountId32; @@ -105,6 +108,35 @@ pub mod mock_origin { } } + impl EnsureOriginWithArg + for EnsureDoubleOrigin + where + OuterOrigin: Into, OuterOrigin>> + + From> + + Clone, + SubjectId: PartialEq + Clone, + AccountId: Clone + Decode, + { + type Success = DoubleOrigin; + + fn try_origin(o: OuterOrigin, a: &SubjectId) -> Result { + let did_origin: DoubleOrigin = o.clone().into()?; + if did_origin.1 == *a { + Ok(did_origin) + } else { + Err(o) + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &SubjectId) -> Result { + let zero_account_id = AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"); + + Ok(OuterOrigin::from(DoubleOrigin(zero_account_id, a.clone()))) + } + } + #[cfg(feature = "runtime-benchmarks")] impl crate::traits::GenerateBenchmarkOrigin for EnsureDoubleOrigin diff --git a/support/src/traits.rs b/support/src/traits.rs index 2c2fa6a66..b2a9f8f17 100644 --- a/support/src/traits.rs +++ b/support/src/traits.rs @@ -81,8 +81,36 @@ pub trait GenerateBenchmarkOrigin { /// Trait that allows types to implement a worst case value for a type, /// only when running benchmarks. #[cfg(feature = "runtime-benchmarks")] -pub trait GetWorstCase { - fn worst_case() -> Self; +pub trait GetWorstCase { + fn worst_case(context: Context) -> Self; +} + +#[cfg(feature = "runtime-benchmarks")] +impl GetWorstCase for u32 { + fn worst_case(_context: T) -> Self { + u32::MAX + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl GetWorstCase for () { + fn worst_case(_context: T) -> Self {} +} + +/// Trait that allows instanciating multiple instances of a type. +#[cfg(feature = "runtime-benchmarks")] +pub trait Instanciate { + fn new(instance: u32) -> Self; +} + +#[cfg(feature = "runtime-benchmarks")] +impl Instanciate for sp_runtime::AccountId32 { + fn new(instance: u32) -> Self { + use sp_runtime::traits::Hash; + sp_runtime::AccountId32::from(<[u8; 32]>::from(sp_runtime::traits::BlakeTwo256::hash( + &instance.to_be_bytes(), + ))) + } } /// Generic filter.