diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index 4ca4a8dd..3417eec6 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -4,10 +4,12 @@ on: branches: - main - develop + - will/grid-refactor pull_request: branches: - main - develop + - will/grid-refactor jobs: build_and_test: @@ -45,11 +47,17 @@ jobs: command: fmt args: --check + - name: Check Clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --workspace --features "avail-core/runtime" + - name: Run tests uses: actions-rs/cargo@v1 with: command: test - args: --workspace + args: --workspace --features "avail-core/runtime" env: RUSTFLAGS: "-C instrument-coverage" LLVM_PROFILE_FILE: "profile-%p-%m.profraw" diff --git a/Cargo.lock b/Cargo.lock index 52775712..0a8ee0d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,11 +23,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ - "gimli 0.27.1", + "gimli 0.27.3", ] [[package]] @@ -38,9 +38,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher", @@ -59,20 +59,37 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.10", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -82,6 +99,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -91,11 +114,144 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] [[package]] name = "array-bytes" @@ -105,9 +261,9 @@ checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -117,42 +273,31 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-trait" -version = "0.1.63" +version = "0.1.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "syn 2.0.25", ] [[package]] name = "auto_impl" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -161,18 +306,45 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "avail-core" +version = "0.5.0" +dependencies = [ + "beefy-merkle-tree", + "derive_more", + "frame-support", + "hash256-std-hasher", + "hex", + "hex-literal", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "serde_json", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", + "sp-trie", + "static_assertions", + "test-case", + "thiserror-no-std", +] + [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ - "addr2line 0.19.0", + "addr2line 0.20.0", "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.30.3", + "object 0.31.1", "rustc-demangle", ] @@ -218,9 +390,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64ct" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bech32" @@ -231,7 +403,7 @@ checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" [[package]] name = "beefy-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "sp-api", "sp-beefy", @@ -268,6 +440,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bitvec" version = "0.17.4" @@ -296,7 +474,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -317,16 +495,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -338,29 +516,28 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "blst" +version = "0.3.10" +source = "git+https://github.com/availproject/blst?tag=v0.3.10#556e037926d9c526c2eb6cb1522bea39690416ea" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "bs58" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byte-slice-cast" @@ -374,6 +551,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "byteorder" version = "1.4.3" @@ -382,9 +565,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" dependencies = [ "serde", ] @@ -397,9 +580,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-expr" @@ -418,21 +601,48 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", @@ -449,25 +659,29 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" dependencies = [ - "bitflags", - "textwrap", - "unicode-width", + "clap_builder", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "clap_builder" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" dependencies = [ - "termcolor", - "unicode-width", + "anstyle", + "clap_lex", ] +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + [[package]] name = "coins-bip32" version = "0.7.0" @@ -477,13 +691,13 @@ dependencies = [ "bincode", "bs58", "coins-core", - "digest 0.10.6", - "getrandom 0.2.8", + "digest 0.10.7", + "getrandom 0.2.10", "hmac 0.12.1", "k256", "lazy_static", "serde", - "sha2 0.10.6", + "sha2 0.10.7", "thiserror", ] @@ -495,12 +709,12 @@ checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" dependencies = [ "bitvec 0.17.4", "coins-bip32", - "getrandom 0.2.8", + "getrandom 0.2.10", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.7", "thiserror", ] @@ -514,22 +728,22 @@ dependencies = [ "base64 0.12.3", "bech32", "blake2", - "digest 0.10.6", - "generic-array 0.14.6", + "digest 0.10.7", + "generic-array 0.14.7", "hex", "ripemd", "serde", "serde_derive", - "sha2 0.10.6", + "sha2 0.10.7", "sha3", "thiserror", ] [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" [[package]] name = "convert_case" @@ -548,9 +762,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpp_demangle" @@ -563,9 +777,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -590,24 +804,23 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ - "atty", + "anes", "cast", + "ciborium", "clap", "criterion-plot", - "csv", + "is-terminal", "itertools 0.10.5", - "lazy_static", "num-traits", + "once_cell", "oorandom", - "plotters", "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -616,9 +829,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools 0.10.5", @@ -626,9 +839,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -636,9 +849,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -647,22 +860,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset 0.9.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -679,7 +892,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -691,7 +904,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "typenum", ] @@ -701,7 +914,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "subtle", ] @@ -711,32 +924,10 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "subtle", ] -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "ctr" version = "0.9.2" @@ -773,82 +964,24 @@ dependencies = [ ] [[package]] -name = "cxx" -version = "1.0.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322296e2f2e5af4270b54df9e85a02ff037e271af20ba3e7fe1575515dc840b8" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.88" +name = "der" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017a1385b05d631e7875b1f151c9f012d37b53491e2a87f65bff5c262b2111d8" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", + "const-oid", + "zeroize", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.88" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26bbb078acf09bc1ecda02d4223f03bdd28bd4874edcb0379138efc499ce971" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357f40d1f06a24b60ae1fe122542c1fb05d28d32acb2aed064e84bc2ad1e252e" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "da-primitives" -version = "0.4.6" -dependencies = [ - "beefy-merkle-tree", - "derive_more", - "frame-support", - "hash256-std-hasher", - "hex-literal", - "log", - "parity-scale-codec", - "parity-util-mem", - "scale-info", - "serde", - "serde_json", - "sp-core", - "sp-io", - "sp-runtime", - "sp-runtime-interface", - "sp-std 4.0.0", - "sp-trie", - "test-case", - "thiserror-no-std", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", + "syn 1.0.109", ] [[package]] @@ -859,7 +992,7 @@ checksum = "4b6618553c32cd1c1f4fbdb9418cc035f3168422f24406ebb08576f6db5ed6ec" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -872,7 +1005,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.109", ] [[package]] @@ -890,16 +1023,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -912,9 +1045,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dusk-bls12_381" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fc81248ab76f1739dd4241ea2e7037a4d4cb0bd170443a7049e13b0e09acd6" +checksum = "81cded349291dd4620fd02065cc0fb9a1da7bea8cfe479e0dd067a4cd87225ea" dependencies = [ "byteorder", "dusk-bytes", @@ -978,14 +1111,14 @@ checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "dyn-clone" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] name = "ecdsa" @@ -1049,9 +1182,9 @@ dependencies = [ "base16ct", "crypto-bigint", "der", - "digest 0.10.6", + "digest 0.10.7", "ff", - "generic-array 0.14.6", + "generic-array 0.14.7", "group", "pkcs8", "rand_core 0.6.4", @@ -1066,6 +1199,12 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.2.8" @@ -1077,6 +1216,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1095,7 +1245,7 @@ checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ "aes", "ctr", - "digest 0.10.6", + "digest 0.10.7", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", @@ -1103,7 +1253,7 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.7", "sha3", "thiserror", "uuid", @@ -1163,13 +1313,13 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bytes", "chrono", "convert_case 0.6.0", "elliptic-curve", "ethabi", - "generic-array 0.14.6", + "generic-array 0.14.7", "hex", "k256", "open-fastrlp", @@ -1180,7 +1330,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn", + "syn 1.0.109", "thiserror", "tiny-keccak", "unicode-xid", @@ -1200,7 +1350,7 @@ dependencies = [ "ethers-core", "hex", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.7", "thiserror", ] @@ -1218,9 +1368,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -1255,9 +1405,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "frame-metadata" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" dependencies = [ "cfg-if", "parity-scale-codec", @@ -1268,9 +1418,9 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ - "bitflags", + "bitflags 1.3.2", "frame-metadata", "frame-support-procedural", "impl-trait-for-tuples", @@ -1291,7 +1441,7 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-state-machine", - "sp-std 5.0.0", + "sp-std", "sp-tracing", "sp-weights", "tt-call", @@ -1300,7 +1450,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "Inflector", "cfg-expr", @@ -1308,29 +1458,29 @@ dependencies = [ "itertools 0.10.5", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1341,9 +1491,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1356,9 +1506,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1366,15 +1516,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1384,38 +1534,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -1440,9 +1590,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1461,9 +1611,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -1484,9 +1634,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.1" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "group" @@ -1539,34 +1695,40 @@ dependencies = [ ] [[package]] -name = "heck" -version = "0.4.0" +name = "hashbrown" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "hashbrown" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-literal" @@ -1600,7 +1762,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -1610,32 +1772,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.6", + "generic-array 0.14.7", "hmac 0.8.1", ] [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1673,27 +1834,37 @@ checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "inout" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -1720,6 +1891,28 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.3", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.9.0" @@ -1740,21 +1933,15 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1768,65 +1955,66 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.6", + "sha2 0.10.7", "sha3", ] [[package]] name = "kate" -version = "0.7.1" +version = "0.8.0" dependencies = [ + "avail-core", "criterion", - "da-primitives", "derive_more", "dusk-bytes", "dusk-plonk", - "frame-support", - "getrandom 0.2.8", "hex", "hex-literal", - "itertools 0.10.5", "kate-recovery", "log", - "num_cpus", + "nalgebra", "once_cell", "parity-scale-codec", + "poly-multiproof", "proptest", "rand 0.8.5", "rand_chacha 0.3.1", - "rand_core 0.6.4", "rayon", "serde", "serde_json", + "sp-arithmetic", "sp-core", - "sp-std 4.0.0", "static_assertions", "test-case", + "thiserror-no-std", ] [[package]] name = "kate-recovery" -version = "0.8.1" +version = "0.9.0" dependencies = [ + "avail-core", + "derive_more", "dusk-bytes", "dusk-plonk", - "getrandom 0.2.8", "hex", - "num", "once_cell", "parity-scale-codec", "rand 0.8.5", "rand_chacha 0.3.1", "serde", + "sp-arithmetic", + "sp-std", + "static_assertions", "test-case", - "thiserror", + "thiserror-no-std", ] [[package]] name = "keccak" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" dependencies = [ "cpufeatures", ] @@ -1839,15 +2027,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libm" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "libsecp256k1" @@ -1898,25 +2086,28 @@ dependencies = [ ] [[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "linux-raw-sys" +version = "0.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" [[package]] name = "linux-raw-sys" -version = "0.0.46" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1924,12 +2115,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "lru" @@ -1955,7 +2143,17 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", ] [[package]] @@ -1975,9 +2173,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -2024,83 +2222,81 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] -name = "nohash-hasher" -version = "0.2.0" +name = "nalgebra" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" +dependencies = [ + "approx", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] [[package]] -name = "nom8" +name = "nohash-hasher" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nomad-base" -version = "0.1.3" +version = "0.1.4" dependencies = [ "ethers-signers", - "frame-support", "nomad-core", "nomad-signature", "once_cell", "parity-scale-codec", - "primitive-types", "scale-info", "serde", "sp-core", - "sp-io", - "sp-std 4.0.0", + "sp-runtime", ] [[package]] name = "nomad-core" -version = "0.1.3" +version = "0.1.4" dependencies = [ "async-trait", "ethers-core", "ethers-signers", - "frame-support", "nomad-signature", "parity-scale-codec", "primitive-types", "scale-info", "serde", "sp-core", - "sp-io", "sp-runtime", - "sp-std 4.0.0", + "sp-std", "tiny-keccak", ] [[package]] name = "nomad-merkle" -version = "0.1.1" +version = "0.1.2" dependencies = [ + "avail-core", "ethers-core", "frame-support", "hex-literal", "nomad-core", "parity-scale-codec", - "primitive-types", "scale-info", "serde", "serde_json", "sp-core", - "sp-io", - "sp-runtime", - "sp-std 4.0.0", "static_assertions", "thiserror-no-std", "tiny-keccak", @@ -2108,42 +2304,24 @@ dependencies = [ [[package]] name = "nomad-signature" -version = "0.1.1" +version = "0.1.2" dependencies = [ "byte-slice-cast", "elliptic-curve", "ethers-core", "frame-support", - "generic-array 0.14.6", + "generic-array 0.14.7", "hex", "k256", "parity-scale-codec", - "primitive-types", - "rlp", - "rlp-derive", "scale-info", "serde", "sp-core", - "sp-io", - "sp-std 4.0.0", + "sp-runtime", "thiserror-no-std", "tiny-keccak", ] -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -2170,8 +2348,8 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.2", - "itoa 1.0.5", + "arrayvec 0.7.4", + "itoa", ] [[package]] @@ -2184,17 +2362,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.1" @@ -2214,15 +2381,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -2234,24 +2402,24 @@ checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", "hashbrown 0.12.3", - "indexmap", + "indexmap 1.9.3", "memchr", ] [[package]] name = "object" -version = "0.30.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "oorandom" @@ -2277,7 +2445,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "auto_impl", "bytes", "ethereum-types", @@ -2293,16 +2461,16 @@ dependencies = [ "bytes", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "parity-scale-codec" -version = "3.3.0" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" +checksum = "756d439303e94fae44f288ba881ad29670c65b0c4b0e05674ca81061bb65f2c5" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bitvec 1.0.1", "byte-slice-cast", "bytes", @@ -2313,39 +2481,14 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.4" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +checksum = "9d884d78fcf214d70b1e239fcd1c6e5e95aa3be1881918da2e488cc946c7a476" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "parity-util-mem" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" -dependencies = [ - "cfg-if", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "parking_lot", - "primitive-types", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", + "syn 1.0.109", ] [[package]] @@ -2366,15 +2509,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.6" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-targets", ] [[package]] @@ -2390,9 +2533,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "pbkdf2" @@ -2409,17 +2552,17 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "hmac 0.12.1", "password-hash", - "sha2 0.10.6", + "sha2 0.10.7", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -2438,31 +2581,18 @@ dependencies = [ ] [[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", +name = "poly-multiproof" +version = "0.0.1" +source = "git+https://github.com/availproject/poly-multiproof?tag=v0.0.1#cd8d31b7eb568dea2fddfc9237e2e31ea7ae7ed3" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "blst", + "merlin 3.0.0", ] [[package]] @@ -2487,9 +2617,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", "toml_edit", @@ -2504,7 +2634,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -2521,31 +2651,31 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" +checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", - "quick-error 2.0.1", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax", + "regex-syntax 0.6.29", "rusty-fork", "tempfile", + "unarray", ] [[package]] @@ -2563,17 +2693,11 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - [[package]] name = "quote" -version = "1.0.23" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -2649,7 +2773,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.10", ] [[package]] @@ -2670,11 +2794,17 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -2682,9 +2812,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2694,42 +2824,43 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "ref-cast" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +checksum = "1641819477c319ef452a075ac34a4be92eb9ba09f6841f62d594d50fdcf0bf6b" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +checksum = "68bf53dad9b6086826722cdc99140793afd9f62faa14a1ad07eb4f955e7a7216" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.3.2", + "regex-syntax 0.7.4", ] [[package]] @@ -2738,23 +2869,31 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex-syntax" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "rfc6979" @@ -2773,7 +2912,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2794,14 +2933,14 @@ checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" @@ -2826,23 +2965,50 @@ dependencies = [ [[package]] name = "rustix" -version = "0.35.13" +version = "0.35.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +checksum = "6380889b07a03b5ecf1d44dc9ede6fd2145d84b502a2a9ca0b03c48e0cc3220f" dependencies = [ - "bitflags", - "errno", - "io-lifetimes", + "bitflags 1.3.2", + "errno 0.2.8", + "io-lifetimes 0.7.5", "libc", - "linux-raw-sys", + "linux-raw-sys 0.0.46", "windows-sys 0.42.0", ] +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno 0.3.1", + "io-lifetimes 1.0.11", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +dependencies = [ + "bitflags 2.3.3", + "errno 0.3.1", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys 0.48.0", +] + [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "rusty-fork" @@ -2851,16 +3017,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", - "quick-error 1.2.3", + "quick-error", "tempfile", "wait-timeout", ] [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + +[[package]] +name = "safe_arch" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "62a7484307bd40f8f7ccbacccac730108f2cae119a3b11c74485b48aa9ea650f" +dependencies = [ + "bytemuck", +] [[package]] name = "salsa20" @@ -2882,9 +3057,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.3.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ "bitvec 1.0.1", "cfg-if", @@ -2896,14 +3071,14 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.3.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2930,12 +3105,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" - [[package]] name = "scrypt" version = "0.10.0" @@ -2945,7 +3114,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "salsa20", - "sha2 0.10.6", + "sha2 0.10.7", ] [[package]] @@ -2956,7 +3125,7 @@ checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct", "der", - "generic-array 0.14.6", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -2991,47 +3160,37 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", ] [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" dependencies = [ - "itoa 1.0.5", + "itoa", "ryu", "serde", ] @@ -3063,22 +3222,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] name = "sha3" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -3097,29 +3256,42 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "hash-db", "log", @@ -3128,7 +3300,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-state-machine", - "sp-std 5.0.0", + "sp-std", "sp-trie", "sp-version", "thiserror", @@ -3137,46 +3309,46 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "blake2", "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "parity-scale-codec", "scale-info", "serde", "sp-core", "sp-io", - "sp-std 5.0.0", + "sp-std", ] [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "integer-sqrt", "num-traits", "parity-scale-codec", "scale-info", "serde", - "sp-std 5.0.0", + "sp-std", "static_assertions", ] [[package]] name = "sp-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "parity-scale-codec", "scale-info", @@ -3187,17 +3359,17 @@ dependencies = [ "sp-io", "sp-mmr-primitives", "sp-runtime", - "sp-std 5.0.0", + "sp-std", ] [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "array-bytes", "base58 0.2.0", - "bitflags", + "bitflags 1.3.2", "blake2", "dyn-clonable", "ed25519-zebra", @@ -3223,7 +3395,7 @@ dependencies = [ "sp-debug-derive", "sp-externalities", "sp-runtime-interface", - "sp-std 5.0.0", + "sp-std", "sp-storage", "ss58-registry", "substrate-bip39", @@ -3235,67 +3407,67 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "blake2", "byteorder", - "digest 0.10.6", - "sha2 0.10.6", + "digest 0.10.7", + "sha2 0.10.7", "sha3", - "sp-std 5.0.0", + "sp-std", "twox-hash", ] [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn", + "syn 1.0.109", ] [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "environmental", "parity-scale-codec", - "sp-std 5.0.0", + "sp-std", "sp-storage", ] [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "async-trait", "impl-trait-for-tuples", "parity-scale-codec", "sp-core", "sp-runtime", - "sp-std 5.0.0", + "sp-std", "thiserror", ] [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "bytes", "ed25519", @@ -3310,7 +3482,7 @@ dependencies = [ "sp-keystore", "sp-runtime-interface", "sp-state-machine", - "sp-std 5.0.0", + "sp-std", "sp-tracing", "sp-trie", "tracing", @@ -3320,7 +3492,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "async-trait", "futures", @@ -3336,7 +3508,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -3347,14 +3519,14 @@ dependencies = [ "sp-core", "sp-debug-derive", "sp-runtime", - "sp-std 5.0.0", + "sp-std", "thiserror", ] [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "backtrace", "lazy_static", @@ -3364,7 +3536,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "either", "hash256-std-hasher", @@ -3379,14 +3551,14 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-io", - "sp-std 5.0.0", + "sp-std", "sp-weights", ] [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -3394,7 +3566,7 @@ dependencies = [ "primitive-types", "sp-externalities", "sp-runtime-interface-proc-macro", - "sp-std 5.0.0", + "sp-std", "sp-storage", "sp-tracing", "sp-wasm-interface", @@ -3404,31 +3576,31 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "Inflector", "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", - "sp-std 5.0.0", + "sp-std", ] [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "hash-db", "log", @@ -3439,43 +3611,37 @@ dependencies = [ "sp-core", "sp-externalities", "sp-panic-handler", - "sp-std 5.0.0", + "sp-std", "sp-trie", "thiserror", "tracing", ] -[[package]] -name = "sp-std" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14804d6069ee7a388240b665f17908d98386ffb0b5d39f89a4099fc7a2a4c03f" - [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "impl-serde", "parity-scale-codec", "ref-cast", "serde", "sp-debug-derive", - "sp-std 5.0.0", + "sp-std", ] [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "parity-scale-codec", - "sp-std 5.0.0", + "sp-std", "tracing", "tracing-core", "tracing-subscriber", @@ -3484,7 +3650,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "ahash 0.7.6", "hash-db", @@ -3497,7 +3663,7 @@ dependencies = [ "parking_lot", "scale-info", "sp-core", - "sp-std 5.0.0", + "sp-std", "thiserror", "tracing", "trie-db", @@ -3507,7 +3673,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "impl-serde", "parity-scale-codec", @@ -3516,7 +3682,7 @@ dependencies = [ "serde", "sp-core-hashing-proc-macro", "sp-runtime", - "sp-std 5.0.0", + "sp-std", "sp-version-proc-macro", "thiserror", ] @@ -3524,23 +3690,23 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std 5.0.0", + "sp-std", "wasmi", "wasmtime", ] @@ -3548,7 +3714,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#946507ba9ef13e263534176b7b74e26fc56efbd4" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.37#6fa7fe1326ecaab9921c2c3888530ad679cfbb87" dependencies = [ "parity-scale-codec", "scale-info", @@ -3557,7 +3723,7 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-debug-derive", - "sp-std 5.0.0", + "sp-std", ] [[package]] @@ -3572,9 +3738,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.38.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b" +checksum = "bfc443bad666016e012538782d9e3006213a7db43e9fb1dda91657dc06a6fa08" dependencies = [ "Inflector", "num-format", @@ -3616,7 +3782,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.109", ] [[package]] @@ -3640,9 +3806,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -3650,15 +3816,14 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "syn" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", - "syn", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -3669,31 +3834,22 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac" [[package]] name = "tempfile" -version = "3.3.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", + "rustix 0.37.23", + "windows-sys 0.48.0", ] [[package]] @@ -3705,37 +3861,28 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", ] [[package]] @@ -3746,7 +3893,7 @@ checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3760,13 +3907,23 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "tiny-bip39" version = "1.0.0" @@ -3779,7 +3936,7 @@ dependencies = [ "pbkdf2 0.11.0", "rand 0.8.5", "rustc-hash", - "sha2 0.10.6", + "sha2 0.10.7", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -3816,25 +3973,25 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml_datetime" -version = "0.5.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.18.1" +version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" dependencies = [ - "indexmap", - "nom8", + "indexmap 2.0.0", "toml_datetime", + "winnow", ] [[package]] @@ -3851,20 +4008,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -3948,7 +4105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "digest 0.10.6", + "digest 0.10.7", "rand 0.8.5", "static_assertions", ] @@ -3971,11 +4128,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -3988,15 +4151,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" - -[[package]] -name = "unicode-width" -version = "0.1.10" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-xid" @@ -4010,7 +4167,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.10", "serde", ] @@ -4037,12 +4194,11 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -4060,9 +4216,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4070,24 +4226,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.25", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4095,22 +4251,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasmi" @@ -4151,7 +4307,7 @@ version = "0.89.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef" dependencies = [ - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -4163,7 +4319,7 @@ dependencies = [ "anyhow", "bincode", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "object 0.29.0", @@ -4197,7 +4353,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli 0.26.2", - "indexmap", + "indexmap 1.9.3", "log", "object 0.29.0", "serde", @@ -4222,7 +4378,7 @@ dependencies = [ "log", "object 0.29.0", "rustc-demangle", - "rustix", + "rustix 0.35.14", "serde", "target-lexicon", "thiserror", @@ -4249,14 +4405,14 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "mach", "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix", + "rustix 0.35.14", "thiserror", "wasmtime-asm-macros", "wasmtime-environ", @@ -4277,13 +4433,13 @@ dependencies = [ ] [[package]] -name = "web-sys" -version = "0.3.60" +name = "wide" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "40018623e2dba2602a9790faba8d33f2ebdebf4b86561b83928db735f8784728" dependencies = [ - "js-sys", - "wasm-bindgen", + "bytemuck", + "safe_arch", ] [[package]] @@ -4317,6 +4473,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.36.1" @@ -4336,20 +4501,50 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.1", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" @@ -4359,9 +4554,15 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" @@ -4371,9 +4572,15 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" @@ -4383,9 +4590,15 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" @@ -4395,15 +4608,27 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" @@ -4413,9 +4638,24 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +dependencies = [ + "memchr", +] [[package]] name = "wyz" @@ -4428,21 +4668,20 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", - "synstructure", + "syn 2.0.25", ] diff --git a/Cargo.toml b/Cargo.toml index 60c7e4df..78b33c31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,51 @@ [workspace] members = [ - "primitives/avail", + "core", + "kate/recovery", "kate", - "primitives/nomad/signature", - "primitives/nomad/nomad-core", - "primitives/nomad/nomad-base", - "primitives/nomad/merkle", + "nomad/signature", + "nomad/core", + "nomad/base", + "nomad/merkle", ] [patch.crates-io] # Substrate (polkadot-v0.9.37). sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-core-hashing = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-api = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-application-crypto = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-storage = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-debug-derive = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-arithmetic = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } sp-trie = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } sp-runtime-interface = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } sp-weights = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } frame-support = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-externalities = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-inherents = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-staking = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-state-machine = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-tracing = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-version = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +sp-wasm-interface = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } + +[profile.dev.package] +nalgebra = { opt-level = 3 } +blst = { opt-level = 3 } +dusk-bls12_381 = { opt-level = 3 } +dusk-plonk = { opt-level = 3 } +dusk-jubjub = { opt-level = 3 } +dusk-bytes = { opt-level = 3 } +rayon = { opt-level = 3 } +rayon-core = { opt-level = 3 } +poly-multiproof = { opt-level = 3 } +ark-bls12-381 = { opt-level = 3 } +ark-ec = { opt-level = 3 } +ark-ff = { opt-level = 3 } +ark-poly = { opt-level = 3 } +ark-serialize = { opt-level = 3 } +ark-std = { opt-level = 3 } +merlin = { opt-level = 3 } diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 00000000..30bec54b --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "avail-core" +version = "0.5.0" +authors = [] +edition = "2021" +license = "Apache-2.0" + +[dependencies] +# Others +derive_more = { version = "0.99.17", default-features = false, features = ["constructor", "from", "add", "deref", "mul", "into"] } +hash256-std-hasher = { version = "0.15.2", default-features = false } +hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] } +log = { version = "0.4.8", default-features = false } +serde = { version = "1", optional = true, features = ["derive"] } +static_assertions = "1.1.0" +thiserror-no-std = "2.0.2" + +# Substrate +beefy-merkle-tree = { git = "https://github.com/paritytech/substrate.git/", branch = "polkadot-v0.9.37", default-features = false, optional = true } +codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } +sp-arithmetic = { version = "*", default-features = false } +sp-core = { version = "*", default-features = false } +sp-io = { version = "*", default-features = false } +sp-std = { version = "*", default-features = false } +sp-trie = { version = "*", default-features = false } + +# Substrate Runtime +frame-support = { version = "4.0.0-dev", default-features = false, optional = true } +sp-runtime = { version = "7", default-features = false, optional = true } +sp-runtime-interface = { version = "7", default-features = false, optional = true } + +[dev-dependencies] +hex-literal = "0.3.4" +serde_json = "1" +test-case = "1.2.3" + +[features] +default = ["std"] +std = [ + "serde", + "hex", + "codec/std", + "scale-info/std", + "log/std", + "sp-core/std", + "sp-io/std", + "sp-std/std", + "sp-trie/std", + "sp-arithmetic/std", + "hash256-std-hasher/std", + "beefy-merkle-tree?/std", + "derive_more/display", + "sp-runtime-interface?/std", + "sp-runtime?/std", + "frame-support?/std", +] +runtime = [ + "sp-runtime-interface", + "sp-runtime", + "frame-support", + "beefy-merkle-tree", +] + +header-backward-compatibility-test = [] +try-runtime = [ + "runtime", + "sp-runtime/try-runtime", +] diff --git a/primitives/avail/src/asdr.rs b/core/src/app_extrinsic.rs similarity index 52% rename from primitives/avail/src/asdr.rs rename to core/src/app_extrinsic.rs index b029cb1a..76e8db2a 100644 --- a/primitives/avail/src/asdr.rs +++ b/core/src/app_extrinsic.rs @@ -1,74 +1,52 @@ -use codec::{Decode, Encode, MaxEncodedLen}; -use derive_more::{Add, Deref, Display, From, Into}; -use frame_support::RuntimeDebug; -#[cfg(feature = "std")] -use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; +use crate::traits::GetAppId; +use codec::{Decode, Encode}; +use derive_more::Constructor; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_runtime::{ - generic::UncheckedExtrinsic, - traits::{SignedExtension, Zero}, -}; +use sp_core::RuntimeDebug; use sp_std::vec::Vec; -mod data_lookup; -pub use data_lookup::*; - -mod get_app_id; -pub use get_app_id::*; - -mod app_unchecked_extrinsic; -pub use app_unchecked_extrinsic::*; +use crate::AppId; -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Add, - From, - Deref, - TypeInfo, - RuntimeDebug, - Encode, - Decode, - Display, - Into, - Default, - MaxEncodedLen, -)] +/// Raw Extrinsic with application id. +#[derive(Clone, TypeInfo, Default, Encode, Decode, RuntimeDebug, Constructor)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct AppId(#[codec(compact)] pub u32); - -#[cfg(feature = "std")] -impl MallocSizeOf for AppId { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.0.size_of(ops) - } +pub struct AppExtrinsic { + pub app_id: AppId, + #[cfg_attr(feature = "std", serde(with = "hex"))] + pub data: Vec, } -impl Zero for AppId { - fn zero() -> Self { - 0u32.into() - } +#[cfg(feature = "runtime")] +use crate::asdr::AppUncheckedExtrinsic; +#[cfg(feature = "runtime")] +use sp_runtime::{generic::UncheckedExtrinsic, traits::SignedExtension}; - fn is_zero(&self) -> bool { - self.0 == 0u32 - } +#[cfg(feature = "runtime")] +impl From> for AppExtrinsic +where + A: Encode, + C: Encode, + S: Encode, + E: SignedExtension + GetAppId, +{ + fn from(ue: sp_runtime::generic::UncheckedExtrinsic) -> Self { + let app_id = ue + .signature + .as_ref() + .map(|(_, _, extra)| extra.app_id()) + .unwrap_or_default(); + let data = ue.encode(); - fn set_zero(&mut self) { - self.0 = 0u32; + Self { app_id, data } } } -/// Raw Extrinsic with application id. -#[derive(Clone, TypeInfo, RuntimeDebug, Default, Encode, Decode)] -pub struct AppExtrinsic { - pub app_id: AppId, - pub data: Vec, +impl GetAppId for AppExtrinsic { + fn app_id(&self) -> AppId { + self.app_id + } } impl From> for AppExtrinsic { @@ -81,18 +59,7 @@ impl From> for AppExtrinsic { } } -impl From> for AppExtrinsic -where - E: SignedExtension + GetAppId, -{ - fn from(app_ext: AppUncheckedExtrinsic) -> Self { - Self { - app_id: app_ext.app_id(), - data: app_ext.encode(), - } - } -} - +#[cfg(feature = "runtime")] impl From<&AppUncheckedExtrinsic> for AppExtrinsic where A: Encode, @@ -108,27 +75,18 @@ where } } -impl From> for AppExtrinsic +#[cfg(feature = "runtime")] +impl From> for AppExtrinsic where A: Encode, C: Encode, S: Encode, E: SignedExtension + GetAppId, { - fn from(ue: UncheckedExtrinsic) -> Self { - let app_id = ue - .signature - .as_ref() - .map(|(_, _, extra)| extra.app_id()) - .unwrap_or_default(); - let data = ue.encode(); - - Self { app_id, data } - } -} - -impl GetAppId for AppExtrinsic { - fn app_id(&self) -> AppId { - self.app_id + fn from(app_ext: AppUncheckedExtrinsic) -> Self { + Self { + app_id: app_ext.app_id(), + data: app_ext.encode(), + } } } diff --git a/primitives/avail/src/asdr/app_unchecked_extrinsic.rs b/core/src/asdr.rs similarity index 95% rename from primitives/avail/src/asdr/app_unchecked_extrinsic.rs rename to core/src/asdr.rs index 441db16e..9f9e2bab 100644 --- a/primitives/avail/src/asdr/app_unchecked_extrinsic.rs +++ b/core/src/asdr.rs @@ -18,12 +18,8 @@ //! Generic implementation of an unchecked (pre-verification) extrinsic. use codec::{Compact, Decode, Encode, EncodeLike, Error, Input}; -use frame_support::{ - dispatch::{DispatchInfo, GetDispatchInfo}, - traits::ExtrinsicCall, -}; use scale_info::{build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, TypeParameter}; -use sp_io::hashing::blake2_256; +#[cfg(feature = "runtime")] use sp_runtime::{ generic::CheckedExtrinsic, traits::{ @@ -39,10 +35,9 @@ use sp_std::{ vec::Vec, }; -use crate::{ - asdr::{AppId, GetAppId}, - OpaqueExtrinsic, -}; +use sp_io::hashing::blake2_256; + +use crate::{traits::GetAppId, AppId, OpaqueExtrinsic}; /// Current version of the [`UncheckedExtrinsic`] encoded format. /// @@ -243,6 +238,10 @@ where type SignedExtensions = Extra; } +#[cfg(feature = "runtime")] +use frame_support::dispatch::{DispatchInfo, GetDispatchInfo}; + +#[cfg(feature = "runtime")] impl GetDispatchInfo for AppUncheckedExtrinsic where @@ -385,7 +384,11 @@ where let compact_len = codec::Compact::(tmp.len() as u32); // Allocate the output buffer with the correct length - let mut output = Vec::with_capacity(compact_len.size_hint() + tmp.len()); + let output_len = compact_len + .size_hint() + .checked_add(tmp.len()) + .expect("Cannot encode this `AppUncheckedExtrinsic` into memory"); + let mut output = Vec::with_capacity(output_len); compact_len.encode_to(&mut output); output.extend(tmp); @@ -461,7 +464,8 @@ where } } -impl ExtrinsicCall +#[cfg(feature = "runtime")] +impl frame_support::traits::ExtrinsicCall for AppUncheckedExtrinsic where Extra: SignedExtension, @@ -486,6 +490,21 @@ where } } +impl TryFrom + for AppUncheckedExtrinsic +where + Address: Decode, + Signature: Decode, + Call: Decode, + Extra: SignedExtension, +{ + type Error = codec::Error; + + fn try_from(opaque: OpaqueExtrinsic) -> Result { + Self::try_from(opaque.0.as_slice()) + } +} + impl TryFrom<&[u8]> for AppUncheckedExtrinsic where @@ -519,7 +538,6 @@ where #[cfg(test)] mod tests { - use sp_core::blake2_256; use sp_runtime::{ codec::{Decode, Encode}, testing::TestSignature as TestSig, diff --git a/core/src/bench_randomness.rs b/core/src/bench_randomness.rs new file mode 100644 index 00000000..2b308abf --- /dev/null +++ b/core/src/bench_randomness.rs @@ -0,0 +1,20 @@ +use frame_support::traits::Randomness; + +/// Provides an implementation of [`frame_support::traits::Randomness`] that should only be used in +/// on Benchmarks! +pub struct BenchRandomness(sp_std::marker::PhantomData); + +impl Randomness for BenchRandomness +where + Output: codec::Decode + Default, + T: Default, +{ + fn random(subject: &[u8]) -> (Output, T) { + use sp_runtime::traits::TrailingZeroInput; + + ( + Output::decode(&mut TrailingZeroInput::new(subject)).unwrap_or_default(), + T::default(), + ) + } +} diff --git a/core/src/constants.rs b/core/src/constants.rs new file mode 100644 index 00000000..c31cad26 --- /dev/null +++ b/core/src/constants.rs @@ -0,0 +1,31 @@ +use core::num::NonZeroU32; +use sp_arithmetic::Perbill; +use static_assertions::const_assert; + +pub mod well_known_keys { + /// Public params used to generate Kate commitment + pub const KATE_PUBLIC_PARAMS: &[u8] = b":kate_public_params:"; +} + +/// We allow `Normal` extrinsics to fill up the block up to 90%, the rest can be used +/// by Operational extrinsics. +pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(90); + +const_assert!(BLOCK_CHUNK_SIZE.get() > 0); +pub const BLOCK_CHUNK_SIZE: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(32) }; + +/// Money matters. +pub mod currency { + + pub type Balance = u128; + + /// AVL has 18 decimal positions. + pub const AVL: Balance = 1_000_000_000_000_000_000; + + /// Cents of AVL has 16 decimal positions (100 Cents = $1) + /// 1 DOLLARS = 10_000_000_000_000_000 + pub const CENTS: Balance = AVL / 100; + + /// Millicent of AVL has 13 decimal positions( 100 mCents = 1 cent). + pub const MILLICENTS: Balance = CENTS / 1_000; +} diff --git a/core/src/data_lookup/compact.rs b/core/src/data_lookup/compact.rs new file mode 100644 index 00000000..5da2db89 --- /dev/null +++ b/core/src/data_lookup/compact.rs @@ -0,0 +1,59 @@ +use crate::{AppId, DataLookup}; + +use codec::{Decode, Encode}; +use derive_more::Constructor; +use scale_info::TypeInfo; +use sp_std::vec::Vec; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Encode, Decode, TypeInfo, Constructor, Debug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct DataLookupItem { + pub app_id: AppId, + #[codec(compact)] + pub start: u32, +} + +impl From<(A, S)> for DataLookupItem +where + u32: From, + u32: From, +{ + fn from(value: (A, S)) -> Self { + Self { + app_id: AppId(value.0.into()), + start: value.1.into(), + } + } +} + +#[derive(Encode, Decode, TypeInfo, Constructor, Debug, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct CompactDataLookup { + /// size of the look up + #[codec(compact)] + pub(crate) size: u32, + /// sorted vector of tuples(key, start index) + pub(crate) index: Vec, +} + +impl CompactDataLookup { + pub fn from_expanded(lookup: &DataLookup) -> Self { + let index = lookup + .index + .iter() + .filter(|(id, _)| *id != AppId(0)) + .map(|(id, range)| DataLookupItem::new(*id, range.start)) + .collect(); + let size = lookup.index.last().map(|(_, range)| range.end).unwrap_or(0); + Self { size, index } + } +} + +impl From for CompactDataLookup { + fn from(lookup: DataLookup) -> Self { + CompactDataLookup::from_expanded(&lookup) + } +} diff --git a/core/src/data_lookup/mod.rs b/core/src/data_lookup/mod.rs new file mode 100644 index 00000000..d6eb6572 --- /dev/null +++ b/core/src/data_lookup/mod.rs @@ -0,0 +1,234 @@ +use codec::{Decode, Encode, Input}; +use core::convert::TryFrom; +use scale_info::{Type, TypeInfo}; +use sp_core::RuntimeDebug; +use sp_std::{ops::Range, vec::Vec}; +use thiserror_no_std::Error; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +use crate::{ensure, AppId}; + +pub mod compact; +use compact::CompactDataLookup; + +pub type DataLookupRange = Range; + +#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + #[error("Input data is not sorted by AppId")] + DataNotSorted, + #[error("Data is empty on AppId {0}")] + DataEmptyOn(AppId), + #[error("Offset overflows")] + OffsetOverflows, +} + +#[derive(PartialEq, Eq, Clone, Default, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "std", + serde(try_from = "CompactDataLookup", into = "CompactDataLookup") +)] +pub struct DataLookup { + pub(crate) index: Vec<(AppId, DataLookupRange)>, +} + +impl DataLookup { + pub fn len(&self) -> u32 { + self.index.last().map(|(_id, range)| range.end).unwrap_or(0) + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn range_of(&self, app_id: AppId) -> Option { + self.index + .iter() + .find(|(id, _)| *id == app_id) + .map(|(_, range)| range) + .cloned() + } + + pub fn projected_range_of(&self, app_id: AppId, chunk_size: u32) -> Option { + self.range_of(app_id).and_then(|range| { + let start = range.start.checked_mul(chunk_size)?; + let end = range.end.checked_mul(chunk_size)?; + Some(start..end) + }) + } + + pub fn projected_ranges(&self, chunk_size: u32) -> Result)>, Error> { + self.index + .iter() + .map(|(id, range)| { + let start = range + .start + .checked_mul(chunk_size) + .ok_or(Error::OffsetOverflows)?; + let end = range + .end + .checked_mul(chunk_size) + .ok_or(Error::OffsetOverflows)?; + Ok((*id, start..end)) + }) + .collect() + } +} + +impl DataLookup { + pub fn from_id_and_len_iter(iter: I) -> Result + where + I: Iterator, + u32: From, + u32: TryFrom, + { + let mut offset: u32 = 0; + let mut maybe_prev_id = None; + + let index = iter + .map(|(id, len)| { + // Check sorted by AppId + let id = AppId(id.into()); + if let Some(prev_id) = maybe_prev_id.replace(id) { + ensure!(prev_id < id, Error::DataNotSorted); + } + + // Check non-empty data per AppId + let len = u32::try_from(len).map_err(|_| Error::OffsetOverflows)?; + ensure!(len > 0, Error::DataEmptyOn(id)); + + // Create range and update `offset`. + let end = offset.checked_add(len).ok_or(Error::OffsetOverflows)?; + let range = offset..end; + offset = end; + + Ok((id, range)) + }) + .collect::>()?; + + Ok(Self { index }) + } +} + +impl TryFrom for DataLookup { + type Error = Error; + + fn try_from(compacted: CompactDataLookup) -> Result { + let mut offset = 0; + let mut prev_id = AppId(0); + let mut index = Vec::with_capacity( + compacted + .index + .len() + .checked_add(1) + .ok_or(Error::OffsetOverflows)?, + ); + + for c_item in compacted.index.into_iter() { + index.push((prev_id, offset..c_item.start)); + prev_id = c_item.app_id; + offset = c_item.start; + } + + let last_range = offset..compacted.size; + if !last_range.is_empty() { + index.push((prev_id, offset..compacted.size)); + } + + let lookup = DataLookup { index }; + ensure!(lookup.len() == compacted.size, Error::DataNotSorted); + + Ok(lookup) + } +} + +// Encoding +// ================================== + +impl Encode for DataLookup { + /// Encodes as a `compact::DataLookup`. + fn encode(&self) -> Vec { + let compacted = CompactDataLookup::from_expanded(self); + compacted.encode() + } +} + +impl Decode for DataLookup { + /// Decodes from a `compact::DataLookup`. + fn decode(input: &mut I) -> Result { + let compacted = CompactDataLookup::decode(input)?; + DataLookup::try_from(compacted).map_err(|_| codec::Error::from("Invalid `DataLookup`")) + } +} + +impl TypeInfo for DataLookup { + type Identity = Self; + + fn type_info() -> Type { + CompactDataLookup::type_info() + } +} + +#[cfg(test)] +mod test { + use super::*; + use test_case::test_case; + + #[test_case( vec![(0, 15), (1, 20), (2, 150)] => Ok(vec![(0,0..15),(1, 15..35), (2, 35..185)]); "Valid case")] + #[test_case( vec![(0, usize::MAX)] => Err(Error::OffsetOverflows); "Offset overflows at zero")] + #[test_case( vec![(0, (u32::MAX -1) as usize), (1, 2)] => Err(Error::OffsetOverflows); "Offset overflows at non zero")] + #[test_case( vec![(1, 10), (0, 2)] => Err(Error::DataNotSorted); "Unsortend data")] + #[test_case( vec![] => Ok(vec![]); "Empty data")] + fn from_id_and_len( + id_len_data: Vec<(u32, usize)>, + ) -> Result, Error> { + let iter = id_len_data.into_iter().map(|(id, len)| (AppId(id), len)); + + DataLookup::from_id_and_len_iter(iter).map(|lookup| { + lookup + .index + .iter() + .map(|(id, range)| (id.0, range.clone())) + .collect::>() + }) + } + + #[test_case( vec![(0, 15), (1, 20), (2, 150)] => CompactDataLookup::new(185, vec![(1u32, 15u32).into(),(2u32,35u32).into()]).encode(); "Valid case")] + #[test_case( vec![(0, 100)] => CompactDataLookup::new(100, vec![]).encode(); "Only Zero AppId")] + #[test_case( vec![] => CompactDataLookup::new(0, vec![]).encode(); "Empty")] + + fn check_compressed_encode(id_lens: Vec<(u32, usize)>) -> Vec { + let lookup = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); + lookup.encode() + } + + #[test_case( vec![(0, 15), (1, 20), (2, 150)] ; "Valid case")] + #[test_case( vec![(0, 15)] ; "Only Zero AppId")] + #[test_case( vec![] ; "Empty")] + fn compressed_conversions(id_lens: Vec<(u32, usize)>) { + let lookup = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); + + let compact_lookup = CompactDataLookup::from_expanded(&lookup); + let expanded_lookup = DataLookup::try_from(compact_lookup.clone()).unwrap(); + + assert_eq!( + lookup, expanded_lookup, + "Lookup: {lookup:?} -> Compacted: {compact_lookup:?} -> Expanded: {expanded_lookup:?}" + ); + } + + #[test_case( vec![(0, 15), (1, 20), (2, 150)] ; "Valid case")] + #[test_case( vec![(0, 15)] ; "Only Zero AppId")] + #[test_case( vec![] ; "Empty")] + fn serialization_compatibility(id_lens: Vec<(u32, usize)>) { + let lookup = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); + let lookup_json = serde_json::to_string(&lookup).unwrap(); + let compressed_from_json = serde_json::from_str::(&lookup_json).unwrap(); + let expanded_lookup = DataLookup::try_from(compressed_from_json.clone()).unwrap(); + + assert_eq!(lookup, expanded_lookup); + } +} diff --git a/primitives/avail/src/data_proof.rs b/core/src/data_proof.rs similarity index 92% rename from primitives/avail/src/data_proof.rs rename to core/src/data_proof.rs index 93dee31c..a59682b4 100644 --- a/primitives/avail/src/data_proof.rs +++ b/core/src/data_proof.rs @@ -1,10 +1,10 @@ +#[cfg(feature = "runtime")] use beefy_merkle_tree::MerkleProof; use codec::{Decode, Encode}; -use frame_support::ensure; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::H256; -use sp_std::{convert::TryFrom, vec::Vec}; +use sp_std::vec::Vec; use thiserror_no_std::Error; /// Wrapper of `beefy-merkle-tree::MerkleProof` with codec support. #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, Default)] @@ -53,7 +53,8 @@ pub enum DataProofTryFromError { InvalidLeafIndex, } -impl TryFrom<&MerkleProof> for DataProof +#[cfg(feature = "runtime")] +impl core::convert::TryFrom<&MerkleProof> for DataProof where T: AsRef<[u8]>, H: PartialEq + Eq + AsRef<[u8]>, @@ -61,12 +62,15 @@ where type Error = DataProofTryFromError; fn try_from(merkle_proof: &MerkleProof) -> Result { + use crate::ensure; use DataProofTryFromError::*; + use sp_io::hashing::keccak_256; + let root = <[u8; 32]>::try_from(merkle_proof.root.as_ref()) .map_err(|_| InvalidRoot)? .into(); - let leaf = sp_io::hashing::keccak_256(merkle_proof.leaf.as_ref()).into(); + let leaf = keccak_256(merkle_proof.leaf.as_ref()).into(); let proof = merkle_proof .proof @@ -95,11 +99,12 @@ where } } -#[cfg(test)] +#[cfg(all(test, feature = "runtime"))] mod test { use crate::Keccak256; use hex_literal::hex; use sp_core::H512; + use sp_io::hashing::keccak_256; use sp_std::cmp::min; use test_case::test_case; @@ -146,7 +151,7 @@ mod test { ], number_of_leaves: 7, leaf_index: 1, - leaf: sp_io::hashing::keccak_256(H512::repeat_byte(1).as_bytes()).into(), + leaf: keccak_256(H512::repeat_byte(1).as_bytes()).into(), }) } @@ -160,7 +165,7 @@ mod test { ], number_of_leaves: 7, leaf_index: 0, - leaf: sp_io::hashing::keccak_256(H512::repeat_byte(0).as_bytes()).into(), + leaf: keccak_256(H512::repeat_byte(0).as_bytes()).into(), }) } @@ -173,7 +178,7 @@ mod test { ], number_of_leaves: 7, leaf_index: 6, - leaf: sp_io::hashing::keccak_256(H512::repeat_byte(6).as_bytes()).into(), + leaf: keccak_256(H512::repeat_byte(6).as_bytes()).into(), }) } diff --git a/primitives/avail/src/header/extension/mod.rs b/core/src/header/extension/mod.rs similarity index 88% rename from primitives/avail/src/header/extension/mod.rs rename to core/src/header/extension/mod.rs index ad5fd923..d6fb76a8 100644 --- a/primitives/avail/src/header/extension/mod.rs +++ b/core/src/header/extension/mod.rs @@ -1,13 +1,13 @@ -use crate::asdr::DataLookup; use codec::{Decode, Encode}; -#[cfg(feature = "std")] -use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::{RuntimeDebug, H256}; +#[cfg(feature = "runtime")] use sp_runtime_interface::pass_by::PassByCodec; +use crate::DataLookup; + pub mod v1; pub mod v2; @@ -15,8 +15,9 @@ pub mod v2; pub mod v_test; /// Header extension data. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo, Encode, Decode, PassByCodec)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo, Encode, Decode)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "runtime", derive(PassByCodec))] pub enum HeaderExtension { V1(v1::HeaderExtension), V2(v2::HeaderExtension), @@ -70,13 +71,6 @@ impl Default for HeaderExtension { } } -#[cfg(feature = "std")] -impl MallocSizeOf for HeaderExtension { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - forward_to_version!(self, size_of, ops) - } -} - impl From for HeaderExtension { #[inline] fn from(ext: v1::HeaderExtension) -> Self { diff --git a/primitives/avail/src/header/extension/v1.rs b/core/src/header/extension/v1.rs similarity index 67% rename from primitives/avail/src/header/extension/v1.rs rename to core/src/header/extension/v1.rs index f0f9b1ed..251b8b64 100644 --- a/primitives/avail/src/header/extension/v1.rs +++ b/core/src/header/extension/v1.rs @@ -1,12 +1,10 @@ use codec::{Decode, Encode}; -#[cfg(feature = "std")] -use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::{RuntimeDebug, H256}; -use crate::{asdr::DataLookup, v1::KateCommitment}; +use crate::{v1::KateCommitment, DataLookup}; #[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -32,10 +30,3 @@ impl HeaderExtension { self.commitment.cols } } - -#[cfg(feature = "std")] -impl MallocSizeOf for HeaderExtension { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.commitment.size_of(ops) + self.app_lookup.size_of(ops) - } -} diff --git a/primitives/avail/src/header/extension/v2.rs b/core/src/header/extension/v2.rs similarity index 68% rename from primitives/avail/src/header/extension/v2.rs rename to core/src/header/extension/v2.rs index f7a6855a..ff9984d5 100644 --- a/primitives/avail/src/header/extension/v2.rs +++ b/core/src/header/extension/v2.rs @@ -1,12 +1,10 @@ use codec::{Decode, Encode}; -#[cfg(feature = "std")] -use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::{RuntimeDebug, H256}; -use crate::{asdr::DataLookup, v2::KateCommitment}; +use crate::{v2::KateCommitment, DataLookup}; #[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -32,10 +30,3 @@ impl HeaderExtension { self.commitment.cols } } - -#[cfg(feature = "std")] -impl MallocSizeOf for HeaderExtension { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.commitment.size_of(ops) + self.app_lookup.size_of(ops) - } -} diff --git a/primitives/avail/src/header/extension/v_test.rs b/core/src/header/extension/v_test.rs similarity index 73% rename from primitives/avail/src/header/extension/v_test.rs rename to core/src/header/extension/v_test.rs index 23d989d6..a7e8b4bf 100644 --- a/primitives/avail/src/header/extension/v_test.rs +++ b/core/src/header/extension/v_test.rs @@ -1,6 +1,4 @@ use codec::{Decode, Encode}; -#[cfg(feature = "std")] -use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -23,13 +21,6 @@ impl HeaderExtension { } } -#[cfg(feature = "std")] -impl MallocSizeOf for HeaderExtension { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.new_field.size_of(ops) + self.commitment.size_of(ops) + self.app_lookup.size_of(ops) - } -} - impl From for HeaderExtension { fn from(ext: v1::HeaderExtension) -> Self { Self { diff --git a/primitives/avail/src/header/mod.rs b/core/src/header/mod.rs similarity index 95% rename from primitives/avail/src/header/mod.rs rename to core/src/header/mod.rs index 9f4682b5..6798deb4 100644 --- a/primitives/avail/src/header/mod.rs +++ b/core/src/header/mod.rs @@ -30,8 +30,7 @@ use sp_runtime::{ Digest, }; use sp_runtime_interface::pass_by::{Codec as PassByCodecImpl, PassBy}; -use sp_std::fmt; -use sp_std::{convert::TryFrom, fmt::Debug}; +use sp_std::{convert::TryFrom, fmt}; use crate::traits::{ExtendedHeader, HeaderBlockNumber, HeaderHash}; @@ -159,7 +158,7 @@ impl HeaderT for Header where Number: Member + MaybeSerializeDeserialize - + Debug + + fmt::Debug + sp_std::hash::Hash + MaybeDisplay + AtLeast32BitUnsigned @@ -175,7 +174,7 @@ where + Member + Ord + MaybeSerialize - + Debug + + fmt::Debug + MaybeDisplay + SimpleBitOps + Codec, @@ -244,16 +243,15 @@ where } } -impl ExtendedHeader for Header { - type Hash = ::Output; - type Number = N; - +impl + ExtendedHeader::Output, Digest, HeaderExtension> for Header +{ /// Creates new header. fn new( - n: Self::Number, - extrinsics: Self::Hash, - state: Self::Hash, - parent: Self::Hash, + n: N, + extrinsics: ::Output, + state: ::Output, + parent: ::Output, digest: Digest, extension: HeaderExtension, ) -> Self { @@ -269,7 +267,7 @@ impl ExtendedHeader for Header { } } -#[cfg(test)] +#[cfg(all(test, feature = "runtime"))] mod tests { use codec::Error; use hex_literal::hex; @@ -282,8 +280,8 @@ mod tests { use super::*; use crate::{ - asdr::DataLookup, kate_commitment::{v1, v2}, + AppId, DataLookup, }; type THeader = Header; @@ -453,10 +451,8 @@ mod tests { }; let extension = extension::v1::HeaderExtension { commitment, - app_lookup: DataLookup { - size: 1, - index: vec![], - }, + app_lookup: DataLookup::from_id_and_len_iter([(AppId(0), 1)].into_iter()) + .expect("Valid DataLookup .qed"), }; let digest = Digest { logs: vec![ @@ -564,19 +560,6 @@ mod tests { (header, hash) } - fn corrupted_app_lookup(header_and_hash: (THeader, H256)) -> (THeader, H256) { - let (mut header, hash) = header_and_hash; - - match header.extension { - extension::HeaderExtension::V1(ref mut ext) => ext.app_lookup.size += 1, - extension::HeaderExtension::V2(ref mut ext) => ext.app_lookup.size += 1, - #[cfg(feature = "header-backward-compatibility-test")] - _ => unreachable!(), - }; - - (header, hash) - } - fn corrupted_number(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { header_and_hash.0.number += 1; header_and_hash @@ -596,7 +579,6 @@ mod tests { #[test_case( corrupted_kate_data_root(header()) => false; "Corrupted data root in kate")] #[test_case( corrupted_kate_cols(header()) => false; "Corrupted cols in kate")] #[test_case( corrupted_kate_rows(header()) => false; "Corrupted rows in kate")] - #[test_case( corrupted_app_lookup(header()) => false )] #[test_case( corrupted_number(header()) => false )] #[test_case( corrupted_state_root(header()) => false )] #[test_case( corrupted_parent(header()) => false )] diff --git a/primitives/avail/src/kate_commitment.rs b/core/src/kate_commitment.rs similarity index 82% rename from primitives/avail/src/kate_commitment.rs rename to core/src/kate_commitment.rs index 14d11a5c..d2c2710b 100644 --- a/primitives/avail/src/kate_commitment.rs +++ b/core/src/kate_commitment.rs @@ -1,11 +1,14 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; +use sp_core::H256; +use sp_std::vec::Vec; + #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_core::{hexdisplay::HexDisplay, H256}; +#[cfg(feature = "std")] +use sp_core::hexdisplay::HexDisplay; #[cfg(feature = "std")] use sp_std::fmt; -use sp_std::vec::Vec; pub mod v1 { use super::*; @@ -39,16 +42,6 @@ pub mod v1 { .finish() } } - - #[cfg(feature = "std")] - impl parity_util_mem::MallocSizeOf for KateCommitment { - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - self.commitment.size_of(ops) - + self.rows.size_of(ops) - + self.cols.size_of(ops) - + self.data_root.size_of(ops) - } - } } pub mod v2 { @@ -103,16 +96,6 @@ pub mod v2 { } } - #[cfg(feature = "std")] - impl parity_util_mem::MallocSizeOf for KateCommitment { - fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize { - self.commitment.size_of(ops) - + self.rows.size_of(ops) - + self.cols.size_of(ops) - + self.data_root.size_of(ops) - } - } - #[cfg(test)] mod tests { use super::*; diff --git a/core/src/keccak256.rs b/core/src/keccak256.rs new file mode 100644 index 00000000..5df84883 --- /dev/null +++ b/core/src/keccak256.rs @@ -0,0 +1,50 @@ +use scale_info::TypeInfo; +use sp_core::{Hasher, RuntimeDebug}; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +/// Keccak 256 wrapper which supports `beefy-merkle-tree::Hasher`. +#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Keccak256 {} + +impl Hasher for Keccak256 { + type Out = sp_core::H256; + type StdHasher = hash256_std_hasher::Hash256StdHasher; + const LENGTH: usize = 32; + + fn hash(s: &[u8]) -> Self::Out { + let keccak_out = sp_io::hashing::keccak_256(s); + keccak_out.into() + } +} + +#[cfg(feature = "runtime")] +pub mod hash { + use super::*; + use sp_core::storage::StateVersion; + use sp_std::vec::Vec; + use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration as _}; + + impl sp_runtime::traits::Hash for Keccak256 { + type Output = sp_core::H256; + + fn trie_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> Self::Output { + match version { + StateVersion::V0 => LayoutV0::::trie_root(input), + StateVersion::V1 => LayoutV1::::trie_root(input), + } + } + + fn ordered_trie_root(input: Vec>, version: StateVersion) -> Self::Output { + match version { + StateVersion::V0 => LayoutV0::::ordered_trie_root(input), + StateVersion::V1 => LayoutV1::::ordered_trie_root(input), + } + } + } +} + +#[cfg(feature = "runtime")] +pub use hash::*; diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 00000000..1f15a60b --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,157 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(clippy::integer_arithmetic)] + +use codec::{Decode, Encode, MaxEncodedLen}; +use derive_more::{Add, Constructor, Deref, Display, Into, Mul}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_arithmetic::traits::Zero; +use sp_core::RuntimeDebug; + +pub mod opaque_extrinsic; +pub use opaque_extrinsic::*; + +/// Customized headers. +#[cfg(feature = "runtime")] +pub mod header; + +/// Kate Commitment on Headers. +pub mod kate_commitment; +pub use kate_commitment::*; + +/// Application Specific Data Retrieval +#[cfg(feature = "runtime")] +pub mod asdr; + +pub mod sha2; +pub use sha2::ShaTwo256; + +pub mod traits; + +pub mod keccak256; +pub use keccak256::Keccak256; + +pub mod data_proof; +pub use data_proof::DataProof; + +pub mod data_lookup; +pub use data_lookup::*; + +pub mod app_extrinsic; +pub use app_extrinsic::*; + +pub mod constants; +pub use constants::*; + +#[cfg(feature = "runtime")] +pub mod bench_randomness; + +#[repr(u8)] +pub enum InvalidTransactionCustomId { + /// The AppId is not registered. + InvalidAppId = 137, + /// Extrinsic is not allowed for the given `AppId`. + ForbiddenAppId, + /// Max padded length was exceeded. + MaxPaddedLenExceeded, + /// Max recursion was reached for a call with AppId != 0. + MaxRecursionExceeded, +} + +#[derive( + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Add, + Deref, + TypeInfo, + Encode, + Decode, + Default, + Into, + MaxEncodedLen, + RuntimeDebug, + Display, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct AppId(#[codec(compact)] pub u32); + +impl Zero for AppId { + fn zero() -> Self { + AppId(Zero::zero()) + } + + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +/// Strong type for `BlockLength::cols` +#[derive( + Clone, + Copy, + Add, + Mul, + PartialEq, + Eq, + Encode, + Decode, + TypeInfo, + PartialOrd, + Ord, + Into, + Constructor, + MaxEncodedLen, + Display, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[mul(forward)] +pub struct BlockLengthColumns(#[codec(compact)] pub u32); + +/// Strong type for `BlockLength::rows` +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive( + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + Clone, + Copy, + Add, + Mul, + PartialEq, + Eq, + PartialOrd, + Ord, + Into, + Constructor, + Display, +)] +#[mul(forward)] +pub struct BlockLengthRows(#[codec(compact)] pub u32); + +/// Return Err of the expression: `return Err($expression);`. +/// +/// Used as `fail!(expression)`. +#[macro_export] +macro_rules! fail { + ( $y:expr ) => {{ + return Err($y.into()); + }}; +} + +/// Evaluate `$x:expr` and if not true return `Err($y:expr)`. +/// +/// Used as `ensure!(expression_to_ensure, expression_to_return_on_false)`. +#[macro_export] +macro_rules! ensure { + ( $x:expr, $y:expr $(,)? ) => {{ + if !$x { + $crate::fail!($y); + } + }}; +} diff --git a/primitives/avail/src/opaque_extrinsic.rs b/core/src/opaque_extrinsic.rs similarity index 95% rename from primitives/avail/src/opaque_extrinsic.rs rename to core/src/opaque_extrinsic.rs index 926b3c6f..7d14e459 100644 --- a/primitives/avail/src/opaque_extrinsic.rs +++ b/core/src/opaque_extrinsic.rs @@ -1,6 +1,5 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime::traits::Extrinsic; use sp_std::vec::Vec; /// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized @@ -51,7 +50,8 @@ impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic { } } -impl Extrinsic for OpaqueExtrinsic { +#[cfg(feature = "runtime")] +impl sp_runtime::traits::Extrinsic for OpaqueExtrinsic { type Call = (); type SignaturePayload = (); } diff --git a/core/src/sha2.rs b/core/src/sha2.rs new file mode 100644 index 00000000..f22519e3 --- /dev/null +++ b/core/src/sha2.rs @@ -0,0 +1,49 @@ +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_core::{Hasher, RuntimeDebug}; + +/// Sha2 256 wrapper which supports `beefy-merkle-tree::Hasher`. +#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ShaTwo256 {} + +impl Hasher for ShaTwo256 { + type Out = sp_core::H256; + type StdHasher = hash256_std_hasher::Hash256StdHasher; + const LENGTH: usize = 32; + + fn hash(s: &[u8]) -> Self::Out { + let sha2_out = sp_io::hashing::sha2_256(s); + sha2_out.into() + } +} + +#[cfg(feature = "runtime")] +pub mod hash { + use super::*; + use sp_core::storage::StateVersion; + use sp_std::vec::Vec; + use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration as _}; + + impl sp_runtime::traits::Hash for ShaTwo256 { + type Output = sp_core::H256; + + fn trie_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> Self::Output { + match version { + StateVersion::V0 => LayoutV0::::trie_root(input), + StateVersion::V1 => LayoutV1::::trie_root(input), + } + } + + fn ordered_trie_root(input: Vec>, version: StateVersion) -> Self::Output { + match version { + StateVersion::V0 => LayoutV0::::ordered_trie_root(input), + StateVersion::V1 => LayoutV1::::ordered_trie_root(input), + } + } + } +} + +#[cfg(feature = "runtime")] +pub use hash::*; diff --git a/core/src/traits.rs b/core/src/traits.rs new file mode 100644 index 00000000..3be72d0f --- /dev/null +++ b/core/src/traits.rs @@ -0,0 +1,40 @@ +use codec::{Codec, Decode}; +use sp_arithmetic::traits::AtLeast32BitUnsigned; +use sp_arithmetic::traits::Saturating; +use sp_core::U256; +use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash as StdHash}; + +pub mod get_app_id; +pub use get_app_id::*; + +pub mod extended_header; +pub use extended_header::*; + +/// Header block number trait. +pub trait HeaderBlockNumber: + AtLeast32BitUnsigned + Codec + StdHash + Copy + Into + TryFrom + Debug + Eq + Saturating +{ +} + +impl< + T: AtLeast32BitUnsigned + + Codec + + StdHash + + Copy + + Into + + TryFrom + + Debug + + Eq + + Saturating, + > HeaderBlockNumber for T +{ +} + +/// Header hash. +#[cfg(feature = "runtime")] +pub trait HeaderHash: sp_runtime::traits::Hash {} +#[cfg(feature = "runtime")] +impl HeaderHash for T {} + +pub trait HeaderHashOutput: Decode + Ord {} +impl HeaderHashOutput for T {} diff --git a/core/src/traits/extended_header.rs b/core/src/traits/extended_header.rs new file mode 100644 index 00000000..82838750 --- /dev/null +++ b/core/src/traits/extended_header.rs @@ -0,0 +1,16 @@ +/// Extended header access +pub trait ExtendedHeader { + /// Creates new header. + fn new( + number: Number, + extrinsics_root: Hash, + state_root: Hash, + parent_hash: Hash, + digest: Digest, + extension: Extension, + ) -> Self; + + fn extension(&self) -> &Extension; + + fn set_extension(&mut self, extension: Extension); +} diff --git a/primitives/avail/src/asdr/get_app_id.rs b/core/src/traits/get_app_id.rs similarity index 88% rename from primitives/avail/src/asdr/get_app_id.rs rename to core/src/traits/get_app_id.rs index 81c59bee..88f84a96 100644 --- a/primitives/avail/src/asdr/get_app_id.rs +++ b/core/src/traits/get_app_id.rs @@ -1,4 +1,4 @@ -use crate::asdr::AppId; +use crate::AppId; /// Get application Id trait pub trait GetAppId { @@ -22,13 +22,13 @@ impl GetAppId for (A, B, C, D, E, F, G, H, #[cfg(test)] mod tests { use super::*; - use crate::asdr::AppId; + use crate::AppId; struct CustomAppId {} impl GetAppId for CustomAppId { fn app_id(&self) -> AppId { - 7.into() + AppId(7) } } @@ -40,7 +40,7 @@ mod tests { let custom_app_id = (0, 1, 2, 3, 4, 5, 6, CustomAppId {}); let default_app_id = (0, 1, 2, 3, 4, 5, 6, DefaultGetAppId {}); - assert_eq!(custom_app_id.app_id(), 7.into()); + assert_eq!(custom_app_id.app_id(), AppId(7)); assert_eq!(default_app_id.app_id(), Default::default()); } } diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..e16848b1 --- /dev/null +++ b/deny.toml @@ -0,0 +1,290 @@ +# This template contains all of the possible sections and their default values + +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# The values provided in this template are the default values that will be used +# when any section or field is not specified in your own configuration + +# Root options + +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +targets = [ + + + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + # { triple = "x86_64-unknown-linux-musl" }, + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + # { triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] +# When creating the dependency graph used as the source of truth when checks are +# executed, this field can be used to prune crates from the graph, removing them +# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate +# is pruned from the graph, all of its dependencies will also be pruned unless +# they are connected to another crate in the graph that hasn't been pruned, +# so it should be used with care. The identifiers are [Package ID Specifications] +# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) +# exclude = [] +# If true, metadata will be collected with `--all-features`. Note that this can't +# be toggled off if true, if you want to conditionally enable `--all-features` it +# is recommended to pass `--all-features` on the cmd line instead +all-features = true +# If true, metadata will be collected with `--no-default-features`. The same +# caveat with `all-features` applies +no-default-features = false +# If set, these feature will be enabled when collecting metadata. If `--features` +# is specified on the cmd line they will take precedence over this option. +# features = [] +# When outputting inclusion graphs in diagnostics that include features, this +# option can be used to specify the depth at which feature edges will be added. +# This option is included since the graphs can be quite large and the addition +# of features from the crate(s) to all of the graph roots can be far too verbose. +# This option can be overridden via `--feature-depth` on the cmd line +feature-depth = 1 + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The path where the advisory database is cloned/fetched into +db-path = "~/.cargo/advisory-db" +# The url(s) of the advisory databases to use +db-urls = ["https://github.com/rustsec/advisory-db"] +# The lint level for security vulnerabilities +vulnerability = "deny" +# The lint level for unmaintained crates +unmaintained = "warn" +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# The lint level for crates with security notices. Note that as of +# 2019-12-17 there are no security notice advisories in +# https://github.com/rustsec/advisory-db +notice = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + + + # "RUSTSEC-0000-0000", +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +# severity-threshold = + +# If this is true, then cargo deny will use the git executable to fetch advisory database. +# If this is false, then it uses a built-in git library. +# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. +# See Git Authentication for more information about setting up git authentication. +# git-fetch-with-cli = true + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +# The lint level for crates which do not have a detectable license +unlicensed = "deny" +# List of explicitly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +allow = [ + "MIT", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "MPL-2.0", +] +# List of explicitly disallowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +deny = [ + + + # "Nokia", +] +# Lint level for licenses considered copyleft +copyleft = "warn" +# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses +# * both - The license will be approved if it is both OSI-approved *AND* FSF +# * either - The license will be approved if it is either OSI-approved *OR* FSF +# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF +# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved +# * neither - This predicate is ignored and the default lint level is used +allow-osi-fsf-free = "neither" +# Lint level used when no other predicates are matched +# 1. License isn't in the allow or deny lists +# 2. License isn't copyleft +# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" +default = "deny" +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + + + # Each entry is the crate and version constraint, and its specific allow + # list + # { allow = ["Zlib"], name = "adler32", version = "*" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +# [[licenses.clarify]] +# The name of the crate the clarification applies to +# name = "ring" +# The optional version constraint for the crate +# version = "*" +# The SPDX expression for the license requirements of the crate +# expression = "MIT AND ISC AND OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# and the crate will be checked normally, which may produce warnings or errors +# depending on the rest of your configuration +# license-files = [ +# Each entry is a crate relative path, and the (opaque) hash of its contents +# { path = "LICENSE", hash = 0xbd0eed23 } +# ] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries. +# To see how to mark a crate as unpublished (to the official registry), +# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. +ignore = false +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + + + # "https://sekretz.com/registry +] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "warn" +# Lint level for when a crate version requirement is `*` +wildcards = "allow" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# The default lint level for `default` features for crates that are members of +# the workspace that is being checked. This can be overriden by allowing/denying +# `default` on a crate-by-crate basis if desired. +workspace-default-features = "allow" +# The default lint level for `default` features for external crates that are not +# members of the workspace. This can be overriden by allowing/denying `default` +# on a crate-by-crate basis if desired. +external-default-features = "allow" +# List of crates that are allowed. Use with care! +allow = [ + + + # { name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + + + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. + # { name = "ansi_term", version = "=0.11.0" }, + # + # Wrapper crates can optionally be specified to allow the crate when it + # is a direct dependency of the otherwise banned crate + # { name = "ansi_term", version = "=0.11.0", wrappers = [] }, +] + +# List of features to allow/deny +# Each entry the name of a crate and a version range. If version is +# not specified, all versions will be matched. +# [[bans.features]] +# name = "reqwest" +# Features to not allow +# deny = ["json"] +# Features to allow +# allow = [ +# "rustls", +# "__rustls", +# "__tls", +# "hyper-rustls", +# "rustls", +# "rustls-pemfile", +# "rustls-tls-webpki-roots", +# "tokio-rustls", +# "webpki-roots", +# ] +# If true, the allowed features must exactly match the enabled feature set. If +# this is set there is no point setting `deny` +# exact = true + +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + + + # { name = "ansi_term", version = "=0.11.0" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite. +skip-tree = [ + + + # { name = "ansi_term", version = "=0.11.0", depth = 20 }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "warn" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "warn" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] + +[sources.allow-org] +# 1 or more github.com organizations to allow git sources for +github = ["paritytech", "availproject"] +# 1 or more gitlab.com organizations to allow git sources for +gitlab = [] +# 1 or more bitbucket.org organizations to allow git sources for +bitbucket = [] diff --git a/kate/Cargo.toml b/kate/Cargo.toml index 64fe54bc..1715bcd8 100644 --- a/kate/Cargo.toml +++ b/kate/Cargo.toml @@ -1,70 +1,82 @@ [package] name = "kate" -version = "0.7.1" +version = "0.8.0" authors = ["Denis Ermolin "] edition = "2021" +license = "Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# Pending to review +poly-multiproof = { git = "https://github.com/availproject/poly-multiproof", default-features = false, tag = "v0.0.1", optional = true } + +# Internal +avail-core = { path = "../core", default-features = false, feature = "runtime" } +kate-recovery = { path = "recovery", default-features = false } + +dusk-plonk = { git = "https://github.com/availproject/plonk.git", tag = "v0.12.0-polygon-2", optional = true } + +# Parity & Substrate codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -da-primitives = { path = "../primitives/avail", default-features = false } -derive_more = "0.99.17" +sp-arithmetic = { version = "*", default-features = false } +sp-core = { version = "*", default-features = false } + +# 3rd-party +derive_more = { version = "0.99.17", default-features = false, features = ["constructor"] } +static_assertions = "1.1.0" +thiserror-no-std = "2.0.2" + dusk-bytes = { version = "0.1.6", default-features = false, optional = true } -dusk-plonk = { git = "https://github.com/availproject/plonk.git", tag = "v0.12.0-polygon-2", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false } -getrandom = { version = "0.2", features = ["js"], optional = true } -hex = { version = "0.4", default-features = false, features = ["alloc"] } -kate-recovery = { path = "recovery", default-features = false, optional = true } +hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] } +hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.8", optional = true } -num_cpus = { version = "1.13.0", optional = true } +nalgebra = { version = "0.32.2", default-features = false, optional = true } once_cell = { version = "1.8.0", optional = true } -rand = { version = "0.8.4", default-features = false, optional = true } +rand = { version = "0.8", default-features = false, features = ["alloc", "small_rng"], optional = true } rand_chacha = { version = "0.3", default-features = false, optional = true } -rand_core = { version = "0.6", default-features = false } rayon = { version = "1.5.2", optional = true } -serde = { version = "1.0.121", optional = true, features = ["derive"] } -sp-core = { version = "7.0.0", default-features = false } -sp-std = { version = "4.0.0", default-features = false } -static_assertions = "1.1.0" +serde = { version = "1", optional = true, features = ["derive"] } +serde_json = { version = "1", optional = true } [dev-dependencies] -criterion = "0.3.5" -hex-literal = "0.3.4" -itertools = "0.10" -proptest = "1.0.0" -serde_json = "1.0" +criterion = { version = "0.5.1", default-features = false } +proptest = "1" +serde_json = "1" test-case = "1.2.3" [features] default = ["std"] -alloc = ["dusk-plonk/alloc"] +alloc = ["dusk-plonk/alloc", "nalgebra/alloc"] +parallel = [ + "rayon", + "criterion/rayon", +] std = [ + "parallel", "kate-recovery/std", - "hex/std", "once_cell", + "hex-literal", + "hex", "codec/std", - "alloc", "serde", - "num_cpus", - "rayon", - "getrandom", - "rand", + "serde_json", "rand_chacha/std", + "rand/std", "log", "dusk-plonk/std", "dusk-bytes", - "sp-std/std", + "avail-core/std", + "sp-arithmetic/std", "sp-core/std", - "getrandom/std", - "rand_core/std", - "frame-support/std", - "da-primitives/std", + "poly-multiproof/blst", + "nalgebra/std", ] + extended-columns = [] maximum-block-size = [] [[bench]] -name = "kzg" +name = "reconstruct" harness = false diff --git a/kate/benches/kzg.rs b/kate/benches/kzg.rs deleted file mode 100644 index dacaddf3..00000000 --- a/kate/benches/kzg.rs +++ /dev/null @@ -1,210 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use da_primitives::{asdr::AppExtrinsic, BlockLengthColumns, BlockLengthRows}; -use itertools::Itertools; -use kate::{ - com::{build_proof, par_build_commitments, Cell}, - config::DATA_CHUNK_SIZE, -}; -use kate_recovery::{data, matrix::Position, proof, testnet}; -use rand::prelude::*; -use rand_chacha::ChaCha20Rng; - -fn variate_rc(rows: u32, cols: u32) -> Vec<(u32, u32)> { - assert_eq!(rows >= 64, true); - assert_eq!(cols >= 64, true); - - let mut dims = Vec::new(); - - let mut i = 64; - while i <= rows { - dims.push((i, cols * (rows / i))); - i <<= 1; - } - - let mut i = 64; - while i < cols { - dims.push((rows * (cols / i), i)); - i <<= 1; - } - - dims -} - -fn generate_matrix_dimensions() -> Vec<(u32, u32)> { - const MIN_ROWS: u32 = 256; - const MAX_ROWS: u32 = 2048; - - const MIN_COLS: u32 = 256; - const MAX_COLS: u32 = 2048; - - let mut dims = Vec::new(); - - let mut r = MIN_ROWS; - while r <= MAX_ROWS { - let mut c = MIN_COLS; - while c <= MAX_COLS { - dims.extend(&variate_rc(r, c)); - c <<= 1; - } - r <<= 1; - } - - dims.into_iter().unique().collect::>() -} - -// Commitment builder routine candidate -fn bench_par_build_commitments(c: &mut Criterion) { - let mut rng = ChaCha20Rng::from_entropy(); - - const CHUNK: usize = DATA_CHUNK_SIZE as usize + 1; - let dims = generate_matrix_dimensions(); - - for dim in dims { - let dlen = (dim.0 * dim.1) as usize * (CHUNK - 2); - - let mut seed = [0u8; 32]; - let mut data = vec![0u8; dlen]; - - rng.fill_bytes(&mut seed); - rng.fill_bytes(&mut data); - - let tx = AppExtrinsic::from(data.to_vec()); - let txs = [tx]; - - c.bench_function( - &format!( - "par_build_commitments/{}x{}/{} MB", - dim.0, - dim.1, - ((dim.0 * dim.1) as usize * CHUNK) >> 20 - ), - |b| { - b.iter(|| { - let (_, _, _, _) = par_build_commitments( - black_box(BlockLengthRows(dim.0)), - black_box(BlockLengthColumns(dim.1)), - black_box(CHUNK.try_into().unwrap()), - black_box(&txs), - black_box(seed), - ) - .unwrap(); - }); - }, - ); - } -} - -fn bench_build_proof(c: &mut Criterion) { - let mut rng = ChaCha20Rng::from_entropy(); - - const CHUNK: usize = DATA_CHUNK_SIZE as usize + 1; - let mdims = generate_matrix_dimensions(); - - for dim in mdims { - let dlen = (dim.0 * dim.1) as usize * (CHUNK - 2); - - let mut seed = [0u8; 32]; - let mut data = vec![0u8; dlen]; - - rng.fill_bytes(&mut seed); - rng.fill_bytes(&mut data); - - let tx = AppExtrinsic::from(data.to_vec()); - let txs = [tx]; - - let public_params = testnet::public_params(dim.1 as usize); - - let (_, _, dims, mat) = par_build_commitments( - BlockLengthRows(dim.0), - BlockLengthColumns(dim.1), - CHUNK.try_into().unwrap(), - &txs, - seed, - ) - .unwrap(); - - c.bench_function( - &format!( - "build_proof/{}x{}/ {} MB", - dim.0, - dim.1, - ((dim.0 * dim.1) as usize * CHUNK) >> 20 - ), - |b| { - b.iter(|| { - let cell = Cell::new( - BlockLengthRows(rng.next_u32() % dims.rows.0), - BlockLengthColumns(rng.next_u32() % dims.cols.0), - ); - - let proof = build_proof(&public_params, dims, &mat, &[cell]).unwrap(); - assert_eq!(proof.len(), 80); - }); - }, - ); - } -} - -fn bench_verify_proof(c: &mut Criterion) { - let mut rng = ChaCha20Rng::from_entropy(); - - const CHUNK: usize = DATA_CHUNK_SIZE as usize + 1; - let mdims = generate_matrix_dimensions(); - - for dim in mdims { - let dlen = (dim.0 * dim.1) as usize * (CHUNK - 2); - - let mut seed = [0u8; 32]; - let mut data = vec![0u8; dlen]; - - rng.fill_bytes(&mut seed); - rng.fill_bytes(&mut data); - - let tx = AppExtrinsic::from(data.to_vec()); - let txs = [tx]; - - let pp = testnet::public_params(dim.1 as usize); - - let (_, comms, dims, mat) = par_build_commitments( - BlockLengthRows(dim.0), - BlockLengthColumns(dim.1), - CHUNK.try_into().unwrap(), - &txs, - seed, - ) - .unwrap(); - - let row = BlockLengthRows(rng.next_u32() % dims.rows.0); - let col = BlockLengthColumns(rng.next_u32() % dims.cols.0); - - let proof = build_proof(&pp, dims, &mat, &[Cell { row, col }]).unwrap(); - assert_eq!(proof.len(), 80); - - c.bench_function( - &format!( - "verify_proof/{}x{}/ {} MB", - dim.0, - dim.1, - ((dim.0 * dim.1) as usize * CHUNK) >> 20 - ), - |b| { - b.iter(|| { - let comm: [u8; 48] = comms[row.as_usize() * 48..(row.as_usize() + 1) * 48] - .try_into() - .unwrap(); - let dims = dims.try_into().unwrap(); - let cell = data::Cell { - position: Position { row: 0, col: 0 }, - content: proof.clone().try_into().unwrap(), - }; - let flg = proof::verify(&pp, &dims, &comm, &cell); - - assert!(flg.unwrap()); - }); - }, - ); - } -} - -criterion_group! {name = kzg; config = Criterion::default().sample_size(10); targets = bench_par_build_commitments, bench_build_proof, bench_verify_proof} -criterion_main!(kzg); diff --git a/kate/benches/reconstruct.data.json b/kate/benches/reconstruct.data.json new file mode 100644 index 00000000..dfa6a80e --- /dev/null +++ b/kate/benches/reconstruct.data.json @@ -0,0 +1,135 @@ +[ + [ + { + "app_id": 2867178220, + "data": "94461b692904e3288a40893d750f842f0f1f72e2d1d305c0e53e20b04abcb9224aa4c91c1dc391f2702ef3a0aab4f3488945bd0005807499f3f3fc0b395b607ed35d2d4bc6ac8b9ab0ff5cb36f58fd2237144c312dbc658e11fec7990febe8ffe4373e33bcfb5189a690b11e473aeb6d57787ef6ea0909e7988d993e583f589b31e8da63fe014db6d1fcadc4a6e99b15d21cfa5ff00cd93d89224b7bfccf7cb44f9b727bf7994b849300a8a4254feab27c9fc3918e4206febe64daa2b5f715fc6763d4fc1ece9be8424ab1db4bb843d097f66568101e586e47b220cf61a0ec635e0cb4490abaa4fefbdad6588eb3e670d1037845257f98971e014f9079ce507f660bf27d25704908dfa2520a92dd06feca0d8737a7c774ceaa1ba9887ff398da09b21bd78fa8dc835a5731d4a4914eddef16209d14e319a809306b62180fbf8d6fa5662e4f1ab09a1efe358a9a88a52393b825120648af932ba1dcd2d47a0ccadb0ba96e10d04d02afaeeee7c332560ebe54f7697ffb9a405398cc489dcf4812771731e9a39b375b37a35bdec4180fd0647f0daaad1327a7f1f6053125a8d64956123fa22d1cc2528f595465b924ed14142e97e0a92c34fbcf76a199c2fe84efb4cc7de2f0024ed5b29b0b81e2786652a8fceac787b23054466151600b5ecc47abd930b80cc78f6abf2811f6f93d33600fe3bf22bf8087d3d39df459170a7e7c26e3f143531208b2702002937eee2b5acdc2bda278c23455b14b060b01a8b9aa57e8ba499f0a38d429872e7701bd8b1f8161aaeec6f46d5f9c996fd83053f9dd787a4586107204d5d0bcb8abfe043bdb5c01d3b8fd667e8d8fc6e8ea7a2e8eb2fa9879b9d2ddaad1bf8550c61f7ac853eb8e9b708eb8eff4cc7adfab147dc355d27ddb0ce3cf78106c871855e1f9cbb340ed0652e691ef657f5a19f2f3f710f668121dea55727497633773b5e0abd7acf97d313139be57ff556a728933b1fccf3203071ac494686343530ac8b5a31951a9ba86048870cbaf626417b8278e8382dabf680da5d8d9de5dfaf6ed54b321c794dca67c10bb0e7e4e9e4b5a2e2edb9f5b5ed5188e7694488b39da2e8a0266569dc08e6e06a68e698085326b6b456d89993e72bddcf522c1f70a1d986c54bbb8328893e56a7fb58ec162dc5b31fefb94c417ce6bda86125b6b0ef4d97fef83bfa38b901f8b7bdce5d0b27c841dba04a99b6b0d88a9d5ae387f193bf4a40e2b4f301f7e63195a1102ec9f5779c9cdac0bcdc0c04c318a848bb018903e225df771fe92bca9b592681f584b9cb484eb2bf6cfdcc616cd08e16ff306b67f09b18279f3ee8fb30bddff62251452482b25980a08c6fa1d8d3e0118204269323e61f43e513f14c6a46a638a1159abe7b1acacbfae6d057e7eebcb03562aba7460a66fa1c547e857b31faea87a6e028fec4d3f05550e5e7af60fbb6e793ecd9bcf85b36a6244995ec33a85d627d9fdf47f185d4ad6fc90af245c6ba5b74bd69e28d29cb311da691308e7a89888dd54b8f4e760c8b809ef1a821507ba26dbdc411af54fddd9d8dd36062fa7f39b4b8293188813d7d93f74a7eade8b8132ab6a393fe4a92ee3eeb1526a0dab793ba41e6e92d9" + }, + { + "app_id": 3120385832, + "data": "978c8270499be4097e6873e513e863f307dd58362e735f8c63c43636c8d301fbc007fb7ec140abc2f1db6d90410e2a3a8fc2bd58cf2aef3545144acb66231943f7b8647872aa2869010aa7ba6a018239b3357574df6f831d9f0f4e6f2859b6387ad5faf7a736d9a88d61495d55091fea38480e956e5df3704ce43a0502ca21584ee570c7cf350f51b613419af2da7ef852a04d3663cd44d1ef07d61f8179f42d999c82c30b87beff1859375401b432cb9627a3d66bfbf32394824a1eaefae7792d6332c711f2ef7cf00b5b0c4b95954f510b9fae330751974a01563c74e6917c2e24e74ee74e35aec557ceb8a69b1d4340efb86acaac7f16d5eeb76126b6af0a966ddfdfc81149ecea188f7d519b50c58a82c2bbdd7d88b9285374d7db22f310a8488f21b238f6aebc9eb1c868b3ab5ba7026cc0c4849e6eb2c64c0df6684ba3523243ca63e044691b0f3e7a02aa4e751fa7fd4e11b69b6b76f302f1a82f86a8bda291875a5f65cb13d60f31a177f68eebd7703fdd6debc299e4f03ca40d0fae82ebb62d644d63608229b831c1f484f8c3c104a141f67d895a95cb4270253021e502d096f9bec316ce7add2dc733ce8a936189e9ce58cf2b6f4165392e6fcf6e162f0813ba7d1f5cc68b033418881c804f2c1988946b141a85212093a01395baa62e611a04169d5c1e03817695edc2f66190da077ab5b6efe8f1a20a294ded7334a054b22f722a7ace2d7b2a111819eab01e06447f2e1567dcf4de32998b3743dd64307a967f9c4d510a4fdd858f0394d4d69d4b7438a7c429c9d1d88fd9bbdd11e88e2e3aa70daa971b933d05c2b7931e3ddcf602c89f55ae58e5a5fb8fc990b9a722a73bfd2b33bc215dd2de3920ce335193f51bdc69f6e1f2e627558a8bfc1acc3e4a4df7ecea489c43b6cbf747f975f9abfe82403ce9de4474baa06296fe71db533ca049d2fa0e29cd4dbe857520cc60209995e333a7ffed2cc8f5068a283d672394d4a5b1a06861a233727e8ca55abe385efa8265e10edb95ceff8b92860d6b9af584e0bcdebb019e471250d39e8dc741ea6aa9b041046102fe5ce71d732f3d86cd00199311964bfe0364533c2ee34bda9fad96d3965ab021bd4720542aa6992faf94745b37c03376e3b284c98911511cc487cfe6bb53223a0cdb45f615f8ca3f5354f2dc7124f139cbd5a0987a5085c9df8face25a209f10ae522ad32e3f286edf400288cf1b5dfe345e7e5d3a8fa9930e79921b9993b7e507537357a9749e3bf41c9121a34cf335d835f6a792a005be878b5e03f56dda628f5bcc20a79e4c0cf5991125274163fb87fd7aa9ab80ff8a232fa7b00f347b0d8d35dd95919bcb9448a755de2469da82fbd1189ab297b23e7e610a42de808dfe3985622f2aeab646f2467af690d3801272995573625fd2f579efa632a1c0f008ea17075e61a9018e9daf0bcbf5338e10217160cbf0f628c2255948cbfa5667fb8fd1895d5d354b8c09ce97a0658153c20136dfb04f71c2dc3fbcc60192428962552e637e5a8b2ed68d8c35ba11749f28f67bc99d83ae04d65c0b0117da75d170fd7c10d06bc86159322a2ccf129da67418ce4ecbd4b635c95941e9f9840fb124a0be6a94a4c1b7a20aeda0b5c23f1c6fa180eb3dacad9df04848a38ef687b4948e8787b2006eb6f3ee9ad666f9d3fc8953e3a94d44ce35ec66a9fb5489e5fe01b0016ffa1078ebe888ca282152155a31affaaf76f2" + } + ], + [ + { + "app_id": 3570869364, + "data": "e9fd48e7a698af62c4c88692b9bcc576b31b048b393d9eb36be9ca767b58a05fb486d05f15f803b0967418ca49aada021e29c52a3550b182645222d5118fc5fc80b30d9b496143c79f5ff67ca959dbee3624a8c6ecb0cf4352e01aeca6b4a738d9ec22c732ec9c7e74c3d0270e6cff9c30bcbbbb715c7b6c73991c3f6b5894526b49bfc9ca7db2cefc6c369c28f6ee213040f1787e2c2c9751e5c40b3c386ebb7c6268b9d6adf2f34df24ca03e8021b894463b1c1e93a47574b5c001fc9f281521f5ab905c9cefe593d30c16071f2b4fd27d3f204854da10a37a378fdb999e9cd97f22079a2ceb00a206c370e5df3e78e0a1b4ef9c5c1933817a4c9280826e35f1f7ae824482c4cec068d19ec80e735ddb94a6ccce117fd5853bc061e71ce04789b9235cf6314d05ad0a17ed2dfa3ce3d7bf1466a6a6b1fef798dc1408cf2c51eee6e5de0e4f12f105cf9b99d0285e48fbfa9330a0b3faa4cbd32829a1cf904400c77b47508dc68f43d9b7066dd41d0697b2dd6a5e2dfaffe17a6884fa58fc383f5e070cf6fe33afaf1762d4f0e204558444f51f6d71faedf49bc51f64744cfdac6dc2fbbc3dbaf7bbe7638b27bbd5f559d3a4fddcfd04cb5dc5ca16cd5dee85097d61f7421b9e86155b4571fc0d91a1a634e0f3b01e5fbca9de94873d8905bde6c54c619ad15d5aad3238db60093f43e383a028091c4c0d27b916ae6509461b51cf276787c04c28bba9718b2393a7e7c6b93cd89ff5c0d547df92bcdf0155ddea23fae8e78f040082986fdcf45ed7f4c1d29ad19d746e139919f8a30423224444225dcddbac71c012b21f791d42f31ef287d1cb7f9b6c44f4154875c2146830ab48a495a836cb9968b76fdd11feaf5a3dd979e7ffb780c6b9e018550a7532cbefcb65ce1dd0be2afda3782346cd0a239969805d541c5d329d5bcbbb3d3e0576940ffe7124c56331749432ad719f721eea19438cd3d8c4c3f9ef59d3e495293d061964e10d26edb44e94ab74fe6fdb0de1b51f7304d76fd9f77c1d50dc51d14a94d2eb6784de3692f61073c4725a2f" + }, + { + "app_id": 3698898287, + "data": "1e7edb5645169db65b5a4333d7e24a7d5b6506e775b18765b3edfb523f9c3a2cba797479cff44fa3f6e2332b1a473cf7f2a859aa404d3a777580d9d11f0566366b6247e417b6c57a9c1cab0e64f74411aa7539002e3af3c64c8af860778c6ee51926a3d377e1d342aed4c2e01d061de793d96a1b01d78a106d44c4d57b3db5228474c5059ea7ecf735aca67bde00d6b3e69d9b3cdddfa918c4772287ab357abac966e789ddf139d69cdca3807cd38819d7c253868669070a34bbbeac4b1ef92eba5974110695e8eb19c5e82f4d0dd9da0a06c7865566ab9864cadfed43edda9a2021f882fcbd84f71049cdb9cc2e420972c83ede19e9459b8adf268a721ab1f1c8664df331f729ec69fb2b79054401c414b5dc525e4dd981483225ebc1e31886711fd504f11ee09fe9e33ad513f28923476f42b7974945623d" + }, + { + "app_id": 4086489077, + "data": "a2227840b7b420b07595ce1508a118714f1e68ae67441f09ca2dc106f8b07dd537993827d3d269663330112b01e315c77bf001dd16eff454c9d05cd647acfda96c9a3fc8ab2ae041cf94b74193defa170889f467d994999252c35235e2fe55da08b9288f0d58baf742343cec985a5f8858c276bf3c831b7a999203667be28406e4dd791322e9d833c5da477085be2f1e8432cc063ed018184acf6613efcff7b2ff501005a54abf6afb0d9325c25771e09229c1338ae88506271ba9b7e448c3da7fddceb6b0f694cb3b39df2243dcaa727acd3024c5ca8d3e6ec25ea78377a4f48ed78886da41b59495b959ff3f333c0a8e265a1a2fd79a0e28af2d41b59abc632ff7c9a39fd64d53298e27506eb9022217af934b1c7c90ca2fd9de1912071f80b748d3f13d9f8f2bfaebe468775af842212c44010d0fa85f1d3202cd922c1e12b6568def37b71e66f4eb20d36de2a27ba398911a6e49bf2540c9d6055f87630711283d9a1b6debce7a1e4658251faf8763b9b1ff6a8604ddee4395e3b73afc720617c69d4906a0202e6bc0aafdab1737b205614e0b3fc65b0c068908ff4c890f24dc5ded60d1a73e5380998b171fb66a8be4cb808f6aeb98548263b5804335c630d40335da18072d34206ac845db8736016a2ccd4d0a6b4846eed735c55c9b8458ca40cd3b72ce1110f2701f10bf4b6c0337a0df239762184e02519e217780c9866749d29bae993681694f53ba170c0f7911acc850d3eb145f119d978026878d598357efb0122fdcc381eb54508d1deaa7c983bb7b1aadce3eb0e6d5a9e1c0eea7e39190f52050288853f61b618445281af9c93c0912db987210ef2e156ad136fd3d5e54af173f76aeb1f65e8e69d4e923a06b1b6b40f89104cc06c4e9e27266ecc1df1964cde62c1e465a2103b556e2e977574a68a8a96106b196d6b21d278f91ea56810ffe5759ad1f5e174756872fe96408d4b765dd9609c91f86916d07095d9ddb631c41846948a779ffeefb39cb290da757edbbec73b28f86086e25b7b46ad428138ef5021201c4cf0ec57e4fbc8031e79ca60fda331e077fb015be6ebb382a098f85fdf15867a8a85ca896cd23a90ca7a7650cafd46a3089e8edfb22ea890551fba73205de8d07646995e6342d0ff911edae53ec050523f6bd6e080b76fa483d57ed75e825b2fa669bcb68394a5a3ca21a426ab2ca241beaae7f1d816b2079f60062ef2141cc86ba23edb39e19df5e2292a97e4a291c2580e1d8ec714d1243beda5fee6c46daac4d64ff9addba07a3268848ae90283e9ec10b21776aa261ea6f562a5bc69aebc01ba869d7b6b20ff86e2bb76ea29902c8725f5e5bb56929766798622671d4e9a5306e948848b701b4bef2d5b9a7a7ab88a831fc3ded843149c7c802481b84388aa6f78ff9923f5caa3b0ca9d157b9a72abae3150d3083e4291b81671d2379bde07865244aeb0023de0bc2845ba6c090880720c1d272e63aebeb5db8695840cd26c979797d8fe6d859eb7a37bf7e362a79a31f44321cb2d6f3d9c44109791deb40fa4a480ea0a1813b53525f24ad26193b6fc632f51729470de100ba90d27bfc5e05997a86be4bdbc03416d2ee4c4aaf9acfe0095a8d165bb799f479d2ac0d22ba211f6c1f61f99d26d333843baa7975dba9247f682bb2e204a16acfea127f359050818df01ba7f7619440406c0a4c8645421de5eb0ea9ebe70f96bd2efcb1218aa300d2ed7fe1c53dcfbab1619959b8d6a5810de8c5f30ebe1260a3607c2e3b249a97fd464edce42e0719a6396efe7b591eacfd76b1425de327882556b7fba82dec0b2ef6b1181ec13e4acbd007bdb4f17f2b0249b7cd660b00352f464a3cfce1a34c56a0602a9761f30d550a135a5326ddf1effe19b1587201f2bf7e3a132ccd16280695c5683b55703b1f8a4ce89897d9f9549c5bf53509cf4d6a43aabce807be0469a8c07125190db84f7f740f26438519bba0e05fbd6c987a42cade13977632d9d831a3a0fd04c3b588310e4db8599019573a2d724927154dacb3179178a9417f1b04e53192f587421334b31341cd77bbb2d6ff50e1b65d4d57b869cf8abda3764462a52b705a14918737e93f69a17433dec67bea6d1ecb91645ded5e5a1750a4ab395f4430a432538f38c9e50941c8000a2951727d9a523a97310bafd77af695fca81a2b72fda797537a9d4cde474faccb009a19c3a4ba15be4a1b9d49029abb94c30b20cac72e00abc2e42982f432b18622ebd67b13d9e1d92d3ceb50305bc3c67b896306a433a9457921c85f09b91e38cd1c50d03670c39a8c8c924848505e10202e6d4070875bc31a6a19c07c056520425b6d0fdc8f828a004e57dee437a21cca505970bb7468418309c8caa63554cfa7feca46878ae60b3495b8eb0453302295561de840dc0aa9b6fa9136494a0243c995fd571cf4ae1e30d37b8a360faee63eea920186b297078ebc58e65b6d62977787da91c2ef99bcbc3f50abd680f9d712b5472783d9be572c6b49317046eb6e6f8fad8dc9755004e17b4c6fc5c752e27f46a863508c0a2008462436e3fca4a144e04d5a32132c2e99bb49aada2b8fe74af15060724e5005c26d76faee8be01a05cc5f986888c1e21b3d70e146abad8d9478112250cfbd91f7675ab7c10f1ec7f1c3e625d75ba8047cb73e534e4a53b09ab08cbe3b1cdeaf6a714da5657117a9e666cea5065fcf0a24f046e12b53b2fe206decfde30be5219b6c6e38354f31b78070fe01044a70d052b7522bacb070d3e4262a7fa3f7321797792286870e0b0e806ee9d4eabd92e0ed9193b7247a5c0bbb025435207ed100e26091e76fcc809d1efc5a765b2154d1d70fdbb5c08805bb200e047a" + } + ], + + [ + { + "app_id": 912747417, + "data": "5cfa2b9e618e7ae0cfb2af0e6ee9f33677e3b4e513efab8a7bb4c9befac1953d72f41198959e47a1b199a5aa213baeaf070fa517a92611a9e7ead08295c243f025ceb58da6678af48eb5743d6c3964247f2028e4ab0485df1c12a897fb98c411dba7414010b2f14ebbb16882bee720df5e55f73b628d7855d008c21e7788e289bfd99c3427a849594038e02a2faea45bb31d902876bae22da1722262c1536f6d42aa839e29ebcba7c6835c0bb47d7651e1495bd62c3f01d93c23778146f33feb8f0660623141e2212b2d15a3195410654f803f0c765378968aa111e70d2febc426bb14290188a67d5733c1630da41d932f48917b5e3e3ce05370d2de8ca28e8b970e9bffef2f135f0195d9f51220c3a6ce5bfbaeedb9f5b8f14686bbc88249329e258ce2dfc4375d906496df835edb26e65be0fcfd93f0146116c5b555b5ffb6009407841e9880fb95303f08bef10b4c98a1d592979f00fd0ef451583a4a3c60a9f2e1b4c1084fec2ed38fa2a06ff65dc736d9037b99143ce264511c9d2b9e16190f5ec05c49c4ed2b31d8037564f91b876123a0a6fa4cf2f29769e790764c97027ddf51eeee803744e5a2597f317f4241e476ff642269f8e32d76ab610cf52a7b4b3970259d5f93a0f5c8c2a1c38a4bf74517d56efa2247256a4170b1dca0514e84ff7df496aeef0ca2823f7bfdad2346ab6cdd17121ad005de6a7e8cd19d6d02311f1bfe7d085ff468e92deaf5d8ac27b5458a6205e2e2d899334578be9aeb2d8597bde5c4d4111082996c3b95759a681d45143ac3ffd88cca866d60a2b0301dc4636733cd0ca21eb01c52b99792397f69bad37ec84da9f3cd00cc6f9489c6b60cc53aeb20475ce1d9a58aeb1bd5471203e2810d386edcd04a40f1dac82ed5104bdeb4c30df5b8a459d5ba00ff90ac9e05b487f7eba36860d6060a0d86253feb044e830c94d16bb0f6d4c153bacb3d541ac17f4d9d8bd46d6e367158d700e5e76d5c1f08c969b4c4d1ddc8025169f02c2412fb46452d3d729df59a4843b397e0c6d8421f87dbc4a065c2bc4012662b8e24e4c60087545f2e08a6029c07f9f579cff6d127d3d08a7b9bbb92e2392a92cdcd353958b148734cb209d1470bcf6fc01f97fa076acab2f698477d058b8048a1ae15b0afb89d7be071a9d2f636a1c65337ca5f603e6ec4c115f59266d12ecc8a6e6df351cb74d93b2479cbb5e2f0a9e42bf8df7bce0d4a8986328abf7792a141d160a177e5d9c9850d041225565bab3874675e578483ea12be82281d93fb8a879edf9f4000c3d682ad7bc123d3b7579b" + }, + { + "app_id": 1380428063, + "data": "7b4dccd49bb5dec165febc1915df957be3392886b2f8bea481737a397c3fed7c3bc593d52caadc83396c80cb755d3c0aa302f1e433e92b394509c380114a58aa25e6e2d7b609ef13e6d31a208ef0f881ced3cb0541e423cf4c401d1736bc31d978b52d242ebc906d59c996a91fd6916e095f11bea2adeb6b5c6ecc59d6e82e524376d7a9132cad915ba56ae17c854aa83282e33e726a03012843c943f82ec55180a54b6de9bf2e43c0eb6f388e9faab5d18d81aab1c5ed87f30467be76098a70570148f8ac020379e67521d02fae3b2a06bc22a422c21cb67aa675885373cf4c7bd2024378ee7a7329694048bd55fda1271d41bbff666dda6696b2ec823b43227184438a31adc2cb118e2c9ed150d64accd2efdc762bc359cda610aa55d9409f2fe910a1bb688b17e6e59d6f3743c6e0cc9c866f5b6748f8fd5e75517fca70ee4019ed04e0c6c11f678c61bc17d0588ac6fd1b5e9bafbf29ce8ffa20b1f39426123ca6603cc5dafda0dd9c27453ac026256368e6cce227dc55b58417939319436a1d9073c1b7116883c671503112f3309bcfac9cfbb3ae6f274ca24bf209721d4124e343f02cc8770affc7af5deb6fcff415a8ffd4b183386461b332195a08e3756687ef8cdad75f96277129fbf0d15ec574e75323adaeb7fa0bd0deab80163d21e5587a6a81f59ada826497b6ae20861304c8e3b3b1088bf07923515b37d1423d57e72f3b777d0a91259587e529b8c2b791089b3b31922c721f096b85f086d01448f0550f0fe7395dd8bb0c634e8210ac61f245dafd118f98838746c1dc744a4d957342afdb338191f14cd560ea41ebc8edfeac5761a9470772328666d8b744cd15bd47d297859dd8568cf56e8e4ed89a1c7b3361f704ae97df0990573770bb6a2a2ab04f89a34a24f7aab7036c2a2925249f7ca4900a55a3bd023be33c58b4220179bc87ce17855c9d70c3e39da0a59c36fcae1c49bd8ccd31fdd544c20ddb036c8cb9a1beb69228040f692dab92d40d8ea615c30cd44ad9b81b3ca9c3464dcf1f691fc44de5a4481366120dfd35936a1617b2ed92a6494cf4ca18a81cc99268d98dec85e0516df4e3dc8203371f8df4f38e037fd6433dbe10bac3efa09af4c478d5a2046869427caa1b058d64486bcffa4cf6cdd160174f46d35a31cf123a887c2b9c5c630cfd7d04fe6fb176e66b1eea16ac61421d274f7b6299b761361129fdbebfa9de6ae542de0dde62608d7f9954af8a5de5c33c4af138829183e64c2f1841caf3ef1b14d100f61742d12c46f667344a88cd46ee303fcfb5352e974dc7b9649e6a1f3419124c9b319cd847dc14f21f850e47fc5d27f6b1a42fbf188c151a237833961f42d5f90a642dffe327a0ca28fe73aaaddd538a4ec2a20e096e65c7959f3e10b8d7ec44a0125642c7b206b4f65c803d793962fcccf6e507b77c064bf7bc248e63333d698427d060f9a58eeafb579ba0382faa00db1be78a4cc4d508d51df1324861294f0bb1114b5995965f36a776a291a1e418aa12250664e8e69e0eea73fe73bd0912b357aeca72274a257487b250948f74a5ec120cc758864aa8962ba983f53730149df35db56e03f69e28816241c35a37eb7260b278133bee303b36f1c07d1bdc91f81e040cfd4d68987e3a702836eb6987cc1e23c260b7bd39f0431490fca7af8f0ef8d9d65bec10d24ef8144fbe95d4efe200205f314e460edd99495cabccd70bc4e44e983f0c73a013b667346c77eab2f309e5c580445c3db0dbeb8e49dede41c0fe0179fe1af106ede3e67e020424e48debd72a1fb95c79339e7db75fe8bc6270be72c869c6fe2be4f0caebfd6b685833572256dd7c070a4f1f06b33285de122cce7b1ef008001ac91bc102a941163041c70ae936a4f6b30a42549a73b8a1a1c69735d4ad652ef059dd3db665370e98d9707c6850ae86608b1ebeb9df6a62db29b18244ae5d8601b935890b02c8dfcec2525990e3c47c06720dd95d05ca3544ea4c16e4fcf21010edb9c06e3f953bca4aded0145da40dc0381a6477efaca487eb761081cccf5a8d06ae0962b7184937b49674fc95b146ce53d63deb23ee5e895b2c6c95127dab30934e77d8bef399a9d7c925e97c71ff963e9441b7e28b683c31a7d39fa62790e7e9dcd4d9e4a7fe48ee46e7e4edfdaf91013299bed0585906f2089b3fb4b8d2de4d86c56a886a26a0db91d9bd2c3fc6bd34ef5e80ba77a41b3c1b094848bf97cf1a84fa8a3308840f8f353af16c67a0397ceae0c49d38d07e80130e94e33bad83739accc8bb94689a02b82fcfd4cd588d81877eb3168a7c6f15f0a72912a8bdfaaa5ced46674cea37312f51b469dbff9f1de68b54eeb683fee40d49e293a7d3d209bec81cd5dabc8f0016f2199ef82817fd259c4381fbece2a95d4394b66803b275d14a0456de141825b8f41418c431dbcdd0d2814afbfd860a3398eaa2a5ecc389ddc4e15bdf437ffe25b9653d06179a887db739026bcd4c24892de19bf665a3352e405363ea70b1900fa5ccc38faed147ecec15ac0d49a0b289cb4ad0f64901f72bf75abe70fb59785095159f685981f5b935698c0260f977d17ebe8f30cbdc56d94f901b" + }, + { + "app_id": 1432371538, + "data": "42fcccf25c2d1dcefe12c2eb00b918ad31407c3e12d182bd133a254015a9fdd10c2cac3edfde06aacb7e5e4394e6eca9444679e615e048a887032618a9048a0c97b8b0c0fb0b6ba09e7f0d32fedeb15bc08e9f3e3001d83cb199d9214d3622011d0ae03bbd5ea66cf9559cc2b1210a0a5a92383cd97764f82a388eec8f3c481b50343c145bfe7bee56c91ec18aa712375bb68dcf074abde3c0d4d3d5db54ac28c1c46d16090ff3e45d304d0c9bdd2ad1011588fcfd5dbeb343e6f6e4ef9e4cd66ac94857d15f782dc215d5e54084ec11c2ea6205c9db736d46568a32dc77abc83a9677bf9b77eaefcc6dd5176208a20fd49c5c6bb080d3905be31ffeaddcfe2c6a69d18a938eb4639950ec19ba0c18507e8312f99ebb6715d0ff5cd81ab84bc7c602f51907cf8515af05ef3f058eee2983a2709e792b210e86311ced80d4f197f7799ce6179387ea240b915f9f3c83549d64227c929c272fc315c61c6ae42fb17103a8e83a42968d97735e425379204002a6756c42f2cf7b15ec4f47804cb159aac93fc442e6f3ef49df245bdf242e90b746b63b031618e26394df9598bc9be24a9207be2fcd92cea283660b68479563622245c5ca25413db246134885631be68a29ac83cdb85b133148eee299289518669c4f02a35240483294fe12faec9f89749d92fd70d203b485168403566dd356ebaad4943f7add5688138e6bec3da426d387ea8e31e0af41927649bed1933d8d6c1c9a0498f8690967481b9a91906721b29ae49a13119825d1871cc76380b7bbaaf88a786bfe7b86003598898e86d76bc02df9a8d8924f7315f816d8bd6c53934a30365182c5ddad438e8369abf12acb95f5d9195b958e464b9d895966f9cd134e7fc88a83fd871740fda0711975a2a5b508e4e68e0bda2d066e7817ab85791703be37e93dd1fd3d26418f64b314f49745706a85e967725dee51fe836ed76ed9324e5ef8c4e2c5b9cd47954cf0321ed056f644e79b9ac85d13443e925201d8b4c31b587372745b2516c58ff69f5b3ce6e9fbe480ba3903d5caa78932e108f8d76b6e579ab45244e46d5bb4c95a24a53e3b14bcaccf57a7163b94d6a0fa570e0de957c08668899bf74c0dbdb85e09c1331fbabdb310017c3d4eeb51ec0bf6afbdc86f8bf05efe4f6e751549894618d434333756735b94b02823f6c2ae10" + }, + { + "app_id": 1892003797, + "data": "278917d5da02c127e0f2f2e85fc4f66284117cd946a837861bda5c3c92534cc64ce4055f54362f48c407cf31c2d9ab05cd77f4d91f45b74ac4b510b4025a19d3205a3d34aea51c0d59fdcd7c45d67ea5bbcc6cb4d0a7223eabfe7a64e4fcafcb6de7b03d0f5581355d54364f50e6d56cec51fb8c6219422392bcc69925eaf1dc5ab5a9be8d34892c0ba9ee648705bd33d7af403fc34a883f96df7157022a56c0fb49b207cec2e1d754c61f2fafb87697b6561d77439dd50a79b657f6f4ac4fb9f954ebd1284d692aea8ffa5021b3691bac24e905c1fd83e5e4bc8ef84a1a44c8090103f97cf44484056d76c5335ac95b73944e0aab83900771a4f162b11c1392993bdc7996dfa133fd194f443143802be3304cfff6c6b85452f39225e9556d5aa5d28b397110dec0e8be3720a395f35daa526e7cdcec1b1075a0946f011ca197c136ae84d768863852804a0ecb501030f229b38920079d22b945b8e4a03fb1155f5445b207ba4f5a1b1868367e1002a9733abf56b9bc7371ae03f0102defc16d5930df4f79236e04a21f8d9bc6d8a2b9b2ac4ead3b18fa6054638520a5a5b8464a39a890b4483c9fb0f7a90ec1680364297e436fca55442b123947d8849170b7a161922a053caf3d6fcd015d9d9447dd146e9f69f97ed5cfcf19d8be240f9c43356ac7933e32ea99bae100bbf11e2fa20bfffed312f41f5fa6f77f7c0c08b3ff3e7266e3ad4bfe3a61cf36e77aafb16b6f9a8aa0db2d0a390a01c119d05142ae50d24399ced2411514db0123ec6b49c612c82bd3c3936bf98fc0af121da9d1c4d463dba46d708960ed6bbb7670fd72689d41c982fe812a540f08c0c08522ed0cdd2116e3da3a67c48d35bfb6b0a5cbf8bcbbbf66d36cd21e7186e0ea154552fbe6b83743d5f4befeb4766d5a8eaea800085fe0d388ac835c6323a2928a33cb403b94e9ac70ef213307f8b9abf1e395a444b42a9ee6914e99fe8e41d9cb621c894ce6b334520403079731f7657c0d61c030b1f6b71b90398f36d56ce8783eef17d3b46dd9fdea0dba83ca4937c3e777cfd18109ab5708bbe6f8e53adce4b0837a19abab1abcc98f127e21cc9a72288bf4234196061c3be4406bd44554c7235184d5c61cb949b174604c1485fb306106e3399120b11d1841bbc9dcf30d5fd13fb27d8242d305bb1cb07dde87a42ac09b3d8e4c9326b02d388fa88600743cee6c5c8a977bb7d3c5bcfe325e481f138ae8465848c28b11d3c4b6e2a301d03c4fa94c67386cb1633f1db81f0d7113cc4d086af904d606cb35165968533944d63873ea90bebd045bdc00b81c1612c154b96da3183854fed595f1e0b2317e7a76ac20569aa0d5e15dc63ae652d0997536a39fc91d04a4cf3dffe15a5db008b32c7b4b1ccd8af252c681e9da330233ed5146b25c0c38bf5d76c63faa42c0dbb3a75c41b0f1c1c75c7d28bdcd5e2a53161ed48dc48da965e7efea9c923e9295c8a7ed2a62035310851ad87b2feb30e8a435341d60c7d253db83294f368167fa352333" + }, + { + "app_id": 2008533748, + "data": "b1faa5a0adcdddadb9b67466a2b20eb2176a22116b108e1428b03c63e9a6e2cf8954aca0ce0c2307f499974a9c688db73751a2ea43d27a480b79d0b8d6da977034d61655f9621336f7bdc0a2c2bb2937bc172176fbc7c04f28fa80645210e0a8e06d1a0cb6fbdd3169ebf5c28d252ef4633026de48d48aae7405986f4d63ea1bd50e250c6ff19a825101a1cdd2bf4e4910104e19aacce296741fb5c5c5525c42e18e12fc16d182d0e2ee47fbb847d2b28b15c8e1018213d080c209e67332291ad625bed0a226acbf8b43e91df995661d289284c5757cd85d36f99c4284a9338e1b09677a61d3c7ecc2e35354ebd834c52612f14accfa55159c5523c9ed336a45659c818c2babd6edc26b1f2c23ec7a6890847503b1b30b5774ec1cd654f10d6278dafb9004f1d2ad0cd6aa59d55542cdc41c3a333205c0e2bf0fec1e88c01c49febdd958b35aa9c489aebd36f9142f5eacb52da5567109f86ffae1259d5721228fccc7b2ce85db68a56cc500909ba3539bace80e62f1e8d8e623e8e4c0476e33b25982e7d738b6f4057fd7eb9f0244e66cdc69c969b8024bc9c2dd787b375e77abc63106a082412f54e3888d55d06a05df3b72b54c0740dd49a67b72ea8a71f65afeab0caf9aa12cf1e45cb6caba12ac23f9af2fc2e3dc650012d4acdf04f88d5a73a9b674a10a759b4b1221bc4bade26af66cef78edf53cba127db3ed91ee1e4b7bdccf64c4f786f09c6a967c4a1abea6ec8561af72248bd4b11f357d694c94bcfb0a8c032019cf6ee3e59f9a6713ffe772f06138df626f59843f91f6cdaa97e0ea05fe1b98b06248021d5e43c41223da46489efca630c9001d23c1cf0b6346a3c982914c6ef588920f6712817ee262f66037ec84601f03336cc98cdf0f42f82f82459e0969c9a1cc3648ad3f5cd79d5a6613e9669cf8a819a6248025674f0fae6d4cd0015bb2edb586885a22310f11d78767ea98320f50ea95edfc9ea52225362c98d1f55ca6f1a7462bf622bd2360882830c7a3789a191e3f5e75ad3c11ebb7fa0c48c5b3a99b399906b78d8ee3305280de2c749d86658cc5fc9ad75383da78f7993c41526f9954b69f84852b333fee6c1e565e2cfce9fc604be1b27f6587f791f786fb56adf6a50eeab7de228e47c009f8b17308eed67dbc2174fe8b583c60fa420c364333e7d632403207e8adc53b1a0504011032ed7684f34fc330a6a05d249facd978035eb3fca09e138ca83f3f77fdb80a28583f9889879c0a81080386df075faa633ec5f4dd56a5f31c7ab1d159d1ef3f31ca9a6be3f11f793ab5e6e9cf9f2eaf393236115684faad9d1c78aee5b8c0007bc181a25e847cb5e2a6d2ea91a5d091c765eb7a6804fcb05fa7c96f5433a22b070c6f67080738f48d28eea7b705270e2c6b0dbc00826995c77dbffc2632169c1b4c41027b642cdd34d3699c5b2222405dbe276cec437be68eb097054029fc541d6d10803b53d5a5ca0bea0afd5f4e86dd4b82c5172954bca2d6e252c70e569084ad1bff86ce062f7e5cde981c6a95cc" + }, + { + "app_id": 2085427659, + "data": "b423cb3a0881e77e1bc7a4498a8a012b58437455e04f597b44fe4050eb42cc12d698fb1c8da1a88cd21597787da1140275a4604445f7cfa746885fdfea22d797b4a7d6260a707df7706f948f9da6ea4552d8bdc86d09ee2a4e2d8f2f5d6f524fde92b42451aa428a151cd69a035b84ec12113f2f9929b073b87898a0d9adc7a86a83cc46c35a154ce4171665430a55d660b79c550ff66766756a1c7bf368794814dd02d40e59771e1ff9c3d59f1c3c09e760a8ddf90300695ffabae00ab566fdeb538db919422251cd84bb919b8644d53e511e254e980cd7fa74b0838e9bb2d78d8769463be4e1753c8fb086bd14f4234baa56f6a416be3e088dc011a07827c81eb658df8c3daac3a505cae3f5c7e343e67c857c583faa8ef169246ccc1bf4d19eedeacb3a5f6396b07e4a986e77070771fb29ea73923891d7b067ce484ec88c02bd041525b028210f125f314d0472874fcd7ebff343ecfacbc1abb420385595ccc37968215010af35dce339391233d3a638ff8d592b6fc361899955691715535c3e8b82a2d4ab7320bf69e30841a0e7f5f41fcce7abe0f9b1ba151e2499e796170dcd524b3d81accc6f2b3e4bcfbb6d6e7e6e2c0013d56bbe1f688c9a4f05af430f201a28e949e98ff0e5a8f8c4a775b220860cac1f42517e3d706252ce4af1f86d54abbfd705cbc058683a4c3f3f162e4d879c578f3a0a5f9294cb75592a5a2697aa22cfab11c0775472e01a5c718d9e8f5e76d24980c041403dd66afb8ea589a9a4a18f9d8bea3b5ae07291b0c192318d78b6977afbb252e68ef1c23804ebb312c8876d1bfbf79ffb8afbce4da13791c2d0d2977f5bc415a381c6e41b06c033c2d61a43291aa41897ad2d27c1b7d7bc93bff7dc64df62ddcca892014511ee80979c5ad38de7a5607eafad746edeee2d9b22c005bf4b19be8cdb0ca9b1ef8d16a0c8b5f77cd9632f0f7d66a90051a87feb589b9cbbae18e9b15f3fed8d13d81860592f1bed54b4c5b25bfaf9a7a5c8466933ad30ae3b64aedb97b657afded76018d7b5a20509dbef416a3deae359d04a62912d1d6418da3e5a8515de5009bb9a2827d8219f8e09604a5e35fee7086a40bc34a01adbe48a05f1d8725669a0364e5acecd127a5871508bf8fa493364d14a5b5a1c0e20c34bb925adc99810d31a5c6fe5b82033502361dcae4675b59eb3da3e89c26db383bb383693994007464569a3aa7cb480cbe077129efc43f4934433aab11cd859d9dbcdcf5d5d33089194e7db69c6b0bf1a9699f60c0ef26757a474caaa95dd198dff9ad142bcb9df3c44fd924b4fc50e20b6aae359821a4e58f55601dc56ced35d272af769e4a20afb8e6f1720ffd2f8786ae72d013b2b3996cb4a72d9d17bb7097eb0ec173ade8c002c9d9adead8eaad18e80783049634b7ea7d6c7e7272846b7ce7baa206b2494cd9ea96cbf66ccfe980ea9ca5650aed5b5bcffb906f1a3a0fb32126d48563d6335bc13f2dc8d38926c5f12cc9a89d7870527d7382a8730075b564a4d195b33835578fb9e4601644912e88228365d6384012dfa3876b652685602d8c0e7f7fba4156a5c8132b902b2049bd53fcf9330c86bdcd2174c5ef3ce9c3363a1964510febd003b4a1c67b6dd21ef6915fe758ef8f59f663af837976a184230542935440a4b64703c7d9b28bc80f815dc9d79f2f8953cf1e82d6e5d31" + }, + { + "app_id": 2231607266, + "data": "cb36a6d8bfbf94e77e6bcb7b4244f36761b0b9314f598b2f68f32f7c1bd3372e09ea2bccba7edbe0901a7df5aa11373cd90cf282a5caf17521e144b17fd519287e86fbf8717fb40930fc1cf8da43d7433037483e884b691b1ad73085b751fe5c95f050fd0116493d6455c556ea0daee80d9ee23d51e023e6a2769df8b84c29cd36caf01631c65bce632f374b015e805b3c91f4c945cd7ed8ed3c848d4216b6022df447240c08ae5351bb8ef5ea557303c20be5159dc7e2ea96ea1a29d441c7b0efdf2f0dc6d701a2ea089652fb1501d857f99b88465f1f487820833ccbd48983e687e4c17e6a92aa90b7698ee1693ee5341f5763b2a588071f625d38f57bfbde989bde531404fe2ed8dd98a4573b4040a3d647dccbbacc2bbb34ed058072112fceb2e26995c7b805d969aada8d6d6527e97dd2b5be4b4c5ffa8fb8e0d88c82f2561985fd5141b8391266e87b39fe8ab0a4b1e762c5a28d23896128d2949c7c57ab849758089df909bb3a9dc43393d55ed074b4a34b5e05f87fe1c309722da96d8de725ac09af0f54b949c7ec8010d70bd9c8e6062d764b6519b9a5487947fbb29ecc8629eaf9616ce007c5739138e321edaff310ab36e69d3caac11d152ff18494ed02b455b9010b19bba14e9b811f8c8dc36de6bad6514cc33cfbb6aa85889c3d40d87a7a796f37d0eb4abf570db6379f46b1c8aa23aeb0504a7bafa06926c1e0d88c0d19703ac6a9baaa91556a291ca842082d8ad35be4008bf08c0e9240bea67f3f7a1f04854b9d09a9c33207fa8d2ad4c1d656a7679f9b3add654076791aec99cc96bf6ac1dd816a6d3f08f2f27bd993bf843ced0dfe4d9ca56c13b0b9d6e6c31c6a20a4c3012fbcaa6d016a22148f0b8a65d783e77f6963f91aff4d00803a420ac9263b121843a5a13ce30235addfcf62848d95279c150a6aa2e20280b4f213d536c8daa57b5b0b8336e82aea38265cf20254446397ebfd4889d2af263bd808370a1d6ca50e5112292e57147cd8f3efd0b6396ebbf537b497fddeb14cce474dff57c903bfd16882ac503d5ab31bc03081fdf58b5e0936699d0b2779c0781aadee4c50289364e3f75f8cf1c91888e05f62cc32b328ba95b0206c7ad2249f38a9fea7acacbf8c3ccdec2b069ac2ba96b624456f1f346f85c94b91a784355986bd327fa304b25839cc2f503d3909c86622f2bf75a0a01c52cec89359d339c82fc423cfb835a6a48338af0d9af723cd07c3ceb8ad13a5ebcb3d50206a4d6b63624a20bae6a641da1b0d526413e6ed900b50d2cb11a4cf69df0fefc1b9d3c1a90852e2d5c812cfa97e30185a6d14ef5704e985ef6046ded518125941d5b29c14e1854a4d6930aa59ce059d1dc6d91d47f5bb9bb9300d5d1807bf35fddce1943941b4508d397ab74a90025a9d6d7a4ad834aa79f320f47c19016e92a87f6a6899458912d032b9103117501a1180a0140047b0a8012e3f63724d0ffeec9111a7cd86c4c34c604b4ada056b2a2aa1ec1afeadc7018b9fe3199379570b57bc74df9ea74f1605a4f5f1f03bad061e8c0f138d2a901da7e1c3066af53b0f6887180d8063d8b9e7d0f934fb5ff66da3f1db60d135aae045d161c7e415aadea944e6749f962fc01e6159b6c871ce6821ab857224ac19c494cc8e416d3b2eb69f765e05958fe0e465dabe0455a352bdc4f19ea76894a70943830285555de6584af15dfa4e456359856b65ccf363fa3662a06f4e464136cb9f7e03c6472e6da8d47dd0f66eed08427e1bb0ad93902643573c30669f4d2c2b1b5b01947144a4285936db4f3649ddb6369420147e1d6b0218356d4e21cb2372eaee4c72a014525ca8ce551a83c419db081bb02d9cd914d2729d0978212dd8f1ad3953a870dec7f9065b551443e5cce33fbeac106fb0203eb9de067f8bcc7185a655a00b3fba88e32f722e42ea47415cc49341346d279aee8d437d837cba2baba3d4e76ea3e10fd13c41f1ba34" + }, + { + "app_id": 3255057126, + "data": "41ddeb850e4f9faf47c0fd5e82f7c299964c1b155f6267263d2d0cdc90064ae55032039a78dd9a155294e4121522c57c9100a96c2d6d28950bd3bf9c0d42b0f843ae2ca9e6b23ffec85a03ccab7826ccc099faf5353b844aee914835c7d02bd2ad65e16e741030b724e5975cf566eac98954a85f2f0e063f93190bcb2f9f638a5c1146a68fe971bee1d07a63efabaed01d415b683a5d03c1019a546ccfad298058d4ed6e930c03242d543d30cfdc6b6c41228bf227246a63080bd43ee0cf6611dfd0d00576b4de146f3a1534c7549623c2b308880870954f577694fa83c0d2be54ff690a59e26971e33e796181108409fc93a7c748df8c715f2b235a83d77f29f1504327bf9ab531a60535f8d8def0d9e0ad80b730791f3c599c56f385e991282fce7ca0de5da6c1955e3dc835b22cb30b5f26b0cd80947b8027bad457d3d997f593f34ef3d0d1f741ce486a02b402d29e4dcba69629425ad2cbfc2fe9d49fbe33bead46aa4ac1abe8946bc0c3432f1eff098f83ead1e07a8d6e4b9540d93e44e85a9db2ec703f05b95ccadd35b2850fbb31879d54ec18b9" + }, + { + "app_id": 3506639155, + "data": "c892f9474e222d50d8333e51fb08c90ce69aa46a574ed5a49e1e4321b7db794cc1190bacd49770dac07b6d452e516e833797edf591c5241279ddef33fb7d7a7f43e418db9f1d53b3878f70835cdd83945b15308dd2522c896d51c88d8ea3a203068fe4e7ffacc30acb5e1c6cde84306f4a30d645375210faf3293559a51871e4ad56a6c00571a2f264b96531d4b3151b8b2976e0d5cb77669a9f1b69f08381c6277d3144f3af1ddf1b2100ffb00fb953a7981e1a6f853f9398eb4a3c0db0b313548e0de4be72f8f876dcd893aa567073f368fba508467081cd739b53f6b381ba0360d88576c0c72ef0ddf355b4112b4834f60932ebc41e083ece51cd11ec16fb127bd06f39a6335b19c9b1d98ce10ce619c7253229fbe34c9f24969beb3987a15811541fed99b5b862d38fc4976f5667cf1550f036c156938d2f6056008eb2defe3bb1fee5209b18cb3f66939bea56965cd86faec4dea9e95a1da01a6fcce6c084b0390c4b0df3ddc410f509dceab6da4264d2c86a024269bca8e4e620a3b907f7ccb2ef624afd5da3b0cc75152e47ad0e05dc206bd602d454323df624affcad72f8b50a67a11bf755c6f23e2af76b63e6b5d34665f481c14ef9f584d8abfefa49955b262984e0fb2d4da8d56a18f7ed57027f68c4abdc8d88a8c90af99281cfed40bb9381780c70626f1e89681401e1b66cdc4c23514f4cbcc2f43e7af5eb61ee537e58205ec20c480d0061fa19d34a8920b142ef7d8b83515fae7570f3e2a4aca0038a5c507fdd48ecd009df1477a7cdc74ebaca7e04ce62654dce38e23f2708e1b8f008578d9064933ec27c5fbc08a6d2baea8e09ac5bed5cb91c137a7186ece4fe0b94ec5bafbe8789b6d358fcd273131bd2f0d5738b133a5f409d515334e2782439f944428f2d729db223ae952ed8134dc4e1c3ad65151e1fffa7e0db78c24dbba3509404a2b58791ec47e5dfb48e21a21ff333d65b24f083c10317bca7a1ac57ad9a47606483140d5941e726028074b6068994ad2654022eb60793999a813eba274daab9bc8376c0e6fcd4fb625496b3462e86b00dc62dbd69ce10c4f15c1e812ce8bb083ff402fa173d3ed384becf2449379bd535d5ea43d616ca2a068af4352f4051b5997a5c839f09172a90955452ee316b3e3df717c6457b32824778bf35c725380014363d082f72dbd53b9bceae659e6588bd0deafdf8347fc73bd83d57328a89b258b29345d8c08c4e1392c33810562eaf328260ef78dc0c513506f226a3f6ab94f428d82230b862b5e571083db9c2400678087f36f88ac38563af3e77656435ca3f4b4eceddde0ed8f4b6d0097264895783ac25edcc93f84f21ce3dca27da11fda51636fe2f43eed3f44f725aae577c0c6906986ec58f6a3fd5c16777c574efc1ff4b276cbbe7a55abbdb6b9994ae087e4ff4f51df5d6f7fb44acb13e6974f8508efc807b80bef8e59ed3a891994990a14688f3d1d037881d18ecf0c2279be68a12c7604763705123aba81ddd474e3169be6e67ab3f941fe16682509d38834405ce9ccc03a405ee8684285ebd51c09eb4d887e79aca7dcf1b8500bbbd0091d7762c995153b6577c33ab9c9f6947c664c57dfa568fb5b8aa496a3a2225c1da3477826cf8f862b09322b4aaf699b8b086b05e9dbe1ce8713cd88884254d42895d5e38cecb6ca1fa7a38b0ad5fa9bc4b3474cfcca26a366f14da79ffdefe412ff806ab9f16cb91db5e163107be002628aea220e6dc91cbc781a0bf74eb085aeef4254abef12c5beff2c6c743b86f17b959b7dd7509853dce39fbb6a7b5d820160afca76c" + }, + { + "app_id": 3828286333, + "data": "1058fd5c9bb07edcbd37a6eaaeffba93eefeba03a356ca" + }, + { + "app_id": 3885071354, + "data": "e615278c6ad2e2c95debb922a754cc4d0fb0a55f85de2554cb9c336c25ec9be2dd98c3bf3c4cf2321df996478e7d10c7acf12bb9331d3d0c7b953db104f0a33c6f80f3fbf5bf25570ad3fb6a7b9b02829d39e5749394947187f981914e8a194ec1b4e6dd053d25d8171eb3bbab2fa7b5aa3a3f65635108ae29255c004143d9f297a59316e2dd83ce16baf68769207ad0deada67c1af71d2eebc9612ce78ce8b5731e763ebe2a5a22282db99e11c519d30b745b749b43ee02b4f8d35b92650ea038870bdca34bf18898f9f2521351a247745cd377eba4d00de0a290ff86274b7f20e33c1b01839a87c96de6ca54cb96e3640f468aeaa927993176a7107f4124e33da379c706e4c4b38d1d1c1e112341b1424e689a10e7cc9626d90437fd07cd20fcfd3866a1c493b3ebe37e4471c2f9bc1957ddbd540ed2f83fea4f5f9f567d0fed776bf17481912b9548a23900b653388dbef4b13dbac490047d05a73d4759b148e490d842ebeddd784a4fa12d5d6e05d7664cd1cbd30a5a3e379a750b13c7fe4fa997a5ba038db884fc34a816949ba9cd6dcdb328a9aebc48bc78cedc89243f5300a06d218938f6dd2c6b7192abb22822a1a3554eb93e6631e43004aed719726741dbbd6349045ca08238dbaa47085573b7db35ee8acc33fffa860db2a7030d3fcbe59b2676f03560eb2844ff5d4e2bd03f4ba892c757824b917e6489d8690866c0abfed6457e0cdd10aca947be5ab989de3a86826b2b4a4efe06da83970196da991a189a1a1c3b779017bed6ad957baa979a3663a2d679116407078805b9235620d7fd8c81a889c6a184638c766c049a7b43d14532bc2c3201d1ed9215a1fb59e373f258499eff95f8eb7b649de3e07197db2e7965f44881fff435ff21370fce65e1b15c329bebbb53e4d161f7813b4a920bae532162ea69b06f15fc42a4bffc84e615b05ddb4f8d519a89531632e8ba37f3448ebce7ae3b725574e4e193e02894a511f73669594ffd7c2dc2189df40511d8a18b3603086b1ae6182a00a59a5175287967fe5abec83600103ab227734bdbb6dfa210b09b6abe200be870d0aef6a2d4482e73ba61a4c15f26f0dfd264067ca6feccc5ade7e4f9641d3f1a52fd746c021ca49962af73e0e679b46cd27237065dcef944c2842a7036752ecea10498d408b52e683e0f67a7f7ec89cc06132b54a7ad28678cbcc5f3bf7ce1cfffe3fd29aa5fb683eec929129dafe3d0170941124997090c9a2d473bc82dc5347caed90952a91520948c40ec4022b73e7ba47de045e02f7a138f602c9ae01f46c4274cfac6aba179ab8a2b3ea7a8e131407911b8eaae2822bf64206407e5852e7d27f8a4f109ed4602f0c0760568847dbc028f359970dbf3a4634628e58c562b4eda2f450b0cd0e6a3" + } + ], + [ + { + "app_id": 75043118, + "data": "ad4abd4afcde9b0885c9b62329a7e8a89c81c5782df83fb233e12832b6b90f612194b2e51a5d786b9bfc21410435db18e41e96eb2dfe67c969b86923476f86011de95c6dd18eda17b0e8011bc26843f07ae3ca7b481444d768869afda07a2cad07d45cd8c5d22654043ddea902253bab2fa2271fd13a5a04f396dd4d49135d8489e554517d1c352aa87fdd25bba6fa91d75c37a99560612caf1691d039c04d7e79fb6e2b741a6a80b5f4e1078ebcb1ed60149db232ba2eccc65a4c85c9b19a67e6d95416f1b5c0c3d002b99e8f9d321ea07e1e6ec818996d779206158f94d2a9935544b52128ad5ec7a6153f3e0c38f3fa48c4ae5c27f1c151642412813069cebf902b5015ea22da450cb87fd8a6ad9f40957741ac1e9587e40a3bb256110bcebfa6df404049b069932c53cf230293f0cece8abb3d199c5a3291deae4ac493b1d861bce6d5704ccf3ddc82ede8c60c187ca8c184bd94ae71f4f0daf5ee06055d6a36a37ebe447e915325c12bbb7a9b6850899846a539aa8e2c404e397d165a113e829cd0abfd5dbdcc8abc0ad92f9f95dee19099c680431dba6aca58688b3db5745084f6aab71716c49bc236f000c3c3282263d849ff262519151dcf52dccbeae964f01d49dfb659fa22e1f8d6ad3b85c3d1a81415470210db4524b1cdbe353cbaf28c0e9b7fac955a8adaa848c4c12605f26f2f489bd8aa5fc7ea0aa0788320e7c567aee8921c420b32d67826a8758826ce4821d22bf513c71b58af910607535ef9c42cadf128af49f1aff7fc30b9bd4ba5be66068e7e9f8af29d1debc37d457d99468297ede0c12a3143a5fed2f3ca6a42d3bfd42f549e5133ca881b46571ecdbc20af2e0c479ea0a2bfc7e12761f8037671b5cf8c1ec5d452d6710a6160ace32b28051f246d4780d7f26f0e30bac2dfe174926685b2c8f523dd82e2a520d8a703d5ec28186cfcb29152f6a3507543d67caa3cf2b44781be11c8a6625e642c96c8177ed92e749a375f24882c894f2fa92b1ee15a90c0c4e24c9cf36453f7ad4d76239eea15a9d09c147bcf0e5c8e35443b445462ede3f6176cbf6149c01781a861f9bdde9bb292d794cdc97ff028c6e6ecde3aeb917761f758e2f5ffeeccec6b54ea8ed7c7d83c9ab6b352ff627d4ac271ca84b841c00cde81535e3c519262d0e2080b46eff8f2c806ca29d0d77c7af8e082cb19a8d86fa51cbd70b0bb687fb58ff8d2d2b4be4f842424c3468e6fdaf24794b1078c6228fa28118ac731056cf663d5e0f69c60c6b0891987d733ea5d7cf4da26d59b552f6202da64e34215df24b8f3b522f7771127a7fc1094476bb264f780e12f91592f4502d06dfbc9117e73bfa2b6a4ce14580ed281613b9d3ae4083e3d3b682807326367a94898d9991b65d428da8e30dda697b5d9d4eba36286f762f0cffe7c85ecfc608c8724530ce5f0efa2ea0aa9e04076453e5c48c3f9fe82b19be84efe2248c97019ecce62c6d264b59248cbf754230620573380c7dd6cf0a5f59288e4b3f4fa59a3ec4cbb5a7532fc7414fb685ca4ae2c3f694a9ce6eba023be021403f4b607e58543a63971c80bc433d63884fd4534c0c42ead9b46ee401bc64e96bdba077b353492c0ceccb44b848749452ebeb37e4d41129a957761809f2ac837722ab2cd1e66640ac2a7d9ca14a1be882005d1491aadac0ad4e8f22eadb6f3864b0a6d13d6ab4a7998b57cf061864f46b5f1f7488b3a09ebe58c7fccb658e1e54671039ccba41d62259185e9a7448f7e77b21fed4716dae5de6991d8a6f7a5f25c899dbe4287fcedac2b0826608aae1df7b7082d2e3beb685225ae29ac170275771e244cde347036058eee2c3b570e123b62098de94100ca9269decd9d0e94b7ce2c02aef3f2dd27c09d97083fff75944c80c7" + }, + { + "app_id": 237249942, + "data": "35b0da313cc09598c70cff589ac1c602da0d9666984b608fc85a5489ba00344280ef7d76d9c2eb81bc9b02e7bc4bf28c721990d8abc078f5ac586fffe376fca27088bac1c6517ab07620f6da071330d9bf4e099251552af717e4a62bde4e735365a0f8b2c08ff69c90da11e1a7cd28cfe5cb90c69d206fce9e93191d388bf57e7e1e76665b7b555b7cd83674fc1e240302b4a02a0f4a1b0fc3c0ab45677a29bbf699218d140e397e9ea9ebc81fdfaf458deae0e0b8a9299f8262852195e2ae385a1f4acf14536d9ad6c067cd64f2de0c97d2a198160b57d6f8f8fa5274c80490d3ccfa318fcf0312355e2d6e83a42c9525f970854d1eeff138b2e94efa5388e63b5edc5c3ba343a0708e2a422ee8db6906a2f78025539a1d3fb6e700c0d70c65f19d7214b8a57858655b653c7e62f0a77ab287f9489a6891991d575b4a136658d7233651a454fcdd7366062ac9cfed294a6abe5a6868d54487707e24be00dc5b4ca3ab3680055a62484ac419ecbbeace7848d34ce69a25d4c5706ef8409daa54ef22a9b374ea87a287bb9ccf69426d2617b2a6dfa21e8bd5b46ef55bb039662d1d198084d1f43f1a6f8ead73534ac063e3687458bfa130d2cab1bf8e271ad014ac41e23711d47f6e4fbc5fbd53940bb1d5add280f3b670a24f6b04c2dbe746bb275e1d577c65fb6a547333f31593f1148b4b51afaf60989f2001c30856ebbbfa5996b1dbacd67c9bb010d5fbf77098db3355ac631fbcdc62fe03e673486441d8f4311e727ae6c1e1019c2179eda8781a6018ff9bcc6038c01ef9e6e60b6ac47328a0201518ccff05907a6f8d296f1a4bf30b694847e912d2b08f026963e605afd0eb13010fb811ec564d3bef297d2a5ca3139df5217e0dfe9f9a9d4e3747db7b722155e6c06ff7d679fd17db6b450cb2313917331d3a538cc63d418f2c164d5d738ab9a6205045bb957e685917c0011db3c068ca51b869e057e1e93fe23535ed56b5eac99bdaf92bf938594c18a15768258fef654fc7ebfe52d4677d2a4418260c7410590ec05891c33203a4e9bbce9ad71d2b1f6b9d649ea1142a410b58bebed56f01bedd77665f2c62a74e488a044d68c6beed4e70a6dba62cad1bb4536277bd3627f832bd88230405615ae29620db210664ad3b1f18c6eac9ea94b34c371799ecf7b51a7dcbf2d2bf1702d7e5a5e65a32e2a8355d88521be6110dc97cfacaec30009081db04ae49aeb82c228e93ce24524d3bf1ccdfc67d466a0ffb742bcf53cc8cc8902290f9694a027f70f2fb1d74b21e65ce05ca8695d82c15835be722c6a8ee28da56110f89985d75766d406ee0a40fb5432131779e656ccd16d992decc2f417d633eb5601aed906ce63cb3461e97a03b2763ba818972fa4554fe0519fbb502795b44590919ecae42e201c3cc3edf479f5e3e54031a81060d8687e5b88875a6c796c483ad585a04eab0de1c858133f5840479c44cca5679002f4585fbc7c429e7706a66f405721fd69d39241473f666df30d742115779712d63342ef197dd1a06dd7fbb96c53f46ac4e57a934a6b26ff66f7c73ed8e5c2d090d67648fa9f6f0fbcc428fac1b325f35d4b775206eb56cbcbb07c70635ae3d47fcacfe5864300f6d4e8d14a04d272a1fce" + }, + { + "app_id": 554175156, + "data": "b510a4a0d25905790b2641b6f08015195f6ee894520f62d6c403e3d406168a0e05c6eafaf69e05121f105226c9497525362deebc047c578c7afda2dfdf45c2784a743bc9f95146ec7d864ce83329ba12877389f95ca902392676ab1e71fedf3e6477d07a81d15e13ec0a05ffb5e1bdefdfa089cc01531a2159f78e445792591d6af4dab408f45fa8c79c5ec4aca39387ef7d78a80aa05b887407a204f4dfcbbfb335b75da9bcc29f738acec3d25bfdc133fc6b86696a891c1a0b4f7cf4c389e7e6270b75c0ed7461172d4479a5950f924aa32e5414ec164aa433c5dc853b73d243b794bbcb7849315b46c45fe1f73d93a682310dad5b587dc4634af5a06dbdc1c03d51837cfdd46b111ea396b6d3ecb417d1983ee1d126c7fa483d648264b6ec447b5eba1c2978112da2a6750b661bec69e95594bd0e19e9ff97942ffea3c5d74c224bc791592f20c6b8e05690f5305634aee99dc595f841043f8fa856938a70820b2188f8cb4ac7511148425fb3fdcd0dbb8923fec648aba3594c9d52d27bf58b0846370a69c00bdf1fa26085131dcf1358ec108529b07df3238dc37289609dbc4438ea2f9c70e392eb62176a479312f1aa43a7879b5f59e1c28cd3a840ccc0a2205045f236d598eb6c72e5ee9f5a14a44b52a60de58894ed5a21de056c8085391140be0a753a8915bbe0257893ef43960ddc3690732455c9c680e79645edb00eb0da29020207181a82410e31d566f22b09f064e8eed1c33b4d0a4d9c45e155b56a98fa7f76db4f8381e73d5cfaa5ba128fd045e251fb65fd1825f5cc709ee7755e794c21a961cbc751060ccbb26d036f4bee41b7726d394d660707d97aabc9bbc20f2a9ff274b3d230e8baa1c5fc897563c1c50b02decfcfe18046885e8cefd17a634fe6bb11f49a27e48ce0ecfca3b888810c01360eca6f2f10b6fcf9a3c7caf59ceb228b2e51e43d8e3abb7e50930ba5354074f3a060691b731eac5ab73f150e3c6d9458176871d15d9e884bd4daa16f9c873549e73e43cba6578b18974c7fadba7b09d17f703f05b11d94777c12269a57ac95aecb612496fd0490a4b7e5c368f3db9ba53e04066bc7b48288ab3586f1b0d3787fcd548e40ed72f5ea554fba9b20fb76c066c2bd4bacb22fd836ccfb497e49563801116f1aa2edc2d630020fa48a66c90b6e032fac03cf0d6c243e5b81225612109633f9c7678fad9f750913560fb1098edbde9cc325254a7e2f73e6b565a8a69f8542e7d69ddfa0f9bbbee515dd85f88662196810f39d8fb9d7ac1a452e7be0a3f80b90f7982db0b1f4e46d69b4a03fad52b16e8000b888a7834d760abd2706d641a05614fda3b615631f5de77a000f6a2f979053308ddc51e6c1a12162b7e7e92915d460e2357e527bcda314ccbc278bfaf01a1b6aa66b91b6e5bab7c84e9d6a1a83030fad2bfa37ae628576e6d9fb7a1ce87c765d18920654a6cabb2d0528204eebcc99fa60075320d1a48f9fa4dd082cc18688d76e16767e3b8c430a844d46b0ff3b039d9904fc94951424b55486f0cd0205b1047c80c229113fba5556b4ac78e2e1467c999c1829c1839cfebf3fbae4c962a8866cbe775c471930634462166bef749d1cbe8cfdce1fe1313870c4eb5c5d076d38b7aea561273104a4ff6703428b3b4669e6ddd5613eb4758577627cc43784ebe954f5d85a203e4da5596ac5238bcc60a721c1fdd55afc8e529b3da0d1e5b8130cb19fea58b6b9f68dc45716cb331cb1f26bcf6b8b7a9774dca19448a0a73eb85c4b0f617e267907e9750d4eeb2728d4a8f76dab2deddae0393825c005d5522b86cdc007562b542123bfac3551fae5daf55b78fcd9e5c617d72544254609bf34ea633beeb8bd6122123f1565bc65c1758abd62a947767b156e955cbc99eefb9fe1a4aa9a0513e9b88c7798b38f96810a0a9cd074eceb842c3440f2e001704979044cfec9154035ca1f82ac28cc0cc64d77fbd6732890ba73d86f73adb79f063e8f6c033f51c38e5d68bd8ae7b6f9d5212193249b24f6e7d74568826d59e5f87b3237a14326cbf5f24108a89fd6ba2922069c21b9e3fd6a60215bd725945bcaee6c51a22f9f30bfce0fa92a467f68b47cb253a6482dfa329ef8a6d3f6" + }, + { + "app_id": 652717895, + "data": "98362e720ac67151052183f17ba4eb81c7c0ba767aa1ac37ac2b399899ca50bc1566cb8a08a08ae1b26c7ec778013f8b43996a86f780ac9c782f3d1a434d28617b996d3c1a58f6af6c9a35eb66cd1bef82f4bca8d89b9a2c99635fdf230510a77aab0a9497d722e73822a226811ef9fc25827ec09beeb70b5ec320602359b9d534e124b595f6639bc156eb10bc219cdb92f82bb0efeba14047ee86c7e3f01044ef931d6a64af48f6bd461f9a20aa9bc5b2b19b5590cc54dd79d1b0482dfe787eee14a00bd448779403fe0ba42bc2f73b30effbf6bcddf1f715cefd5416e14ad5cbdbc7654f5d0ef37e1289da6d4c57b377dfc29e93afb45990b519d08d599915a927f05b0403d53c6ee925e01c8a9902cd2535916aba6bdb26a1ac1cb9d54e8bec3281cdc48b529e161bf3edc98c3f85ba9457db44e4060fea108c58158e0f2940e2ce9e996739438de52e59f1ff5fd3adc63cab4a475b532998e209d4720337b24b6a45e8152ff626e425ab3e7159d6604a1d342259838bbd50625c71bfd0d4f167ba2881d8ef2d4c996716b8fe6775f76b6d09130a3e3a175af3b35163a4279811c015a5c50b6331064d1afa5395cf4265cb3d8f7a921d37893fcaa06ebd4462a09acc6e2cdb747f4891b9c780e33ce2961d7b968a03bb64b2d832139515af074f45703e6159e90f27bf473eedb492a8691ec0ba25ddf529536eabb6ec5ca977d328c966cccf655d1341b2854df6bc6811f7b7763d254afb68bd2bbe06cd1988e6def8827fa0391a27c29bbd1e8443aab008c79f02ca155ba5a1ce8988bb5ad64e9679a5ca7010a7cfd3d960618726963a8d7df458a21a001f59f0f9ddc0ede830a3f5273d903717bb2789da219541c0c0c7d8091831376637a551ac28797ab11219f52a809478da5575109955bbf07f43132f150e3c17bdc2fe550390123c9631a81b449d393576e04a74718ab1f96edec2765ed640dfe4836375438bbd10d5903116244dd31a1117c6649df40c13bee45bbb6fa135e2e6fe733aae257b4ab9db874051fd9ac29dca7f8438c0ef2907d7d1353dbd0ef61acbc8f2794e083346e09fbd968a8a56a73756cf6b346872b781c6b1bb9b6801cff514a0e308895f73ce8a0468d7a64ee9e1e162002941a65bc8e46c07786cf66e51d9ab8777082d1e5d84117cb879f554d1fcf810a8ccffdb512e9ee177d6b871af0be3f9ec972c85ec4605ef06c6b2a760c679bcb5d269cb5bb63acee30bd732a153c817f1b2fc80188e762251215472480a7af52bc74004ab0cc5abf8170e32cd74dd37923ef9e3550a0ecb7c22b18eff4cd2e1876e688f2cbc497cc98fe02ab104c63eefc592e6e413917f10defb4d96f7cbe55ffdd91a2fea8c5eda3e834877bde98b6d81e521814401a21c6c57395de424abbad71a4fc21203cbf434dcf12d3f022f243b601b4aec2744d3ec9c758d02242075f9835c081221ac67ed8f201d19d87fe89e52d7df27323a9638048e343e03b08c5b9f3acfd29bd8aba4787ccdefb7f6e42ba2445d35a80861dcaccba6e24161122d2aa6610372b4b8080250e679eb8a1f0668a6f3e66ea21b80de687e3fcf6f0663c3815a1bac5bd044e90b0171962140e090961d2d8284f4ce7a52279ec098dd88fc2ef0df718ff5090ea685ffaa401f2134775b469e5a315bec4b11db09c40bc7c2592f0c057d8345d4b6bf9bde371750da6a04331f74c7f7ba57ec7c8df047570e65ce1923c3dbb3ab8034b89be882c75b20dc6102ef5bfa9c77ce0dbea3ffdc3ed32f294d31d1abc53aac14060123bcdde3f9e818d8617583afc518619e8b4291ae15cdcd85bf33781363f82e122eff90f80854f55d9f9bfc26b2e09982027c452bdf21ee8d4ff43681a2643efed43f79128f4607183fa31ff4926a7c2002e00a8bc3cc3c3e2fefbbb3bf0d9a263f3814bbdb2a7ff1162ebe656318358f93e732f440004e339751754dd470119500ea5c82a0245f1d2e21eb1a046134b017d7931d84d73b139e6e46f7d6380a9561f2c67a2e123c9a4597b617876fe1029ac12765ac8cb2efa1170c929af5eec39cb86849651ccb871d4097bd493f3b605f39daf54594b051b686492ddfc252cc3f79ac24246263" + }, + { + "app_id": 1104624959, + "data": "1113b808ef2675ef89058cf67411a9e8a9352eaf7ad5158e5e407efe02644403e78743feb61c1ac56d1ba824dd6c34c464abd7c6de0e5140e8bf9781c16a5314af77cfa2765d411cfa077ca3a3725d8efd2fba36521b18d926a553e3f51c76264d8ac65ee2d33ac48c29051abfc280" + }, + { + "app_id": 1460565589, + "data": "ccb41188cb33352b57c3edb78687167ee38c7111833c4b7faae71e905acd5437574268b1c425c194291249ff3f39cbd667fc65d74354a5ecb8792fb6a75e27cbed3862556b22332afb33ed7531a0cb9dd619f1b81cd6509f8e27ead2440f3294d601fc9f5969043d00b758bc4d98de01b4531a613bdfcf95683a2b3f1a67596ca14627c2cddf67bda02edfe92c0df03ebf2ecb42ac497f1c229f71eb7e22d9024d8c3e45abd83921151b1bc8ea4d8d6ecfc79de2539eb3db3eac67ced4294235a8c23b1ffa4f10a7baac071f0ffb20628ca85381dab76a99befa2e86b70b37e0215e942234403c17ad68ea32ffa41badb2692aafd1342f7d9b2fb7ef7019527eb073b92ded03e84b44248e0ba03cb86b4efef34223be43afb484522757ddc3eb1051ff245b1f39b543eb05ddbf7e91ba16b806294e0e242cb15cecb0f28f4df8f4fe535ba08dfaf03776bd53ee7f68970b52704c2434a5bffe7559f5519f10b31d5ca5eefbff534f6568cf8276d4d3e975d51a9189fff8f13eaecf5f65b3697520a1ff80d86a58f1e8a4ba73262534ab7f1b9d9b5b2238033bf1d5819d40c3f684b50f270a72f4ec5acbe94162b5eea346c6dbf6c1a679e502f3a4c8436a9febe31200f883d3c0d289d23f702bbf555fdb5cad3178497472417cba7fb70d94f5ad32b87b937c89f73731d6aebafcb5d54a61afbbf601d322dcc81b670d33cf9bb153c3ced53cd2ce11ad61aa267f703939562577517670808e1698e1f965b857b49a6de72e32d7dff3a8601f733b8e955575e5da6920ca1f3505c9d09bcc67429b4252c4ce13d798bf79083cfd7159d7a39e937f879e5016b67a218fb177232c910b6a3149f5259e7b58fd5ca85501e1f2e9d9079ce2791adfb2647d620c929782f45e49a3092c14dcf1fb9b0ea4fff5df65ab2a78f211f21dfb89fcd5ec1f181d821bbe12b347eaea677bf7058bdf8ca348100e18c09de851c27e6d589c8ab8976fc45aede667f6188fd19158f64b650a8a0894e9ce6f3a035cd333fa7d22b6eac56d380bff7e1614e4eb72ff27f5d579f56a85dffb1f98790e1fd769e741f99df54cd988823ac7e22f8ae9a9d1bb5dfcddfe557371be4b47b7ae6fdbc8a6dd4eb3b3be8f1bdbc90504bf9274ff72221102faf2a9e0fe3dd69f65d52b3ec7aad864e0971d563e06154c43" + }, + { + "app_id": 1611396816, + "data": "6c98ff14bf46d39786bc6f4dee9c80e346c67be1e8c295879faafeb9331bc6c137931fc937948941bd6fee58de2dd2cd4cfa2333bf1586fd477d9d02b3d7bde788d0a5a6d316cffc3dd5fe65612778bd7cbcc1dd9211130ad2a66005086e59b4f39717f7e43846da1f4a2d192f6d4d4ad431e3adcdf287222bdc693e913e02d62400dfaf4c6b3d5a635a77ff40b71ab06cdce7da303cfce648dd711e7362b2479c7af042be174ba1c60361daa3f1e01be588238190a3429a52655ef2840aa9159d98e27c155a4d41b2af8419b6c65da2f265ff9e653552703f59efb3ddb8b337b2ae62d3b361d3e94139b89e7d775dee9076aab9ae254868a2a06af8ff8291058e92e0bd68fd3f1f49aae82e0be37bbf0fa52e6101b606d41afe316b1ba77f62ba470292d09d514cdb115465d38249cc4102f9d50a9be8b26170d0d057c23d595a5d2e7d7890b6128b8b32da1697dca65169ca19c3d7a7976a9c0102460e69bf565a855e5f83d7e065b1ef48ab3dd61a881c5a574e4ee80eb9189645763e691e772517f36bfa9c42b0caec8b369102ffad3a45a541bbce1f19dfe3f570c690d3a4e91468b4077c47f0d15d412646218fe1b3a0a90c445e8b74c032844a032034c69c21a4a8cbc9fb6695ee8cbfa1afb33494d42fb39e3f62df00eed81c6b8806a7401c3294cdb732394bc5b4a3ac7c5a289abddd5050fa5b000f8f1dded1fbb477292188ff391944e76863992447061efba7f18bce2a194040fb147097f9820d9330e20a3e38f40a63ee36c5ae3b9cf2474530836fbb1317aadcc8e21d981989de0caa567213737db6255c6bc5a4551da1deee308e164ce138ba9dc57ac9be96ffc034533f07851c7ffc94ea54f530f1f1ebda9a5e126905d16ee69c1866df2a5d141795d3da86ddaf5d6b967a9fc2c78811cc74f30140864bd2a08c532ad22abc641da977b68d3c2d27c573756b443aab5df80c105d8ebaf20b22fe028862d5d8f92453e5c0ae810ab9e9177070d6b6e5f2e7df3a695206db0f8dc66f96cc1029489ccecebad45bbea56b45bc47052c46e60bcb112009456bfb09b11d21e117bd8cfe6c79648014b2c228226d99136dc5921ca5f29469e250fde6cb2bc3691a70ffc594aee440dbda4053b9fe9c99924c584ee639634562a213784ff70d3a9695a0fc0c8c1309f2a2bd81d869006e40425f94d68dac090453a7f6e93d5c5efe30048261e7fe7151455c44f47a94f8e6e9c89af288b84d397b2bdddd2ec304f2ba5c5964d48301e631f0153cc6562f25fd8a7d902d3a2038b84004e6647170546c63aa7db500097f79912bae110f520e5f8b3285bd4add7a13313ef914dd0221fd838ba9d0a04da705610462c79448f565276bc6e078" + }, + { + "app_id": 2209933717, + "data": "579e1f4b7be2155fa1930b4e5ecdffcc8a9aa8f7e694ca4e55a841c6a3486b282364f52be970411710600293a55431d37f869b62542a50636874839ed86218fdf5696afc9fed40f220bc0c6063dc7ad58cc6c95bf8c627f9f15a2e8b0c11dec18ab6d80454d8e03480124250288bdaf5167fa5085198ac72d5b20a092a283bbb50aa44e28c7c627dcd22a88ca99c28b65cfd243280c3d9e43b67424a814cea9ccd3ebcc0ac08afcbdd0abe561f390cbaa92f0212db1f040ecaca850aa09053ba62da6927eba5cf7d7a85b22ce8bc29152680980a99900d255c44441a3f080d6a7a0da4912518279f55e97f4d8e4b1d5c07ba769f5f3c4d2dab8e34f180f07e7709e90059b855d876ecd86cd1551517f5eb45504a22de5261d6f83cf945ec2de39e00be5157238f2a3eeb4a333fcda94d9f4e6789122944254925b36134b69128dc5ec173d98ee9817f2c6a0713285af92c1ef6534a8c95515edd452b765bc61df32206b4b84babd73ca6e499cfeeb1af37f07761e34fccab94799d3c67290c78958b77a933f1d76cad17a4e71456f25819c6fe94759331bff7b29ad8919f935a9cb55dbce91bf7d0afccdfa55ddc2abcf89406a1bc0a0407ce4ead2c2c22b784de7240b0ce12d861a744d7a4e4c320d18071242e8161409f40f6294676f459004b1f0b726a0b0bb379d7a8234cfdc86ab0440a7405b04ef81e38886a59a4eaa62796bb023c6b59397ea41d4118d1985302fd1593765c871ee87c72927d7c5f0a8f992336dda1bf0440c13b2eaa13f56d63978578ebd746d40d3c3760c0effe0699ce6b8d9bc1e448008babea6fbe92cf414eb21a338fdda1fdde9dd91a5cff689ccfbb37dedee63427f507b7f5cb202826f6ff053f80282d4844b2dc7f9924f8dd29e0d8f38013ddf2541b211d2d50f0ec7769ea3745c133346473c3b7e279c9bed03ccb82cb752518a67acfb1ef6aef47c9507cdf84af79fd989fccff8bbe2324fedaee56c247ca9217fe113915888cb4c9def8616f622a5cd9593e110a891c5d4797609b62eabcbfe00295f90f50b043693fcf23ce7d03da3d70eee4c9d13e80311a49f529fb1cd8186f89c37a045e3e7191bb157530ede14a3a033eabc42b7d168adc9743481471fd2148924a0114439bbaab6371c9ff78a3dca0a959d4cc492c2f25f97acb33956ec269e75ac8df83cd3c0bca5557fec8b398bb7e9b0f0975bd6f429a20c470963017ca7a4af335cc3cbe407bd31db208e9aaa21ec485f7439b711ad2a7fb843b799ef88bfa9f26f30c8a42ff43ec1557162fab66b29cba56a47cdce44f7a4915cba463d0eb86e87d24e625f457d2038fa34c3e6eee9fb5bbcb9ce8fb12c82b57d0196ca34b36329a99868c572ca10b39098852b8d56df42e72c9c026ce285248dd093fdd2cc21fc185d264309c988defc45a4fa0f88f99c299f1f18739b72a35385f07baa94fe1097f3276a1456123a13b41b43f315ea7c801a90fcbd75bd0bb25163fc22bc9c5500315c1726c45a6013ea6d0f746b7a8e67a3b0bbf2b473edfb6f98ea6f91bba3f034fe96b4aff5cd310a782530305dbf6da4e7704c63aae877c3ea8c8a1faf73a277f5d1998e78ad6f182c85936f3b1f3758165432d13e852423a878dd6778541c3713936b055319a715ad3187c531db3180bde740066cfd8b922ef500c82c41676d403225dbdf2bccd32955cbc55bab749f031d4efc3834c9d7599e3bf9461a880f2e0f040de7f171057d00400a20f08b9d470a028ea3fe971997262a4fd62b13264d02b491f975c8053831307a414644dda482372c91b008409c13279aea4eba3e20118d60a9147cb9369d4121c81b85309dcbf82f22fbd9c79001b91095b6924bc93b423de6d50acbf78ef0029437428027437b16b0dcc9f1ec1db630f95deed06174f0abc440f989e66c5d04e9f58f4ff6e7702ecda5b8c5a3eebb239ddac85d4d7beba210cfecbd1f3e3b9eac140302914d7cf722d8bd7c1da0ca9f70dd98e8ae13dd7f7063dea38472072dfdc57048c2b54fb5b0d0774d971d45e443d2e3259a0f30a7145edce7a9fac3148d64cd4ec0202beace20d2d381c02b9cb07fcfc4efaf71ddbb21aae01e13e5f9bc12d3371a296d9ac775afeca05dc4dc63a4f24ee9a58a95b2c05bd53990ee3af10525e7eba72765fe94871f638214b1f7012c058819548445e8847be24b31b25ea4be813448b0276c4d9ad066296f00d0f64a79ca3ebafc154f2ecbe81971bba7be9871e37a45a59ef37454d723684a3b0c8149167fc52c266673e91da9b95bf86259d3daab5b0c4c7b8e991e496faaa1c9a2ce2d1d668ec214cd37df05173e6d8c94f940187d50708cce086a66043ba2ec4aa38dc9cda26add5f923807c9c487abf3c994e062c99089b6ed16d6d01d7391727e435d4e40d1e23d0dd5905939abe36b71e2389c644dca8088a18f3303a851dcda938ffc09e5d6e0d6b9283a798e40f51a4587fad87e7514d5e2f510ff304f06125b1d45c170e7a66de9329927150c835d3f410ac834f61c2c0bd20b3d1c0f6e50303e87d49cbc9c2c6518bc2072eac5e6f526a7408bc0f7e4ca34da66add82150e9a2f5a5d7977d920f038a50dffeaeca928f87ed03ef13df866ba67e472c0724ca470d7bf02b8c48eac27305b9abe74ce8bc174f3299ac0941400a65936b8eaaa6a3f4339bbb114b4b56bb28231bb374daa19923e28e3ce552d38cf218ceccbf8ac795c0d8230ed5d47463a9f69e3b0e2e2e03f8489c365ffdba83a33426147d0d0abcfcd2037b96ddf283395f8679285063c39529d7086c1a64f45b2aa21b2f879ac34b60e7a6a54768226d8441131a60abe5e5ebe8e394af1ecea60b97640bccf275801185c83e5c0" + }, + { + "app_id": 2355063471, + "data": "f783115a39bb709592eb2197f6ba940ad77af14dbd366287ad353005d88ee023f5c93ee9fe3e816fc00ced35633ec3f9b4cb058e671547886b41c63f0f5a9605cf6f66ec689f6dabff294b8fc66e503710ef0160a14ebfa2f7f1eb9ffee24bd685ccb3e175a384eea22e2567a12054c4d599cf53f734a71732c0dddbdf00489a9bf08417303f9318d5a67bdf1789ebe8b812f257eb17ef251bbdcd6b158975f5f5c54c72aff3b65eabeae98cc7f93acb0daf19ef032044ac7563b0e0a7d14cb6abb2bac1255f4b14c8e8fe9fb9bf2b514c55e867076ff2be169f98ba59ad6e2267468befa2c69d448e909ce229feff6e7b25fa817df441e43cfbeb7dd75f84a9c2684d383972b5e491a870c6a1a85a0000a075bef3a974f03a4767f20ccee96aa6e15ab34d7207984a20cadafe3d1d3b7b4bb2482690fc09cf1c09dbcd7b44fc7001f103e71544988a4a52d4914b0faef9c08c1deedc147f2c3cc122732f32189f440b04782ff3035b9fc042ef23db788b52e868117dafbb1c6dcc358f28ba0df29d5c6d1c48e77eabeb742c73fb7ed12a057601e1b767745b6627bf2d31afc32172d27c" + }, + { + "app_id": 2492217952, + "data": "70d67e1aaeefb4e48c299a0240e8c5b98198931342344b4f5a1f4f308ece1e10dfd7ed93aecfe64390fd847e0208cd2d266b5fde7e12ff6c312150de9d1a30abafe8654b07226e7848280a14f5aea982c40f2dba6f17bcfb471b9bf4ddea0eba72cb4dd2f4dfb9fa935f576bb93b3e4fd1eb1b4afd33ed1715e567becaf3ffe3516c3a099582b9738353a7d9a099bb88e46af232ee19504d4d25db3252d20935921ae7f60c903664b8fc88d84896436bbe48dd" + }, + { + "app_id": 2802187347, + "data": "5d59a3919c30cb537c26fdbbe815bfa829df645fe3bb2102165379f3f50b1f47c6c47731311729439c2ddb17568ea346ccc9f32d1a67f9b325de5a9a2a6c1179ea22dc6fcaad144819daf387fab46276c2bbdcc7d0862f1c0d6f57a8cc7a4cfeb77ae4a81ee76833342453e0761a675fa24d984fe5657aed7eca76055da5c8eb0804f002a744d0188e6752a3c4f7076766a0f005a6480b03c9aca79404fdb83fc9b9af8312a346c7ff940242a80c24c231a3aa556f3ce30f4a5e53421037af7fcb3b14899adbbe1565ffd2a95618918c41e4ba7f469e298d6ec929f211c80f401c368e82906cdf4f514ed2ebfede7dfd24aa84d613ac0fdc459d56f2bcbe0096a431d829d76abc21eafa721bb2619bb793c67b951a283eebdfd0e5dcb4570809ac65137b0a428335ee3465df582274bdab2d7d502f70827590c2b7ebc5cb802b05f6ad3fda8443497920d5f39d23c26b374d483134c3efdb8254cb4aa1d31ac8e7d581cbe364defe8bb8c9a38b82972c07460ca5d93d247de2b57335f428002f93882775fba1010fae8b7ab704f8c3281ac2c7a671c8de1f83eaf1b4d23f7c49030facb43e1c6f837df672eb0bb01f7f1be60198c31785b3f4f743e721be9458cc29b9dde90680c0f332c3dc49157aa0fec1317a546ed784d6b827d60662e8a083ec2a36614abeb8f9a0eaf9620f7cd4d3dd2d6282d8d4bcb3ccd05b215fa7c667f14cab10b0ce1422b79ec55d32084a5458334a802efc9eedc73682c85ce8249cd922a5735f603584f74d0be6d108b560c96861f5f138d4de147942a8f8891052b65d9d5085c6a734739243e058a5fa35f4ffb98aca8eb5768e5e382ae3c2be85b8d8f55f1c9ab3fcfe9f5ee485430afbbaf48cb70c5bc8dd85f7066c1b72cc61ea75254ec043ed52ea74ff161855b89f1d968ac9b4bf0fb451fb5ad5766f434782cae42bc715d420a60c3ee39a75c0ae25280c94392f08604fbb97bf1071099c7b98d0e3d2092b5220031b11fe9ec56b30303f120d7b29430c052ac6d1090f90e614eecd53b52914b94b4ca0ae97e5cc59d75c9d2b274b2ef29cbaa5f9f8351d384b993a2915f55036252af2b62b7ef042c82e241eda801a3c509eb3742bbd1154f56ce6e48b2958f7bfe78006c7a47a3aff74424165a73bbc9c9b0b9b44a4ccf4e08ef03248694d798d931878351166606d8cd5df6c3e7582153cab7b15e644ce6bb69be08dce94cfc327bbebe92c1433a3f922dac4a10763164939540cf03a382f25e9772d32a152d62bbe3765e952a85e14ea6a0dc5f51ae2ba02f979a566186c5251a9a74f68c29e1d2bc3785d91315bd2fb321635a3c47cc0d16ef4d32da544ff8c8cd927c276c49a2b15eeef494e494aa0a8358c6d4b67f4acf1f044d270839f52fcc72977f73009008ebd92fb9b68f937a9d75c52053f25f6bb06a09e2cf4b6189f76567b4d14802430375f97ebd1e232a5c6ca4870200b00afafb45ab54789ab988bcebf2640e6b44c586735705e2e38a6cf7266fcee028941d540511751d050afcb7b6bc88a3a593d79bc30bd54bfc3367a21e86a17f45801b932d5862f0aedecfbd4aef578bffd9dc6932df7d06f0d744843c7b899704ca33eb2368e6dc4c67ea56780ac9b7362b94bb1c7824ef38cd00ac05dcf88f710048caccff13edd9637da487a35a4ed840fc0cd841a798116e0864a345666e43cd85c0323f5feb34851bbf66ab70f517179c9b568acbd4a79bbe1b9ee77533f5c8077141998be6e280c44ee5ac7ebefd460fdb44a9cee921c58d2d934e85c4bcafc197bb6f816b451a5a22334f0d299c7b3a4d5eff63055d51f7521dc0f70f7b0aabb60012f091e522475221ace85c9e636cc5d69197c25eb7a0848e3401bb1b71b68052e3e918532b5902df8cbe8ec40aba0b39d3a81620def982ed63b1a3d47fa09b4fedaeb3260ae13e200782d35ee1af652b396d4f304342af6268f72464380431cac1a43061e050b08f7255af030a4f3c9c67dec8dd15bb854bd2b4fcefbcb49363ee09ff57a857f889485e5a4330e11e89c221b45649c45e80a53a036b3114432ba09ce43b5ad531a461337960668e6bc87f3cbd323b13c669e1568232b6f8b940632a05e5731fa2109889afafa58e6c02ee70ca123cfca2e05f1a2147fdf34bb4380c188b3e28033e5485d48d1c0c248f26b003582f2c2ee5c3b3c4cbd6e0d15dd00a4c5ec3fce30916f158329953014887f853242a507fda46cb7ef16062cdd2b84cd6b6d7d1b40f279c713851d7f5428ff7b6d9ca638c0ec0a60a6c00a2fcdb7c882ccd27c68e34e6fe425b34584cb43b699a603cf8e2b019a12708f4133f55c8511ade05325f457" + }, + { + "app_id": 2996444749, + "data": "19477d140b32d4cacdefe2cad3cad1942b0539de6b3a2fd321e66f005c38a5a9542d4d3f2f08a4e88f6acd7e4518156b3b138abbb19f2f3be961ceb725a8b8de7247d6151de5ca5f5a5e65339ceff3da2f5b7127f2ab348cfc908571315abedcb8a08357c1c459210ebb317d97853fd5b6d1741438799a5a650bb98028ba1e4b9d2902d97a9368939bdb85153624c3eaa13278dadf6adc88dd3608e4ef19063ff20f40342cb9bb9f9c0dc691c34cdbeafe767478ebafe4bf2ef043fd306b6ebcd2837b5948029c534d4bb76609da457bd2930b76a3e4236bf3bca314321f21be45da586179b853d80c49a5b95bf67d863052a6ad4dd4b081860e05da4ff2e1e81e8c7861509c0481fab6587781889554cbd9981286ec437b36065f56e5a0eac5f5ce683931e421121769787b7d49154bab6fb22a46aad8ebfc3a84cb791ef4b4a0dfbd4cb34554f204c21e5b975bd345e0c670906d3bfcfd4c1a3d1b0a73f0629e7437d75f511e43c9eab4f308bc06a59786c69e4b412471dc63413144035b37610f5f5fa1cc6503bdb6140b1e75dfe3d3b18b36ecdd78f6dfeeacc12c585bd191d1b32ba1c8330d335ff61ba5e2898f3cf466068e8d7a1b4b9ec42652794e5a810f80e234091443481c864f13fb3d5d27f3ec90ea8e4e3ba736e714b5d12ae2fbe975efe0b59a540c76af7a1a7929fb5f86bdf4ce5c84788cd919abad1ed0f091c0b33ca9d86e5d1773545d41f99b0ab2bfd4a6aacdd28edd3bc798360b6e72eebf55bc1e6a62f017b39965f4df4b7c5f39a55d8f95b058946652372b559b49ee367faa7008863990b83aebf1ce789c955f9aaa3b6d189623f710ce84ef7eaa344ce678a39b05c0ea37229932e459af010fe6d20ca9b8cfbf9914d560782c0162eca5ac82a06ce5b6755711b20f40d3c63ad065d06b821743c0cd380720a3892d6d38cf17889ff06d544df4d92935f5f68109074af8cf270e47bdf164f38626f047db1535f303827e56c82e4f028a52a99e6088d197e453fa0197a49bbc54f728a8ddd3ee9cddfa7bc97a1c1bc733275497e4df1e410e6cf007c6fe76c6ec23962602c123a4537964ca60e282dde80559d55c9779055339edf9291f415ad373c66cf1911ee20f9d1633476a54e78783ee7aed4ae2f0256a841c0a3b1fdcf289179420555a1275c625fc1c08b22fd3890e33d831fa5e1deace2d7137cab6fa095935637e6b04f8672061b0c7eb73f4e6b5c5bbef3871b8fc61a42cbf6f83191bf129197190a46fcf7a7bb24c37bc8a4208e592e2a8609c209b6e7e6dcf759d8f690666284d9fd06e176f2f94c2d98effd1d6b18c9721ea8a85a68651904c3e51a72699d0a922a94805b76f702f5925cba30984e16d3e8cf608dde11ef34b91c07636c056c6748a066809aa43ab5c5127b2dab00e32a1b7b0f526bb6083402ff42e366a39670d5a468ca2b2cf7b102744779b05661c8e973665d40426e3eaacbebc3f18c6161e3007fac1b1281d948bbcde2b316582906398eb1e2235e1d9d385e300b04df8d34801d95f8db315b1f6ed5e62429ac40927bd33f6fff6a5d1c729508d95365a3e1f5fb3ac1ef49f1fb75257457e4bcf89a1cfdeb2cec1f9d61ec578973756b7b3117bdbb767a0cd7df487b98122122f9917d45e9b8f571f109632db09f1b688b552bfa472b272286dd5dadc1427757f3f24e9c3fdaebf709341a525b0aa989458557365b5957f1264b79056a883153e551291cc8dcc4aa0559e06d5b22b3e56e1aa7f2c0d6013c57611cb095a157c2b10b43e0a7b1c61d05fe2f3f0c63829fc2477e3d94b0b2b60c5e45bbdc1f8a39e7e77a4ffd7f5cdea80fdb13663b9b06da92412fd052a08f8cc59d6b3eee2a680550d33de7a59108f78c18e584b7b6db4d9e4b184038794294a9fa6738a293d71b760812e10b959088d5aa157cc18f10ed3e59d2ce577e244ee89bf11e15f7d430da8248929a62902a192ae1b2badf28494bc77c66e9db50bf598fa9165e752729d78e7de69ea57b6be609ccea8d83d2b827bb87640e6e888865858d29a8a2e132cf4c8c43472e18d6d9f22ed1e42ea48488db3aa54d08a9cc64d14377f06c4d2267c2e709b597cfbcfb284c6d27b2d701517102d3d612d9dcc8391c5b99af67ce85e822381037245e15ea533b6bfcbbedd4755b549b4e6f52931029475b2cd5bd5b9907e7a9c5f0a9178e7e1bee3895a860f92960894eab8bce437794356579ed0b1c21fb2ada821b28fb1e32d4141db90c6289118d76c442d85da08f78b459d323a3935174661098bcd6c567cb0d6683677303a4412648db184fa3d440461efc67e3deab668758d1c8976984294199b28134ce02de6b68b46d2297a5df5ed40705806f43836064e29912a6a43e4871c2a643848fcbc7553de6db91edc743de6c821b57049c937c6e652fb0a55ae94d5cfbed5d4b4a9b59cd3c0282becc86efb1f99328241d4c59e63dbafdf01f4b4c11e1e37fcd0b352f26c1d07a81683dc5d593fcdc96ae0e22ab66749a0c7e9dcd0c81ceaf40241093591a65f9c57dec137dd48707f4db223ac13b483c1e1cb941ee7d5a7093eac21906310d4d8c86ec7db30aa11cef179257ef050c239f3ec7110c404c29389b0ae3f2c07eecd4a690fc2f606a96278f0d2052591cf72ca2ade6ce644170140c27bb498d7972c7df34ce62d6a4f30e2ff9c35254743e9eca1894492e6c28fdbecf52282e2881dc7b85d5b34762f826856a2de5cad687dab30455ae721d687ff21603a848335d901835993c9365f7ffd0af803bb672993e69b7cfda5c76e32a6d2f09d13487193c5" + }, + { + "app_id": 3315510934, + "data": "79249977e3d11b007f11355f602905ae2915f9ef77b5dbbf7f29f6c6ef38cdda86c24b9181e77fc617db2a7b14811c3270b174e44c8f0789d710297636e9bd2cddc780d94e049bef7d9003cdd26115137e351c6adbd29897cb6bc449d31c502af84351c76487c2ee4652dba1c688711eadd45aacca46ec8feb59200af90150ef25c01f2ac1aa43120f79c99f6cd698b7619e1c7a5c3e7726d90d42737c24364db4d33a87faf6d88e05831906d89e6f36bf066a8ce765782c9aeec2795be308a3e5656d1f41d62cc035ecf653c5c930ff9e6ca21deedbd02010bad3df9cfa9f41ebd8400cbaf7fec514f46c93be1912594c7decd09d78528345b676778d1b9017813c55f467e41fd8f1a5870b33696246760b489f1460d50e6d4e7b902daa3bd527d11eff647454ae5ea2171383962c7443588a86aa88864ae703ba5b7b9a6c440b98222a27f46a15c61db166b2fa000efb7423beacb97eec80bfd7294f06acae1d409f79b9536cc9e6b7d4f5ae5fd537fe19bf0a667aca789186fa1f449c7a638c396cba1c19881e16c5c2e1613a6382e04df54ebcb9282ffd6bc6df71cfecb3629811015c7d63525e2d1a0a2b7b32352055a03c1d8dabe27a4142b7648a5813645612c8d47dc8760cdffc1effe33849c104bad0c089f9b589e297bb3eb41d2e53d7372b8154802b2f158e34d6c6468a6286bc9b30d9dfeca62698f89331c46c2c1d9dc68360aedd48a8bb4ca636598366f03f99ff138bfcf47289d97ea9959b4b0f925d5b04e8c15a8e9c6b813157ac2174bdaf09da67a853d9fbff62cef069c6d1c515740c" + }, + { + "app_id": 3408444956, + "data": "bb89f92fb327746b2a2b9e86266d583b6e587755ebfcdb1cbfea1cf59bcfe7e222b8fd73e3156aa054b0ffea1495f47083597ef699955b23dd18ef533757a7a455fc386039ddcf396facd016a166f022b69882d0a428b03c7db597bf432e086e13212787bf208ff60a5b18fc62ed0bf6f4b9fa793e7dff4006a5d7afbc66c84ec9ac19eca8dfa5a3aed00aa011404a47d7567795f6d4e6181d1eb2e7687afcd70ddf3bcf91f707532737f16caf045fbfed9a25de66543be0d9258a176b4ca0d5d5a0c2f9df6ad4e51698569c1fb0920ec8d4a98b1ea63baac061dc6baad62691ad8940f75d2b65ab38d0fa839d6f491f97f20cebc618f177a1364e2893f3d815e8a3e0fe69141271a7d1740864de4a5c5275a6e04342212b0478ec4e9f510b6bce7febf7ebfdfa81de4fb88b6d749c22e61c531dcc7974a4cce574fa1c8ad181b0f6b5798b30c6cc118ed94c0056b3fa62e3b6ae774bfb8a3dc43b306e0f4f73ed32c04ee51b0350fd08016618acd12fd231a1a4324696796128948ff64618a6fc68788cbf0896741af2521a8e00e7d0b7aa835ce97934921bfd28ed18eb8391109d95692d2335f8add32fb505c769d0961dea5e3f40d1651ea41b66ba78f987294ef310a41a3a96f75f8d9e6c898f5655c79fef35ffc2b3905181f11f3ef438aab778dcce85bde52fb5f9b862338d9b1f473f734a16ed67f34e65df7bbec84f8b20e268963682102be15ace8ec18c9e0a879d1005e0fd7308b0803464b9f1fd82c4b3540bc503d3d2eb6a461f7dec768800db56ee22c496cab71444b3a75ee676af1d687c9f2fabdae0aac2f6d6e65facc4730281dda985eaaf56f02244f1b04a634b2523da86610017b60a60b3f588c1052edd46f8bd03464d8b488cfb2d39c0cc140adbaf16397cba217cafabd6f69a17fff5e97082d6618130ef896e227db7b90965f7e485c083d8caf43c591e51fc84f74d11ba727469c1979c48bfa07c3c4c999aedbb2fd64208b013d516e3626a1b3f03e6cd712bb003004ea3bf84a699dc04a6b8d270e3be5df14c99b5c7c5ea587d17fda0800288569ceb20caa4841c1f77b91c2c0a8a7cbf13caa7fc47ee309076027b930c01892066c1797e365d2f62401ad456b30b980a8afe52ab2524ee739b3efd03e9a2dc30b3a6c59dd7acfb7480fa349e80b119f77f98a29fdb095ac67716cf44d4c7727ba84301d0f28d490f158b4145be93db9969ca2502e23b33a09f7a170041797b989ffcef656ca2ced67b5d0106d53f189dcf4820abe3d97b5c74e4f2ec20bad690cf2b314889fb1fc10bc5b2cd92783330bba8460d8c757107f5331ae4e4fb335416d65b59450a281ab643c9f26fdac4738454feaf175a780041e83d90f90254eb2e409141448dbd3403fe9c060571a2d22851316eab5bb601720420d09d3d2b1d793fb4456fb798d97ee99c2a4d9c3df15820eef414801be4484f3ed8e340b556a5d6526f25e41dcb4c098c655895310721f2eecd6ed87e65f745795da3aff6d8dd92b1673783fbc1a57fe2b091f1eace76d33ae2229f9b8e9a16aac64c527c34ce423a9f4dec816117ad7c9928f5b747502688e643e73a01d48936594b0a8997b76a5ab8016b743324f2fe9ddf8fa3ae1ed39737863d732efaa1917ff80f9c6424205143652bebb9c82d27130ae4690bebb6169edf5a6493f67b5adda352ec7fb7fe9a0e8ae5c43744a0ba899bef675ab456ff39ec1bce4a95a56b84787f8f0c790c0caf2e5e78b6505d5af4d570239c98a5a5cafd1096a8f2f91fdf3350266dc30f1d188764cbe7bdfa90f581186aac25ca71a5ca1b90c9ccaca0b474f4c48a345e7dd0d22627ded5f4de932d63e6c3cfcf0240b916469cab20c8b097577bfa916587fbbaf38ee0f5bbf12f10ddb50b2b85a114e874b06154eb34e89f75c1a3edcef52a08ebc2c52935c8d29e0854bb2eff3f8524a9770e9877139cbc240187f5d1db651140353ed040282b43e2e887584ab85a1f0e9cecfb643054e5cf3c987bc28cc3d8903d3e37d9c5b01a55ab06a2b7f131ffd7fc9e8e8d10a8df00fd7e0e3229065287c1b26e857221ed459b63bc313886b75c53d51b58f221117ffbb19edf83d122fd514edb6f4d0499f880bbe1ab237e1a3c0fb4b6f9ec87b09f27ffd9a02f5c7993cd01c97ff3a4faaa63a362fc675a19c9ee314248d57caf3504337e331dc7590ebde2a469" + }, + { + "app_id": 3878605408, + "data": "f318643f745891fef0e0547a94b02430a2e0717db2b3b5f0140c1107c727469f607313471f90c9f6e3c201090a4b0a7b19ed7f1fe8e33e0e9f6460f215abab05a48c571e876cbe73de43f885410e36369e182ae1a320942d963706fbc805dbdfe964e43d89938d85d5352132928592b4bbc20cc5775f27ec5f5c27fa42f7c6231fb278ff17bae6ca92b980b279691439ccacb65c267c24572f6c4435318dae6ee134249457d29e0eeb54ac83d73c55139f9cc01585a622190c3ba17f1d49ab54a4e7b997183427689067767503573c9fa3bafa5b1e2ba38631b6499174d5f0d9077fde4e6b3e4e3e317f842307ca7aa5ecd6447800bca1eceed88ee58247ff04dec7604a5a82f90919a887c994fb4a95272cb0906ac9d47ff9a4e168024ad41033ec17bd98d9a39a49c51c2298d055e3cccb8e7279717506190a8e05f3627e91fabae803063da84147f6c0ebb889a479f37599d4e9feaf700dac1d664a29b086625e5309c1010f46f14f620535bb5ef904d7bd8bc4177ce15eca8f537c8af7a9504d52ef3c3959243c209e41383949d8184fa52fb0cb8a8df88f45268d82da3b93b2da77c868409d56586e6339b757771865fdc6b92047ea3267ff4a7090b4f4b6f86e2bb1bb07ddb2eea6b97c2dedfbd8736c1f8d790a60879bfc3b650cf3d6ef13da00415389db0030da5c026386cb5bb0884eb709e8b1bcb96bcdb090b1312165202a346495ccffe493c03b8f41d1f4ffc4e4c31f7fe9a1b89b85a17896af6e9f89b6c21b967157a1a77d1e840ec20940a0bc348caa10471946eb30f0f1798797fac9282bcd29adc2d1dbc3fa65435fcc6ac161aff3bf8b6ff574bc2884d7115e1c9df3358b24c7ad232d3a615eb01c732e28a496ebb7e8e8b06e84241528340270fae38b6a0033d960bb410acbb881de7d683fc8c8b65a69515e35911957f94de935832d08aafc7b98145d13e2418e085cf0148dff17733fa457285c6f2f665b7ce2da7d7e87883a67ded8c4211e15b9f41bf49c56c3038ac534adbf8e47530e194478446fa728717f3d1d06472b72999842825cffd8a5415089d5843839fe05e58dc9a0695f5c1cefb26bb70576a53353be42195498f62327703f87a281c2bbe99b61c85aec8f1c2258a5149716ab84ec5a77d45ea56323e717da0fe1d9c47dcbf4be9d02bf5953ed34187fc1c2e383ab4c492e025d0078665b9d834a538e2a2ed018e5bb5a0fd292164972a8983f2a7614f17fa6f751418193807bc3d568f910c15ad369ab10affbbf254758392d6a1cbdd6ce0563b2d014a7ab8c5a96b2e96679191b6959843037c2280f6735715c547855594fb63c50310cf9cabccf0b44d8ffd53f1add0cf35cab35eb8d06b1cc3eb46e526583d156a9d8dc648f015dae376af15709d7e092707f520d9858bc97ee4317e1b8b4871be537223e9abc98e63e451c31b173066fe9fddb9a0b39707e3ca1c9b77455d9fe4d26f16d6791aabc1d8b1c75da3fcf09716f6cec19dcff4fc869ce7c73584569e51f666bd90d39a930ec4305cf1015cd1f09716c9bcb02fe7b23c0af55e84af1505156e1b58f453b4881bd51436581a559b84841c641da6112a7b8b0c86af0b97741f7b899ce68db0c174a39865c1afa0c1a48ac4590925f5f07becac1a3774b87e252b3ec7ca5378a175b44374138419058064836f63ccf967704dcf7270a20b8e6f6e2ee86d62c3b0c34d29e3ee54df5c4ed5f4e3551a3caa00ae0cd75a729a8fe7ebd78c1e5e4354a399399a9dbefbf42a39e45f726c128e23a3f8f73749d985e290a08a5cd05e6a98ffbe5c0072b8a04867019488b79a4e640cb15ffeb6231078e5e0ede5453dd6fc94f3fc475a9ff1fb2666d559fc170f4b80aa98a633b6d0ffbb605d09c6b7efe4808d2ee4d49dc28748c769f745df6009624ab334fdff90b0e029a5ac51083dec1a62c7c9b0dc18e0f281fd54fac7f607f9b22d09a4fd5d17e70ff28181068b37af137a61e8ae0fa8cc0482bf4398bad275353a9c539f3ca72e47803efb7d2fc4732fa898cc556f96023186196bb56a153bd57ba70977f775f51faf1995f0811e63967b9b7551a1286021eb6956f56e673" + } + ] +] diff --git a/kate/benches/reconstruct.rs b/kate/benches/reconstruct.rs new file mode 100644 index 00000000..92c14dd1 --- /dev/null +++ b/kate/benches/reconstruct.rs @@ -0,0 +1,160 @@ +use avail_core::{AppExtrinsic, BlockLengthColumns, BlockLengthRows, DataLookup}; +use core::num::NonZeroU32; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use dusk_plonk::prelude::BlsScalar; +use kate::{ + com::{Cell, *}, + metrics::IgnoreMetrics, + Seed, Serializable as _, +}; +use kate_recovery::{ + com::reconstruct_extrinsics, + commitments, + data::{self, DataCell}, + matrix::Position, + proof, testnet, +}; +use nalgebra::DMatrix; +use rand::{prelude::IteratorRandom, Rng, SeedableRng}; +use rand_chacha::ChaChaRng; +use sp_arithmetic::{traits::SaturatedConversion, Percent}; + +const XTS_JSON_SETS: &str = include_str!("reconstruct.data.json"); + +#[rustfmt::skip] +fn load_xts() -> Vec> { + serde_json::from_str(XTS_JSON_SETS).expect("Autogenerated Json file .qed") +} + +fn sample_cells_from_matrix(matrix: &DMatrix, columns: Option<&[u16]>) -> Vec { + fn random_indexes(length: usize, seed: Seed) -> Vec { + // choose random len/2 (unique) indexes + let mut idx = (0..length).collect::>(); + let mut chosen_idx = Vec::::new(); + let mut rng = ChaChaRng::from_seed(seed); + + for _ in 0..length / 2 { + let i = rng.gen_range(0..idx.len()); + let v = idx.remove(i); + chosen_idx.push(v); + } + chosen_idx + } + const RNG_SEED: Seed = [42u8; 32]; + + let (rows, cols) = matrix.shape(); + let cols = u16::try_from(cols).unwrap(); + let indexes = random_indexes(rows, RNG_SEED); + + (0u16..cols) + .filter(|col_idx| match &columns { + None => true, + Some(allowed) => allowed.contains(&col_idx), + }) + .flat_map(|col_idx| { + let col_view = matrix.column(col_idx.into()).data.into_slice(); + + indexes + .iter() + .map(|row_idx| { + let row_pos = u32::try_from(*row_idx).unwrap(); + let position = Position::new(row_pos, col_idx); + debug_assert!(*row_idx < col_view.len()); + let data = col_view[*row_idx].to_bytes(); + DataCell::new(position, data) + }) + .collect::>() + }) + .collect() +} + +fn random_cells( + max_cols: BlockLengthColumns, + max_rows: BlockLengthRows, + percents: Percent, +) -> Vec { + let max_cols = max_cols.into(); + let max_rows = max_rows.into(); + + let rng = &mut ChaChaRng::from_seed([0u8; 32]); + let amount: usize = percents + .mul_ceil::(max_cols * max_rows) + .saturated_into(); + + (0..max_cols) + .flat_map(move |col| { + (0..max_rows).map(move |row| Cell::new(BlockLengthRows(row), BlockLengthColumns(col))) + }) + .choose_multiple(rng, amount) +} + +fn bench_reconstruct(c: &mut Criterion) { + let xts_sets = load_xts(); + + let mut group = c.benchmark_group("reconstruct from xts"); + for xts in xts_sets.into_iter() { + let size = xts + .iter() + .map(|app| app.data.len()) + .sum::() + .try_into() + .unwrap(); + group.throughput(Throughput::Bytes(size)); + group.sample_size(10); + group.bench_with_input(BenchmarkId::from_parameter(size), &xts, |b, xts| { + b.iter(|| reconstruct(xts.as_slice())) + }); + } + group.finish(); +} + +fn reconstruct(xts: &[AppExtrinsic]) { + let metrics = IgnoreMetrics {}; + let (layout, commitments, dims, matrix) = par_build_commitments( + BlockLengthRows(64), + BlockLengthColumns(16), + unsafe { NonZeroU32::new_unchecked(32) }, + xts, + Seed::default(), + &metrics, + ) + .unwrap(); + + let columns = sample_cells_from_matrix(&matrix, None); + let extended_dims = dims.try_into().unwrap(); + let lookup = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let reconstructed = reconstruct_extrinsics(&lookup, extended_dims, columns).unwrap(); + for ((app_id, data), xt) in reconstructed.iter().zip(xts) { + assert_eq!(app_id.0, *xt.app_id); + assert_eq!(data[0].as_slice(), &xt.data); + } + + let dims_cols: u32 = dims.cols.into(); + let public_params = testnet::public_params(usize::try_from(dims_cols).unwrap()); + for cell in random_cells(dims.cols, dims.rows, Percent::one()) { + let row: u32 = cell.row.into(); + + let proof = build_proof(&public_params, dims, &matrix, &[cell], &metrics).unwrap(); + assert_eq!(proof.len(), 80); + + let col: u16 = cell + .col + .0 + .try_into() + .expect("`random_cells` function generates a valid `u16` for columns"); + let position = Position { row, col }; + let cell = data::Cell { + position, + content: proof.try_into().unwrap(), + }; + + let extended_dims = dims.try_into().unwrap(); + let commitment = commitments::from_slice(&commitments).unwrap()[row as usize]; + let verification = proof::verify(&public_params, extended_dims, &commitment, &cell); + assert!(verification.is_ok()); + assert!(verification.unwrap()); + } +} + +criterion_group! { benches, bench_reconstruct } +criterion_main!(benches); diff --git a/kate/examples/multiproof_verification.rs b/kate/examples/multiproof_verification.rs new file mode 100644 index 00000000..6049baee --- /dev/null +++ b/kate/examples/multiproof_verification.rs @@ -0,0 +1,110 @@ +use avail_core::{AppExtrinsic, AppId, BlockLengthColumns, BlockLengthRows}; +use core::num::NonZeroU16; +use hex_literal::hex; +use kate::{ + gridgen::EvaluationGrid, + pmp::{merlin::Transcript, traits::PolyMultiProofNoPrecomp}, + testnet::multiproof_params, + Seed, +}; +use kate_recovery::matrix::Dimensions; +use poly_multiproof::traits::AsBytes; +use rand::thread_rng; +use thiserror_no_std::Error; + +#[derive(Error, Debug)] +enum AppError { + Kate(#[from] kate::com::Error), + MultiProof(#[from] poly_multiproof::Error), +} + +fn main() -> Result<(), AppError> { + let verified = multiproof_verification()?; + println!("Multiproof verfication is {verified}"); + + Ok(()) +} + +fn multiproof_verification() -> Result { + let target_dims = Dimensions::new_from(16, 64).unwrap(); + let pp = multiproof_params(256, 256); + let pmp = poly_multiproof::m1_blst::M1NoPrecomp::new(256, 256, &mut thread_rng()); + let points = kate::gridgen::domain_points(256)?; + let (proof, evals, commitments, dims) = { + let exts = vec![ + AppExtrinsic { + app_id: AppId(0), + data: hex!("CAFEBABE00000000000000000000000000000000000000").to_vec(), + }, + AppExtrinsic { + app_id: AppId(1), + data: hex!("DEADBEEF1111111111111111111111111111111111").to_vec(), + }, + AppExtrinsic { + app_id: AppId(2), + data: hex!("1234567899999999999999999999999999999999").to_vec(), + }, + ]; + let seed = Seed::default(); + let grid = EvaluationGrid::from_extrinsics(exts, 4, 256, 256, seed)? + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) })?; + + // Setup, serializing as bytes + let polys = grid.make_polynomial_grid()?; + + let commitments = polys + .commitments(&pp) + .unwrap() + .iter() + .flat_map(|c| c.to_bytes().unwrap()) + .collect::>(); + + let multiproof = polys + .multiproof( + &pmp, + &kate::com::Cell::new(BlockLengthRows(0), BlockLengthColumns(0)), + &grid, + target_dims, + ) + .unwrap(); + + let proof_bytes = multiproof.proof.to_bytes()?; + let evals_bytes = multiproof + .evals + .iter() + .flat_map(|row| row.iter().flat_map(|e| e.to_bytes().unwrap())) + .collect::>(); + (proof_bytes, evals_bytes, commitments, grid.dims()) + }; + + let mp_block = kate::gridgen::multiproof_block(0, 0, dims, target_dims).unwrap(); + let commits = commitments + .chunks_exact(48) + .skip(mp_block.start_y) + .take(mp_block.end_y - mp_block.start_y) + .map(|c| kate::pmp::Commitment::from_bytes(c.try_into().unwrap())) + .collect::, _>>() + .unwrap(); + + let block_commits = &commits[mp_block.start_x..mp_block.end_x]; + let evals_flat = evals + .chunks_exact(32) + .map(|e| kate::gridgen::ArkScalar::from_bytes(e.try_into().unwrap())) + .collect::, _>>() + .unwrap(); + let evals_grid = evals_flat + .chunks_exact(mp_block.end_x - mp_block.start_x) + .collect::>(); + + let proof = kate::pmp::m1_blst::Proof::from_bytes(&proof)?; + + let verified = pmp.verify( + &mut Transcript::new(b"avail-mp"), + block_commits, + &points[mp_block.start_x..mp_block.end_x], + &evals_grid, + &proof, + )?; + + Ok(verified) +} diff --git a/kate/recovery/Cargo.toml b/kate/recovery/Cargo.toml index ae27d964..9b39eaaa 100644 --- a/kate/recovery/Cargo.toml +++ b/kate/recovery/Cargo.toml @@ -1,28 +1,45 @@ [package] name = "kate-recovery" -version = "0.8.1" +version = "0.9.0" authors = ["Denis Ermolin "] edition = "2018" +license = "Apache-2.0" [dependencies] +# Internals +avail-core = { path = "../../core", default-features = false } +dusk-plonk = { git = "https://github.com/availproject/plonk.git", tag = "v0.12.0-polygon-2", default-features = false, optional = true } + +# Substrate codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -dusk-bytes = "0.1.6" -dusk-plonk = { git = "https://github.com/availproject/plonk.git", tag = "v0.12.0-polygon-2" } -getrandom = { version = "0.2", features = ["js"] } -num = "0.4.0" -once_cell = { version = "1.9.0", default-features = false } -rand = "0.8.4" -rand_chacha = "0.3" -serde = { version = "1.0", features = ["derive"] } -thiserror = "1.0.37" +sp-arithmetic = { version = "*", default-features = false } +sp-std = { version = "*", default-features = false } + +# 3rd-parties +derive_more = "0.99.17" +static_assertions = "1.1.0" +thiserror-no-std = "2.0.2" + +dusk-bytes = { version = "0.1.6", default-features = false, optional = true } +once_cell = { version = "1.9.0", optional = true } +rand = { version = "0.8", default-features = false, features = ["alloc", "small_rng"], optional = true } +rand_chacha = { version = "0.3", default-features = false, optional = true } +serde = { version = "1", optional = true, features = ["derive"] } [dev-dependencies] hex = "0.4" -once_cell = "1.9.0" -rand = "0.8.4" -rand_chacha = "0.3" test-case = "1.2.3" [features] default = ["std"] -std = [] +std = [ + "once_cell", + "serde", + "sp-arithmetic/std", + "sp-std/std", + "avail-core/std", + "rand/std", + "rand_chacha/std", + "dusk-bytes", + "dusk-plonk/std", +] diff --git a/kate/recovery/src/com.rs b/kate/recovery/src/com.rs index 1a42be9d..0934e8b2 100644 --- a/kate/recovery/src/com.rs +++ b/kate/recovery/src/com.rs @@ -1,54 +1,92 @@ -use codec::Decode; -use dusk_bytes::Serializable; +use crate::matrix; +use core::{num::TryFromIntError, ops::Range}; + +use avail_core::{data_lookup::Error as DataLookupError, AppId, DataLookup}; + +use sp_std::prelude::*; +use thiserror_no_std::Error; + +#[cfg(feature = "std")] +use crate::data; +#[cfg(feature = "std")] +use crate::{config, sparse_slice_read::SparseSliceRead}; +#[cfg(feature = "std")] +use avail_core::ensure; +#[cfg(feature = "std")] +use codec::{Decode, IoReader}; +#[cfg(feature = "std")] +use dusk_bytes::Serializable as _; +#[cfg(feature = "std")] use dusk_plonk::{fft::EvaluationDomain, prelude::BlsScalar}; -use num::ToPrimitive; -use rand::seq::SliceRandom; +#[cfg(feature = "std")] +pub use sp_arithmetic::{traits::SaturatedConversion as _, Percent}; +#[cfg(feature = "std")] +use static_assertions::{const_assert, const_assert_ne}; +#[cfg(feature = "std")] use std::{ collections::{HashMap, HashSet}, - convert::TryFrom, + convert::{TryFrom, TryInto}, iter::FromIterator, }; -use thiserror::Error; - -use crate::{ - config::{self, CHUNK_SIZE}, - data, index, matrix, -}; #[derive(Debug, Error)] pub enum ReconstructionError { - #[error("Missing cell (col {}, row {})", .position.col, .position.row)] - MissingCell { position: matrix::Position }, - #[error("Invalid cell (col {}, row {})", .position.col, .position.row)] - InvalidCell { position: matrix::Position }, + #[error("Missing cell ({0})")] + MissingCell(matrix::Position), + #[error("Invalid cell ({0})")] + InvalidCell(matrix::Position), + #[error("Maximum cells allowed {0}")] + MaxCells(usize), + #[error("Minimum cells allowed {0}")] + MinCells(usize), #[error("Duplicate cell found")] DuplicateCellFound, #[error("Column {0} contains less than half rows")] InvalidColumn(u16), - #[error("Cannot reconstruct column: {0}")] - ColumnReconstructionError(String), #[error("Cannot decode data: {0}")] - DataDecodingError(String), + DataDecodingError(#[from] UnflattenError), #[error("Column reconstruction supports up to {}", u16::MAX)] RowCountExceeded, + #[error("Rows must be power of two")] + InvalidRowCount, + #[error("Missing AppId {0}")] + MissingId(AppId), + #[error("DataLookup {0}")] + DataLookup(#[from] DataLookupError), + #[error("Some cells are from different columns")] + CellsFromDifferentCols, + #[error("Invalid evaluation domain")] + InvalidEvaluationDomain, + #[error("Bad zero poly evaluation")] + BadZeroPoly, +} + +#[cfg(feature = "std")] +impl std::error::Error for ReconstructionError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self { + Self::DataDecodingError(unflatten) => Some(unflatten), + _ => None, + } + } } /// From given positions, constructs related columns positions, up to given factor. /// E.g. if factor is 0.66, 66% of matched columns will be returned. /// Positions in columns are random. /// Function panics if factor is above 1.0. -pub fn columns_positions( - dimensions: &matrix::Dimensions, +#[cfg(feature = "std")] +pub fn columns_positions( + dimensions: matrix::Dimensions, positions: &[matrix::Position], - factor: f64, + factor: Percent, + rng: &mut R, ) -> Vec { - assert!(factor <= 1.0); + use rand::seq::SliceRandom; - let cells = (factor * dimensions.extended_rows() as f64) - .to_usize() - .expect("result is lesser than usize maximum"); - - let rng = &mut rand::thread_rng(); + let cells = factor + .mul_ceil(dimensions.extended_rows()) + .saturated_into::(); let columns: HashSet = HashSet::from_iter(positions.iter().map(|position| position.col)); @@ -61,15 +99,16 @@ pub fn columns_positions( /// Creates hash map of columns, each being hash map of cells, from vector of cells. /// Intention is to be able to find duplicates and to group cells by column. +#[cfg(feature = "std")] fn map_cells( - dimensions: &matrix::Dimensions, + dimensions: matrix::Dimensions, cells: Vec, ) -> Result>, ReconstructionError> { let mut result: HashMap> = HashMap::new(); for cell in cells { - let position = cell.position.clone(); + let position = cell.position; if !dimensions.extended_contains(&position) { - return Err(ReconstructionError::InvalidCell { position }); + return Err(ReconstructionError::InvalidCell(position)); } let cells = result.entry(position.col).or_insert_with(HashMap::new); if cells.insert(position.row, cell).is_some() { @@ -88,14 +127,14 @@ fn map_cells( /// * `dimensions` - Extended matrix dimensions /// * `app_id` - Application ID pub fn app_specific_rows( - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, - app_id: u32, + index: &DataLookup, + dimensions: matrix::Dimensions, + app_id: AppId, ) -> Vec { index - .app_cells_range(app_id) - .map(|range| dimensions.extended_data_rows(range)) - .unwrap_or_else(std::vec::Vec::new) + .range_of(app_id) + .and_then(|range| dimensions.extended_data_rows(range)) + .unwrap_or_default() } /// Generates empty cell positions in extended data matrix, @@ -108,13 +147,13 @@ pub fn app_specific_rows( /// * `dimensions` - Extended matrix dimensions /// * `app_id` - Application ID pub fn app_specific_cells( - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, - app_id: u32, + index: &DataLookup, + dimensions: matrix::Dimensions, + id: AppId, ) -> Option> { index - .app_cells_range(app_id) - .map(|range| dimensions.extended_data_positions(range)) + .range_of(id) + .and_then(|range| dimensions.extended_data_positions(range)) } /// Application data, represents list of extrinsics encoded in a block. @@ -130,17 +169,20 @@ pub type AppData = Vec>; /// * `dimensions` - Extended matrix dimensions /// * `cells` - Cells from required columns, at least 50% cells per column /// * `app_id` - Application ID +#[cfg(feature = "std")] pub fn reconstruct_app_extrinsics( - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, + index: &DataLookup, + dimensions: matrix::Dimensions, cells: Vec, - app_id: u32, + app_id: AppId, ) -> Result { let data = reconstruct_available(dimensions, cells)?; - let ranges = index.app_data_ranges(app_id); + const_assert!(config::CHUNK_SIZE as u64 <= u32::MAX as u64); + let range = index + .projected_range_of(app_id, config::CHUNK_SIZE as u32) + .ok_or(ReconstructionError::MissingId(app_id))?; - Ok(unflatten_padded_data(ranges, data) - .map_err(ReconstructionError::DataDecodingError)? + Ok(unflatten_padded_data(vec![(app_id, range)], data)? .into_iter() .flat_map(|(_, xts)| xts) .collect::>()) @@ -153,13 +195,16 @@ pub fn reconstruct_app_extrinsics( /// * `index` - Application data index /// * `dimensions` - Extended matrix dimensions /// * `cells` - Cells from required columns, at least 50% cells per column +#[cfg(feature = "std")] pub fn reconstruct_extrinsics( - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, + lookup: &DataLookup, + dimensions: matrix::Dimensions, cells: Vec, -) -> Result, ReconstructionError> { +) -> Result, ReconstructionError> { let data = reconstruct_available(dimensions, cells)?; - let ranges = index.data_ranges(); + + const_assert!(config::CHUNK_SIZE as u64 <= u32::MAX as u64); + let ranges = lookup.projected_ranges(config::CHUNK_SIZE as u32)?; unflatten_padded_data(ranges, data).map_err(ReconstructionError::DataDecodingError) } @@ -169,51 +214,54 @@ pub fn reconstruct_extrinsics( /// /// * `dimensions` - Extended matrix dimensions /// * `cells` - Cells from required columns, at least 50% cells per column +#[cfg(feature = "std")] pub fn reconstruct_columns( - dimensions: &matrix::Dimensions, + dimensions: matrix::Dimensions, cells: &[data::Cell], -) -> Result>, ReconstructionError> { +) -> Result>, ReconstructionError> { let cells: Vec = cells.iter().cloned().map(Into::into).collect::>(); let columns = map_cells(dimensions, cells)?; columns .iter() .map(|(&col, cells)| { - if cells.len() < dimensions.rows().into() { - return Err(ReconstructionError::InvalidColumn(col)); - } + ensure!( + cells.len() >= dimensions.height(), + ReconstructionError::InvalidColumn(col) + ); let cells = cells.values().cloned().collect::>(); - let column = reconstruct_column(dimensions.extended_rows(), &cells) - .map_err(ReconstructionError::ColumnReconstructionError)? + let column = reconstruct_column(dimensions.extended_rows(), &cells)? .iter() .map(BlsScalar::to_bytes) - .collect::>(); + .collect::>(); Ok((col, column)) }) .collect::>() } +#[cfg(feature = "std")] fn reconstruct_available( - dimensions: &matrix::Dimensions, + dimensions: matrix::Dimensions, cells: Vec, ) -> Result, ReconstructionError> { let columns = map_cells(dimensions, cells)?; + let rows: usize = dimensions.height(); - let scalars = (0..dimensions.cols()) + let scalars = (0..dimensions.cols().get()) .map(|col| match columns.get(&col) { - None => Ok(vec![None; dimensions.rows() as usize]), + None => Ok(vec![None; rows]), Some(column_cells) => { - if column_cells.len() < dimensions.rows() as usize { - return Err(ReconstructionError::InvalidColumn(col)); - } + ensure!( + column_cells.len() >= rows, + ReconstructionError::InvalidColumn(col) + ); let cells = column_cells.values().cloned().collect::>(); reconstruct_column(dimensions.extended_rows(), &cells) .map(|scalars| scalars.into_iter().map(Some).collect::>()) - .map_err(ReconstructionError::ColumnReconstructionError) }, }) .collect::>, ReconstructionError>>()?; @@ -242,11 +290,12 @@ fn reconstruct_available( /// * `dimensions` - Extended matrix dimensions /// * `cells` - Application specific data cells in extended matrix, without erasure coded data. /// * `app_id` - Application ID +#[cfg(feature = "std")] pub fn decode_app_extrinsics( - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, + index: &DataLookup, + dimensions: matrix::Dimensions, cells: Vec, - app_id: u32, + app_id: AppId, ) -> Result { let positions = app_specific_cells(index, dimensions, app_id).unwrap_or_default(); if positions.is_empty() { @@ -259,7 +308,7 @@ pub fn decode_app_extrinsics( .get(&position.col) .and_then(|column| column.get(&position.row)) .filter(|cell| !cell.data.is_empty()) - .ok_or(ReconstructionError::MissingCell { position })?; + .ok_or(ReconstructionError::MissingCell(position))?; } let mut app_data: Vec = vec![]; @@ -273,7 +322,12 @@ pub fn decode_app_extrinsics( Some(cell) => app_data.extend(cell.data), } } - let ranges = index.app_data_ranges(app_id); + + const_assert!((config::CHUNK_SIZE as u64) <= (u32::MAX as u64)); + let ranges = index + .projected_range_of(app_id, config::CHUNK_SIZE as u32) + .map(|range| vec![(app_id, range)]) + .unwrap_or_default(); Ok(unflatten_padded_data(ranges, app_data) .map_err(ReconstructionError::DataDecodingError)? @@ -282,62 +336,73 @@ pub fn decode_app_extrinsics( .collect::>()) } -// Removes both extrinsics and block padding (iec_9797 and seeded random data) -pub fn unflatten_padded_data( - ranges: Vec<(u32, AppDataRange)>, - data: Vec, -) -> Result, String> { - if data.len() % config::CHUNK_SIZE > 0 { - return Err("Invalid data size".to_string()); - } +#[derive(Error, Clone, Debug)] +pub enum UnflattenError { + #[error("`AppDataRange` cannot be converted into `Range`")] + RangeConversion(#[from] TryFromIntError), + #[error("`AppData` cannot be decoded due to {0}")] + Codec(#[from] codec::Error), + #[error("Invalid data size, it needs to be a multiple of CHUNK_SIZE")] + InvalidLen, +} - fn trim_to_data_chunks(range_data: &[u8]) -> Result, String> { - range_data - .chunks_exact(config::CHUNK_SIZE) - .map(|chunk| chunk.get(0..config::DATA_CHUNK_SIZE)) - .collect::>>() - .map(|data_chunks| data_chunks.concat()) - .ok_or_else(|| format!("Chunk data size less than {}", config::DATA_CHUNK_SIZE)) +#[cfg(feature = "std")] +impl std::error::Error for UnflattenError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self { + Self::RangeConversion(try_int) => Some(try_int), + Self::Codec(codec) => Some(codec), + _ => None, + } } +} - fn trim_padding(mut data: Vec) -> Result, String> { - while data.last() == Some(&0) { - data.pop(); - } +#[cfg(feature = "std")] +// Removes both extrinsics and block padding (iec_9797 and seeded random data) +pub fn unflatten_padded_data( + ranges: Vec<(AppId, AppDataRange)>, + data: Vec, +) -> Result, UnflattenError> { + ensure!( + data.len() % config::CHUNK_SIZE == 0, + UnflattenError::InvalidLen + ); - match data.pop() { - None => Err("Cannot trim padding on empty data".to_string()), - Some(config::PADDING_TAIL_VALUE) => Ok(data), - Some(_) => Err("Invalid padding tail value".to_string()), - } - } + fn extract_encoded_extrinsic(range_data: &[u8]) -> SparseSliceRead { + const_assert_ne!(config::CHUNK_SIZE, 0); + const_assert_ne!(config::DATA_CHUNK_SIZE, 0); - fn decode_extrinsics(data: Vec) -> Result { - ::decode(&mut data.as_slice()).map_err(|err| format!("Cannot decode data: {err}")) + // INTERNAL: Chunk into 32 bytes (CHUNK_SIZE), then remove padding (0..30 bytes). + SparseSliceRead::from_iter( + range_data + .chunks_exact(config::CHUNK_SIZE) + .map(|chunk| &chunk[0..config::DATA_CHUNK_SIZE]), + ) } ranges .into_iter() .map(|(app_id, range)| { - let range = range.start as usize..range.end as usize; - trim_to_data_chunks(&data[range]) - .and_then(trim_padding) - .and_then(decode_extrinsics) - .map(|data| (app_id, data)) + //let range = range.start as usize..range.end as usize; + let range: Range = range.start.try_into()?..range.end.try_into()?; + let reader = extract_encoded_extrinsic(&data[range]); + let extrinsic = ::decode(&mut IoReader(reader))?; + + Ok((app_id, extrinsic)) }) - .collect::, String>>() + .collect::, _>>() } // This module is taken from https://gist.github.com/itzmeanjan/4acf9338d9233e79cfbee5d311e7a0b4 // which I wrote few months back when exploring polynomial based erasure coding technique ! - +#[cfg(feature = "std")] fn reconstruct_poly( // domain I'm working with // all (i)ffts to be performed on it eval_domain: EvaluationDomain, // subset of available data subset: Vec>, -) -> Result, String> { +) -> Result, ReconstructionError> { let missing_indices = subset .iter() .enumerate() @@ -348,7 +413,7 @@ fn reconstruct_poly( zero_poly_fn(eval_domain, missing_indices.as_slice(), subset.len() as u64); for i in 0..subset.len() { if subset[i].is_none() && zero_eval[i] != BlsScalar::zero() { - return Err("bad zero poly evaluation !".to_owned()); + return Err(ReconstructionError::BadZeroPoly); } } let mut poly_evals_with_zero: Vec = Vec::new(); @@ -377,6 +442,7 @@ fn reconstruct_poly( Ok(reconstructed_data) } +#[cfg(feature = "std")] fn expand_root_of_unity(eval_domain: EvaluationDomain) -> Vec { let root_of_unity = eval_domain.group_gen; let mut roots: Vec = vec![BlsScalar::one(), root_of_unity]; @@ -388,6 +454,7 @@ fn expand_root_of_unity(eval_domain: EvaluationDomain) -> Vec { roots } +#[cfg(feature = "std")] fn zero_poly_fn( eval_domain: EvaluationDomain, missing_indices: &[u64], @@ -419,6 +486,7 @@ fn zero_poly_fn( } // in-place shifting +#[cfg(feature = "std")] fn shift_poly(poly: &mut [BlsScalar]) { // primitive root of unity let shift_factor = BlsScalar::from(5); @@ -435,6 +503,7 @@ fn shift_poly(poly: &mut [BlsScalar]) { } // in-place unshifting +#[cfg(feature = "std")] fn unshift_poly(poly: &mut [BlsScalar]) { // primitive root of unity let shift_factor = BlsScalar::from(5); @@ -446,7 +515,8 @@ fn unshift_poly(poly: &mut [BlsScalar]) { } } -pub type AppDataRange = std::ops::Range; +pub type AppDataRange = Range; + // use this function for reconstructing back all cells of certain column // when at least 50% of them are available // @@ -455,17 +525,20 @@ pub type AppDataRange = std::ops::Range; // // performing one round of ifft should reveal original data which were // coded together +#[cfg(feature = "std")] pub fn reconstruct_column( row_count: u32, cells: &[data::DataCell], -) -> Result, String> { +) -> Result, ReconstructionError> { // just ensures all rows are from same column ! // it's required as that's how it's erasure coded during // construction in validator node - fn check_cells(cells: &[data::DataCell]) { - assert!(!cells.is_empty()); + fn check_cells(cells: &[data::DataCell]) -> bool { + if cells.is_empty() { + return false; + } let first_col = cells[0].position.col; - assert!(cells.iter().all(|c| c.position.col == first_col)); + cells.iter().all(|c| c.position.col == first_col) } // given row index in column of interest, finds it if present @@ -474,20 +547,34 @@ pub fn reconstruct_column( cells .iter() .find(|cell| cell.position.row == idx) - .map(|cell| { + .and_then(|cell| { <[u8; BlsScalar::SIZE]>::try_from(&cell.data[..]) - .expect("didn't find u8 array of length 32") + .map(|data| BlsScalar::from_bytes(&data).ok()) + .ok() + .flatten() }) - .and_then(|data| BlsScalar::from_bytes(&data).ok()) } // row count of data matrix must be power of two ! - assert!(row_count % 2 == 0); - assert!(cells.len() >= (row_count / 2) as usize && cells.len() <= row_count as usize); - check_cells(cells); - - let eval_domain = EvaluationDomain::new(row_count as usize).unwrap(); - let mut subset: Vec> = Vec::with_capacity(row_count as usize); + let row_count_sz = + usize::try_from(row_count).map_err(|_| ReconstructionError::RowCountExceeded)?; + ensure!(row_count % 2 == 0, ReconstructionError::InvalidRowCount); + ensure!( + cells.len() >= row_count_sz / 2, + ReconstructionError::MinCells(row_count_sz / 2) + ); + ensure!( + cells.len() <= row_count_sz, + ReconstructionError::MaxCells(row_count_sz) + ); + ensure!( + check_cells(cells), + ReconstructionError::CellsFromDifferentCols + ); + + let eval_domain = EvaluationDomain::new(row_count_sz) + .map_err(|_| ReconstructionError::InvalidEvaluationDomain)?; + let mut subset: Vec> = Vec::with_capacity(row_count_sz); // fill up vector in ordered fashion // @note the way it's done should be improved @@ -510,102 +597,35 @@ mod tests { use super::*; use crate::{ data::DataCell, - index::AppDataIndex, matrix::{Dimensions, Position}, }; - #[test] - fn app_data_index_cell_ranges() { - let cases = vec![ - ( - AppDataIndex { - size: 8, - index: vec![], - }, - vec![(0, 0..8)], - ), - ( - AppDataIndex { - size: 4, - index: vec![(1, 0), (2, 2)], - }, - vec![(1, 0..2), (2, 2..4)], - ), - ( - AppDataIndex { - size: 15, - index: vec![(1, 3), (12, 8)], - }, - vec![(0, 0..3), (1, 3..8), (12, 8..15)], - ), - ]; + #[test_case(0 => vec![0] ; "App 0 spans 2 rows form row 0")] + #[test_case(1 => vec![0, 2] ; "App 1 spans 2 rows from row 0")] + #[test_case(2 => vec![2] ; "App 2 spans 1 rows from row 2")] + #[test_case(3 => vec![4, 6] ; "App 3 spans 2 rows from row 4")] + #[test_case(4 => Vec::::new() ; "There is no app 4")] + fn test_app_specific_rows(id: u32) -> Vec { + let id_lens: Vec<(u32, u32)> = vec![(0, 2), (1, 3), (2, 3), (3, 8)]; + let index = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); + let dimensions = Dimensions::new(8, 4).unwrap(); - for (index, result) in cases { - assert_eq!(index.cells_ranges(), result); - } + app_specific_rows(&index, dimensions, AppId(id)) } - #[test] - fn app_data_index_data_ranges() { - let cases = vec![ - ( - AppDataIndex { - size: 8, - index: vec![], - }, - vec![(0, 0..256)], - ), - ( - AppDataIndex { - size: 4, - index: vec![(1, 0), (2, 2)], - }, - vec![(1, 0..64), (2, 64..128)], - ), - ( - AppDataIndex { - size: 15, - index: vec![(1, 3), (12, 8)], - }, - vec![(0, 0..96), (1, 96..256), (12, 256..480)], - ), - ]; - - for (index, result) in cases { - assert_eq!(index.data_ranges(), result); - } + fn to_matrix_pos(data: &[(u32, u16)]) -> Vec { + data.iter().cloned().map(Position::from).collect() } - #[test_case(0, &[0] ; "App 0 spans 2 rows form row 0")] - #[test_case(1, &[0, 2] ; "App 1 spans 2 rows from row 0")] - #[test_case(2, &[2] ; "App 2 spans 1 rows from row 2")] - #[test_case(3, &[4, 6] ; "App 3 spans 2 rows from row 4")] - #[test_case(4, &[] ; "There is no app 4")] - fn test_app_specific_rows(app_id: u32, expected: &[u32]) { - let index = AppDataIndex { - size: 16, - index: vec![(1, 2), (2, 5), (3, 8)], - }; - let dimensions = Dimensions::new(8, 4).unwrap(); - let result = app_specific_rows(&index, &dimensions, app_id); - assert_eq!(expected.len(), result.len()); - } - - #[test_case(0, &[(0, 0), (0, 1), (0, 2), (0, 3), (2, 0)] ; "App 0 has five cells")] - #[test_case(1, &[(2, 1), (2, 2), (2, 3)] ; "App 1 has 3 cells")] - #[test_case(2, &[] ; "App 2 has no cells")] - fn test_app_specific_cells(app_id: u32, expected: &[(u32, u16)]) { - let index = AppDataIndex { - size: 8, - index: vec![(1, 5)], - }; + #[test_case(0 => to_matrix_pos(&[(0, 0), (0, 1), (0, 2), (0, 3), (2, 0)]) ; "App 0 has five cells")] + #[test_case(1 => to_matrix_pos(&[(2, 1), (2, 2), (2, 3)]) ; "App 1 has 3 cells")] + #[test_case(2 => Vec::::new() ; "App 2 has no cells")] + fn test_app_specific_cells(app_id: u32) -> Vec { + let id_lens: Vec<(u32, usize)> = vec![(0, 5), (1, 3)]; + let index = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); let dimensions = Dimensions::new(4, 4).unwrap(); - let result = app_specific_cells(&index, &dimensions, app_id).unwrap_or_default(); - assert_eq!(expected.len(), result.len()); - result.iter().zip(expected).for_each(|(a, &(row, col))| { - assert_eq!(a.row, row); - assert_eq!(a.col, col); - }); + + app_specific_cells(&index, dimensions, AppId(app_id)).unwrap_or_default() } #[test] diff --git a/kate/recovery/src/commitments.rs b/kate/recovery/src/commitments.rs index 419ab885..9cde4d75 100644 --- a/kate/recovery/src/commitments.rs +++ b/kate/recovery/src/commitments.rs @@ -1,26 +1,26 @@ -use std::{ - array::TryFromSliceError, - convert::{TryFrom, TryInto}, - num::TryFromIntError, -}; - +use crate::config::COMMITMENT_SIZE; +use core::{array::TryFromSliceError, convert::TryInto, num::TryFromIntError}; +use sp_std::prelude::*; +use thiserror_no_std::Error; + +#[cfg(feature = "std")] +use crate::{com, config, matrix}; +#[cfg(feature = "std")] +use avail_core::{ensure, AppId, DataLookup}; +#[cfg(feature = "std")] +use core::convert::TryFrom; +#[cfg(feature = "std")] use dusk_bytes::Serializable; +#[cfg(feature = "std")] use dusk_plonk::{ fft::{EvaluationDomain, Evaluations}, - prelude::{BlsScalar, PublicParameters}, -}; -use thiserror::Error; - -use crate::{ - com, - config::{self, COMMITMENT_SIZE}, - index, matrix, + prelude::{BlsScalar, CommitKey, PublicParameters}, }; #[derive(Error, Debug)] -pub enum DataError { +pub enum Error { #[error("Scalar slice error: {0}")] - SliceError(TryFromSliceError), + SliceError(#[from] TryFromSliceError), #[error("Scalar data is not valid")] ScalarDataError, #[error("Invalid scalar data length")] @@ -29,58 +29,54 @@ pub enum DataError { BadScalarData, #[error("Bad data len")] BadLen, - #[error("Plonk error: {0}")] - PlonkError(dusk_plonk::error::Error), + #[error("Plonk error")] + PlonkError, #[error("Bad commitments data")] BadCommitmentsData, #[error("Bad rows data")] BadRowsData, + #[error("Integer conversion error")] + IntError(#[from] TryFromIntError), } -#[derive(Error, Debug)] -pub enum Error { - #[error("Invalid data: {0}")] - InvalidData(DataError), -} - -impl From for Error { - fn from(e: TryFromSliceError) -> Self { - Self::InvalidData(DataError::SliceError(e)) - } -} - -impl From for Error { - fn from(_: TryFromIntError) -> Self { - Self::InvalidData(DataError::BadCommitmentsData) +#[cfg(feature = "std")] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self { + Self::SliceError(slice) => Some(slice), + Self::IntError(try_int) => Some(try_int), + _ => None, + } } } +#[cfg(feature = "std")] impl From for Error { fn from(e: dusk_bytes::Error) -> Self { match e { - dusk_bytes::Error::InvalidData => Self::InvalidData(DataError::ScalarDataError), - dusk_bytes::Error::BadLength { .. } => Self::InvalidData(DataError::BadScalarDataLen), - dusk_bytes::Error::InvalidChar { .. } => Self::InvalidData(DataError::BadScalarData), + dusk_bytes::Error::InvalidData => Self::ScalarDataError, + dusk_bytes::Error::BadLength { .. } => Self::BadScalarDataLen, + dusk_bytes::Error::InvalidChar { .. } => Self::BadScalarData, } } } - +#[cfg(feature = "std")] impl From for Error { - fn from(e: dusk_plonk::error::Error) -> Self { - Self::InvalidData(DataError::PlonkError(e)) + fn from(_: dusk_plonk::error::Error) -> Self { + Self::PlonkError } } +#[cfg(feature = "std")] fn try_into_scalar(chunk: &[u8]) -> Result { let sized_chunk = <[u8; config::CHUNK_SIZE]>::try_from(chunk)?; BlsScalar::from_bytes(&sized_chunk).map_err(From::from) } +#[cfg(feature = "std")] fn try_into_scalars(data: &[u8]) -> Result, Error> { let chunks = data.chunks_exact(config::CHUNK_SIZE); - if !chunks.remainder().is_empty() { - return Err(Error::InvalidData(DataError::BadLen)); - } + ensure!(chunks.remainder().is_empty(), Error::BadLen); chunks .map(try_into_scalar) .collect::, Error>>() @@ -99,26 +95,27 @@ fn try_into_scalars(data: &[u8]) -> Result, Error> { /// * `index` - Application data index /// * `dimensions` - Extended matrix dimensions /// * `app_id` - Application ID +#[cfg(feature = "std")] pub fn verify_equality( public_params: &PublicParameters, commitments: &[[u8; COMMITMENT_SIZE]], rows: &[Option>], - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, - app_id: u32, + index: &DataLookup, + dimensions: matrix::Dimensions, + app_id: AppId, ) -> Result<(Vec, Vec), Error> { - if commitments.len() != dimensions.extended_rows().try_into()? { - return Err(Error::InvalidData(DataError::BadCommitmentsData)); - } - + let ext_rows: usize = dimensions.extended_rows().try_into()?; + ensure!(commitments.len() == ext_rows, Error::BadCommitmentsData); let mut app_rows = com::app_specific_rows(index, dimensions, app_id); - if rows.len() != dimensions.extended_rows().try_into()? { + if rows.len() != ext_rows { return Ok((vec![], app_rows)); } - let (prover_key, _) = public_params.trim(dimensions.cols() as usize)?; - let domain = EvaluationDomain::new(dimensions.cols() as usize)?; + let dim_cols = dimensions.width(); + // @TODO Opening Key here??? + let (prover_key, _) = public_params.trim(dim_cols)?; + let domain = EvaluationDomain::new(dim_cols)?; // This is a single-threaded implementation. // At some point we should benchmark and decide @@ -128,11 +125,8 @@ pub fn verify_equality( .zip(rows.iter()) .zip(0u32..) .filter(|(.., index)| app_rows.contains(index)) - .filter_map(|((&commitment, row), index)| { - try_into_scalars(row.as_ref()?) - .map(|scalars| Evaluations::from_vec_and_domain(scalars, domain).interpolate()) - .and_then(|polynomial| prover_key.commit(&polynomial).map_err(From::from)) - .map(|result| (result.to_bytes() == commitment).then_some(index)) + .filter_map(|((commitment, maybe_row), index)| { + row_index_commitment_verification(&prover_key, domain, commitment, maybe_row, index) .transpose() }) .collect::, Error>>()?; @@ -142,6 +136,26 @@ pub fn verify_equality( Ok((verified, app_rows)) } +#[cfg(feature = "std")] +fn row_index_commitment_verification( + prover_key: &CommitKey, + domain: EvaluationDomain, + commitment: &[u8], + maybe_row: &Option>, + index: u32, +) -> Result, Error> { + if let Some(row) = maybe_row.as_ref() { + let scalars = try_into_scalars(row)?; + let polynomial = Evaluations::from_vec_and_domain(scalars, domain).interpolate(); + let result = prover_key.commit(&polynomial)?; + + if result.to_bytes() == commitment { + return Ok(Some(index)); + } + } + Ok(None) +} + /// Creates vector of exact size commitments, from commitments slice pub fn from_slice(source: &[u8]) -> Result, TryFromSliceError> { source @@ -152,18 +166,14 @@ pub fn from_slice(source: &[u8]) -> Result, TryFromSl #[cfg(test)] mod tests { + use super::verify_equality; + use avail_core::{AppId, DataLookup}; use dusk_plonk::prelude::PublicParameters; use once_cell::sync::Lazy; use rand::SeedableRng; use rand_chacha::ChaChaRng; - use crate::{ - commitments, - index::{self, AppDataIndex}, - matrix, - }; - - use super::verify_equality; + use crate::{commitments, matrix}; static PUBLIC_PARAMETERS: Lazy = Lazy::new(|| PublicParameters::setup(256, &mut ChaChaRng::seed_from_u64(42)).unwrap()); @@ -174,9 +184,9 @@ mod tests { &PUBLIC_PARAMETERS, &[], &[], - &index::AppDataIndex::default(), - &matrix::Dimensions::new(1, 1).unwrap(), - 0, + &DataLookup::default(), + matrix::Dimensions::new(1, 1).unwrap(), + AppId(0), ) .is_err()); } @@ -193,42 +203,38 @@ mod tests { let row_4 = Some(hex::decode("722c20416c65782073657473206f757420746f207265736375652074686520006b696e67646f6d2e204f6e206869732071756573742c206865206465666561007473204a616e6b656e27732068656e63686d656e20616e64207265747269650076657320766172696f7573206974656d73207768696368206c656164206869006d20746f77617264204a616e6b656e2077686f6d20686520646566656174730020616e642073656573207475726e656420746f2073746f6e652e20416c65780020726574726965766573207468652063726f776e2c20616e6420746865207000656f706c65206f6620526164617869616e2061726520726573746f7265642000756e64657220746865206e65776c792063726f776e6564204b696e67204567006c652e800000000000000000000000000000000000000000000000000000000004fd01412072656d616b65206f66207468652067616d652c207469746c65640020416c6578204b69646420696e204d697261636c6520576f726c642044582c002077617320616e6e6f756e636564206f6e204a756e652031302c2032303230002c20616e642072656c6561736564206f6e204a756e652032322c2032303231002e2054686520800000000000000000000000000000000000000000000000000076a04053bda0a88bda5177b86a15c3b29f559873cb481232299cd5743151ac004b2d63ae198e7bb0a9011f28e473c95f4013d7d53ec5fbc3b42df8ed101f6d00e831e52bfb76e51cca8b4e9016838657edfae09cb9a71eb219025c4c87a67c004aaa86f20ac0aa792bc121ee42e2c326127061eda15599cb5db3db870bea5a00ecf353161c3cb528b0c5d98050c4570bfc942d8b19ed7b0cbba5725e03e5f000b7e30db36b6df82ac151f668f5f80a5e2a9cac7c64991dd6a6ce21c060175800edb9260d2a86c836efc05f17e5c59525e404c6a93d051651fe2e4eefae2813004925683890a942f63ce493f512f0b2cfb7c42a07ce9130cb6d059a388d886100536cb9c5b81a9a8dc46c2d64a7a5b1d93b2d8646805d8d2a122fccdb3bc7dc00975ab75fc865793536f66e64189050360f623dc88abb8300180cdd0a8f33d700d2159b3df296b46dd64bec57609a3f2fb4ad8b46e2fd4c9f25d44328dd50ce00514db7bbf50ef518c195a7053763d0a8dfdab6b946ee9f3954549319ac7dc600bac203232876b27b541433fb2f1438289799049b349f7a2c205d3a97f66ef4002800baa3cb78fb33130181775fb26a62630236bd8bc644a3656489d135ba1800b11846029a9183d434593cbbc1e03a4f8dba40cf6cfa07ba043c83f6a4888700364c233191a4b99aff1e9b8ab2aba54ecc61a6a8d2a50043e8948be1e76a43007d348990b99e55fee2a4bc79b29b27f2f9720e96840517dc8a0be65757110400").unwrap()); - let size = 79; - let index = vec![(1, 1), (2, 74)]; + let id_lens: Vec<(u32, u32)> = vec![(0, 1), (1, 73), (2, 6)]; + let lookup = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); + let dimension = matrix::Dimensions::new(4, 32).unwrap(); + let id = AppId(1); let result = verify_equality( &PUBLIC_PARAMETERS, &commitments, &[row_0.clone(), None, row_2, None, row_4, None, None, None], - &AppDataIndex { size, index }, - &matrix::Dimensions::new(4, 32).unwrap(), - 1, + &lookup, + dimension, + id, ); assert_eq!(result.unwrap(), (vec![0, 2, 4], vec![])); - let size = 79; - let index = vec![(1, 1), (2, 74)]; - let result = verify_equality( &PUBLIC_PARAMETERS, &commitments, &[row_0, None, None, None, None, None, None, None], - &AppDataIndex { size, index }, - &matrix::Dimensions::new(4, 32).unwrap(), - 1, + &lookup, + dimension, + id, ); assert_eq!(result.unwrap(), (vec![0], vec![2, 4])); - let size = 79; - let index = vec![(1, 1), (2, 74)]; - let result = verify_equality( &PUBLIC_PARAMETERS, &commitments, &[None, None, None, None, None, None, None, None], - &AppDataIndex { size, index }, - &matrix::Dimensions::new(4, 32).unwrap(), - 1, + &lookup, + dimension, + id, ); assert_eq!(result.unwrap(), (vec![], vec![0, 2, 4])); } diff --git a/kate/recovery/src/data.rs b/kate/recovery/src/data.rs index 7d47d049..d55fab75 100644 --- a/kate/recovery/src/data.rs +++ b/kate/recovery/src/data.rs @@ -1,9 +1,11 @@ -use std::{collections::HashMap, convert::TryInto}; +use core::convert::TryInto; +use derive_more::Constructor; +use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; use crate::matrix::{Dimensions, Position, RowIndex}; /// Position and data of a cell in extended matrix -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Constructor)] pub struct DataCell { /// Cell's position pub position: Position, @@ -12,7 +14,7 @@ pub struct DataCell { } /// Position and content of a cell in extended matrix -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Constructor)] pub struct Cell { /// Cell's position pub position: Position, @@ -21,6 +23,7 @@ pub struct Cell { } impl Cell { + #[cfg(feature = "std")] pub fn reference(&self, block: u32) -> String { self.position.reference(block) } @@ -36,13 +39,13 @@ impl Cell { /// Merges cells data per row. /// Cells are sorted before merge. -pub fn rows(dimensions: &Dimensions, cells: &[&Cell]) -> Vec<(RowIndex, Vec)> { +pub fn rows(dimensions: Dimensions, cells: &[&Cell]) -> Vec<(RowIndex, Vec)> { let mut sorted_cells = cells.to_vec(); sorted_cells .sort_by(|a, b| (a.position.row, a.position.col).cmp(&(b.position.row, b.position.col))); - let mut rows = HashMap::new(); + let mut rows = BTreeMap::new(); for cell in sorted_cells { rows.entry(RowIndex(cell.position.row)) .or_insert_with(Vec::default) @@ -56,7 +59,7 @@ pub fn rows(dimensions: &Dimensions, cells: &[&Cell]) -> Vec<(RowIndex, Vec) impl From for DataCell { fn from(cell: Cell) -> Self { DataCell { - position: cell.position.clone(), + position: cell.position, data: cell.data(), } } @@ -95,7 +98,7 @@ mod tests { &cell(position(0, 1), content([1; 32])), ]; - let mut rows = rows(&dimensions, &cells); + let mut rows = rows(dimensions, &cells); rows.sort_by_key(|(key, _)| key.0); let expected = [ @@ -120,10 +123,10 @@ mod tests { &cell(position(0, 1), content([1; 32])), ]; - let mut rows = rows(&dimensions, &cells); + let mut rows = rows(dimensions, &cells); rows.sort_by_key(|(key, _)| key.0); - assert!(rows.len() == 1); + assert_eq!(rows.len(), 1); let (row_index, row) = &rows[0]; assert_eq!(row_index.0, 0); assert_eq!(*row, [[0u8; 32], [1u8; 32]].concat()); diff --git a/kate/recovery/src/index.rs b/kate/recovery/src/index.rs deleted file mode 100644 index 61145ac5..00000000 --- a/kate/recovery/src/index.rs +++ /dev/null @@ -1,118 +0,0 @@ -use std::{convert::TryFrom, iter::once, ops::Range}; - -use serde::{Deserialize, Serialize}; - -use crate::config; - -/// Index is list of pairs (app_id, start_index), -/// where start index is index of first cell for that application. -#[derive(Serialize, Deserialize, Default, Debug, Clone)] -pub struct AppDataIndex { - /// Number of the data cells in the matrix - pub size: u32, - /// Data index per application - pub index: Vec<(u32, u32)>, -} - -#[derive(PartialEq, Eq, Debug)] -pub enum AppDataIndexError { - SizeOverflow, - UnsortedLayout, -} - -impl AppDataIndex { - /// Calculates cell ranges per application from extrinsic offsets. - /// Range is from start index to end index in matrix. - pub fn cells_ranges(&self) -> Vec<(u32, Range)> { - // Case if first app_id in index is zero is ignored - // since it should be asserted elsewhere - let prepend = self.index.first().map_or(vec![(0, 0)], |&(_, offset)| { - if offset == 0 { - vec![] - } else { - vec![(0, 0)] - } - }); - - let starts = prepend.iter().chain(self.index.iter()); - - let ends = self - .index - .iter() - .skip_while(|&&(_, offset)| offset == 0) - .map(|&(_, offset)| offset) - .chain(once(self.size)); - - starts - .zip(ends) - .map(|(&(app_id, start), end)| (app_id, (start..end))) - .collect::>() - } - - pub fn app_cells_range(&self, app_id: u32) -> Option> { - self.cells_ranges() - .into_iter() - .find(|&(id, _)| app_id == id) - .map(|(_, range)| range) - } - - fn app_cells_ranges(&self, app_id: u32) -> Vec> { - self.cells_ranges() - .into_iter() - .filter(|&(id, _)| app_id == id) - .map(|(_, range)| range) - .collect::>() - } - - /// Calculates data range per application from extrinsics layout. - /// Range is from start index to end index in matrix flattened as byte array. - pub fn data_ranges(&self) -> Vec<(u32, Range)> { - const CHUNK_SIZE_U32: u32 = config::CHUNK_SIZE as u32; - self.cells_ranges() - .into_iter() - .map(|(app_id, Range { start, end })| { - (app_id, (start * CHUNK_SIZE_U32..end * CHUNK_SIZE_U32)) - }) - .collect::>() - } - - pub fn app_data_ranges(&self, app_id: u32) -> Vec<(u32, Range)> { - const CHUNK_SIZE_U32: u32 = config::CHUNK_SIZE as u32; - self.app_cells_ranges(app_id) - .iter() - .map(|Range { start, end }| (app_id, (start * CHUNK_SIZE_U32..end * CHUNK_SIZE_U32))) - .collect::>() - } -} - -impl TryFrom<&[(T, u32)]> for AppDataIndex -where - T: Clone + Into, -{ - type Error = AppDataIndexError; - - fn try_from(layout: &[(T, u32)]) -> Result { - let mut index = Vec::new(); - // transactions are ordered by application id - // skip transactions with 0 application id - it's not a data txs - let mut size = 0u32; - let mut prev_app_id = 0u32; - - for (app_id, data_len) in layout { - let app_id: u32 = app_id.clone().into(); - if app_id != 0 && prev_app_id != app_id { - index.push((app_id, size)); - } - - size = size - .checked_add(*data_len) - .ok_or(Self::Error::SizeOverflow)?; - if prev_app_id > app_id { - return Err(Self::Error::UnsortedLayout); - } - prev_app_id = app_id; - } - - Ok(AppDataIndex { size, index }) - } -} diff --git a/kate/recovery/src/lib.rs b/kate/recovery/src/lib.rs index 48f158ea..fcc8c3a4 100644 --- a/kate/recovery/src/lib.rs +++ b/kate/recovery/src/lib.rs @@ -1,9 +1,13 @@ +#![cfg_attr(not(feature = "std"), no_std)] + pub mod com; pub mod commitments; pub mod config; pub mod data; -pub mod index; pub mod matrix; pub mod proof; +#[cfg(feature = "std")] +pub mod sparse_slice_read; + #[cfg(feature = "std")] pub mod testnet; diff --git a/kate/recovery/src/matrix.rs b/kate/recovery/src/matrix.rs index 5c81697a..b86fbb00 100644 --- a/kate/recovery/src/matrix.rs +++ b/kate/recovery/src/matrix.rs @@ -1,22 +1,61 @@ -use std::ops::Range; - -use serde::{Deserialize, Serialize}; - use crate::config::{self, CHUNK_SIZE}; +use core::{ + convert::TryInto, + fmt::{Display, Formatter, Result}, + num::NonZeroU16, + ops::{Mul, Range}, +}; +use derive_more::Constructor; +use sp_std::prelude::*; +use sp_std::vec; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; const EXTENSION_FACTOR_U32: u32 = config::EXTENSION_FACTOR as u32; /// Position of a cell in the the matrix. -#[derive(Default, Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Default, Debug, Clone, Copy, Hash, Eq, PartialEq, Constructor)] pub struct Position { pub row: u32, pub col: u16, } +impl From<(R, C)> for Position +where + u32: From, + u16: From, +{ + fn from(row_col: (R, C)) -> Self { + Self { + row: row_col.0.into(), + col: row_col.1.into(), + } + } +} + +impl From for (R, C) +where + R: From, + C: From, +{ + fn from(p: Position) -> (R, C) { + (p.row.into(), p.col.into()) + } +} + +impl Display for Position { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.write_fmt(format_args!("{}:{}", self.col, self.row)) + } +} + impl Position { /// Refrence in format `block_number:column_number:row_number` + #[cfg(feature = "std")] pub fn reference(&self, block_number: u32) -> String { - format!("{}:{}:{}", block_number, self.col, self.row) + format!("{}:{}", block_number, self) } /// Checks if position is from extended row @@ -26,18 +65,20 @@ impl Position { } /// Matrix partition (column-wise) -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Partition { pub number: u8, pub fraction: u8, } /// Matrix row index -#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct RowIndex(pub u32); impl RowIndex { /// Refrence in format `block_number:row_number` + #[cfg(feature = "std")] pub fn reference(&self, block_number: u32) -> String { format!("{}:{}", block_number, self.0) } @@ -57,72 +98,145 @@ impl RowIndex { /// Extended columns (EC is erasure code): [1,EC,5,EC], [2,EC,6,EC], [3,EC,7,EC], [4,EC,8,EC] /// Matrix representation: [1,5,2,6,3,7,4,8] /// Extended matrix representation: [1,EC,5,EC,2,EC,6,EC,3,EC,7,EC,4,EC,8,EC] -#[derive(Debug, Clone)] +#[derive(Copy, Debug, Clone, PartialEq, Eq)] pub struct Dimensions { - rows: u16, - cols: u16, + rows: NonZeroU16, + cols: NonZeroU16, +} + +impl From<(R, C)> for Dimensions +where + R: Into, + C: Into, +{ + fn from(rows_cols: (R, C)) -> Self { + let (rows, cols) = rows_cols; + Self { + rows: rows.into(), + cols: cols.into(), + } + } +} + +impl From for (R, C) +where + R: From, + C: From, +{ + fn from(d: Dimensions) -> Self { + (d.rows.get().into(), d.cols.get().into()) + } } impl Dimensions { - /// Creates new matrix dimensions. - /// Data layout is assumed to be row-wise. - /// Returns `None` if rows or cols is 0. - pub const fn new(rows: u16, cols: u16) -> Option { - if rows == 0 || cols == 0 { - return None; + pub fn new, C: TryInto>(rows: R, cols: C) -> Option { + let rows = rows.try_into().ok()?; + let cols = cols.try_into().ok()?; + + Some(Self { rows, cols }) + } + + pub fn new_from, C: TryInto>(rows: R, cols: C) -> Option { + let rows: u16 = rows.try_into().ok()?; + let cols: u16 = cols.try_into().ok()?; + + Self::new(rows, cols) + } + + /// Creates a `Dimension` without checking whether parameters are non-zero. This results in + /// undefined behaviour if any parameter is zero. + /// + /// # Safety + /// Parameters `rows` and `cols` must not be zero. + pub const unsafe fn new_unchecked(rows: u16, cols: u16) -> Self { + Self { + rows: NonZeroU16::new_unchecked(rows), + cols: NonZeroU16::new_unchecked(cols), } - Some(Dimensions { rows, cols }) } /// Returns number of rows - pub fn rows(&self) -> u16 { + #[inline] + pub fn rows(&self) -> NonZeroU16 { self.rows } + /// Returns number of rows, which is always greater than zero. + /// + /// # SAFETY + /// As internal member is `NonZeroU16`, this always returns greater than zero. + #[inline] + pub fn height(&self) -> usize { + NonZeroU16::get(self.rows).into() + } + /// Returns number of columns - pub fn cols(&self) -> u16 { + #[inline] + pub fn cols(&self) -> NonZeroU16 { self.cols } + /// Returns number of cols, which is always greater than zero. + /// + /// # SAFETY + /// As internal member is `NonZeroU16`, this always returns greater than zero. + #[inline] + pub fn width(&self) -> usize { + NonZeroU16::get(self.cols).into() + } + /// Matrix size. - pub fn size(&self) -> u32 { - self.rows as u32 * self.cols as u32 + pub fn size + Mul>(&self) -> T { + T::from(self.rows.get()) * T::from(self.cols.get()) + } + + pub fn divides(&self, other: &Self) -> bool { + other.cols.get() % self.cols == 0u16 && other.rows.get() % self.rows == 0u16 + } + + /// Extends rows by `row_factor` and cols by `col_factor`. + pub fn extend(&self, row_factor: NonZeroU16, col_factor: NonZeroU16) -> Option { + let rows = self.rows.checked_mul(row_factor)?; + let cols = self.cols.checked_mul(col_factor)?; + + Some(Self { rows, cols }) } /// Extended matrix size. - pub fn extended_size(&self) -> u64 { - self.extended_rows() as u64 * self.cols as u64 + pub fn extended_size(&self) -> u32 { + self.extended_rows() * u32::from(self.cols.get()) } /// Row size in bytes pub fn row_byte_size(&self) -> usize { - CHUNK_SIZE * self.cols as usize + CHUNK_SIZE * self.width() } /// Extended matrix rows count. pub fn extended_rows(&self) -> u32 { - (self.rows as u32) * EXTENSION_FACTOR_U32 + u32::from(self.rows.get()) * EXTENSION_FACTOR_U32 } /// List of data row indexes in the extended matrix. - pub fn extended_data_rows(&self, cells: Range) -> Vec { - assert!(cells.end <= self.size()); - if cells.end == 0 { - return vec![]; + pub fn extended_data_rows(&self, cells: Range) -> Option> { + // Invalid range returns `None` + if cells.end > self.size() || cells.end == 0 { + return None; } let first_row = self.extended_data_row(cells.start); let last_row = self.extended_data_row(cells.end - 1); - (first_row..=last_row) + let data = (first_row..=last_row) .step_by(config::EXTENSION_FACTOR) - .collect::>() + .collect::>(); + Some(data) } /// Cell positions for given column in extended matrix. /// Empty if column index is not valid. pub fn col_positions(&self, col: u16) -> Vec { - if self.cols() <= col { + if self.cols().get() <= col { return vec![]; } (0..self.extended_rows()) @@ -136,7 +250,7 @@ impl Dimensions { if self.extended_rows() <= row { return vec![]; } - (0..self.cols()) + (0..self.cols().get()) .map(|col| Position { col, row }) .collect::>() } @@ -151,12 +265,12 @@ impl Dimensions { /// Column index of a cell in the matrix. fn col(&self, cell: u32) -> u16 { - (cell % self.cols as u32) as u16 + (cell % u32::from(self.cols.get())) as u16 } /// Extended matrix data row index of cell in the data matrix. fn extended_data_row(&self, cell: u32) -> u32 { - (cell / self.cols as u32) * EXTENSION_FACTOR_U32 + (cell / u32::from(self.cols.get())) * EXTENSION_FACTOR_U32 } /// Extended matrix data position of a cell in the data matrix. @@ -168,16 +282,17 @@ impl Dimensions { } /// Extended matrix data positions for given data matrix cells range. - pub fn extended_data_positions(&self, cells: Range) -> Vec { - assert!(cells.end <= self.size()); - cells - .map(|cell| self.extended_data_position(cell)) - .collect::>() + pub fn extended_data_positions(&self, cells: Range) -> Option> { + (cells.end <= self.size()).then(|| { + cells + .map(|cell| self.extended_data_position(cell)) + .collect::>() + }) } /// Checks if extended matrix contains given position. pub fn extended_contains(&self, position: &Position) -> bool { - position.row < self.extended_rows() && position.col < self.cols + position.row < self.extended_rows() && position.col < self.cols.get() } /// Creates iterator over rows in extended matrix. @@ -187,26 +302,27 @@ impl Dimensions { /// Creates iterator over data cells in data matrix (used to retrieve data from the matrix). pub fn iter_data(&self) -> impl Iterator { - let rows = self.rows as usize; - let cols = self.cols as usize; + let rows = self.height(); + let cols = self.width(); (0..rows).flat_map(move |row| (0..cols).map(move |col| (row, col))) } /// Creates iterator over cell indexes in data matrix (used to store data in the matrix). pub fn iter_cells(&self) -> impl Iterator { - let rows = self.rows as u32; - let cols = self.cols; - (0..cols).flat_map(move |col| (0..rows).map(move |row| row * cols as u32 + col as u32)) + let rows: u32 = self.rows.get().into(); + let cols: u32 = self.cols.get().into(); + (0..cols).flat_map(move |col| (0..rows).map(move |row| row * cols + col)) } /// Creates iterator over data positions by row in extended matrix. pub fn iter_extended_data_positions(&self) -> impl Iterator { - let rows = self.rows as u32; - let cols = self.cols; + let rows: u32 = self.rows.get().into(); + let cols = self.cols.get(); (0..rows).flat_map(move |row| (0..cols).map(move |col| (row * EXTENSION_FACTOR_U32, col))) } /// Generates cell positions for given block partition + #[cfg(feature = "std")] pub fn iter_extended_partition_positions( &self, partition: &Partition, @@ -214,13 +330,20 @@ impl Dimensions { let size = (self.extended_size() as f64 / partition.fraction as f64).ceil() as u32; let start = size * (partition.number - 1) as u32; let end = size * (partition.number as u32); - let cols: u32 = self.cols().into(); + let cols: u32 = self.cols.get().into(); (start..end).map(move |cell| Position { row: cell / cols, col: (cell % cols) as u16, }) } + + pub fn transpose(self) -> Self { + Self { + rows: self.cols, + cols: self.rows, + } + } } #[cfg(test)] @@ -274,6 +397,6 @@ mod tests { .unwrap() .iter_extended_partition_positions(&Partition { number, fraction }) .zip(expected.iter().map(|&(row, col)| Position { row, col })) - .for_each(|(p1, p2)| assert!(p1 == p2)); + .for_each(|(p1, p2)| assert_eq!(p1, p2)); } } diff --git a/kate/recovery/src/proof.rs b/kate/recovery/src/proof.rs index c30c60fe..1e867d5e 100644 --- a/kate/recovery/src/proof.rs +++ b/kate/recovery/src/proof.rs @@ -1,34 +1,43 @@ +#[cfg(feature = "std")] use dusk_bytes::Serializable; +#[cfg(feature = "std")] use dusk_plonk::{ bls12_381::G1Affine, commitment_scheme::kzg10::{commitment::Commitment, proof::Proof, PublicParameters}, fft::EvaluationDomain, prelude::BlsScalar, }; -use thiserror::Error; +use thiserror_no_std::Error; use crate::{config::COMMITMENT_SIZE, data::Cell, matrix::Dimensions}; #[derive(Error, Debug)] pub enum Error { - #[error("Proof, data or commitment is not valid: {0}")] - InvalidData(String), - #[error("Evaluation domain is not valid for given dimensions: {0}")] - InvalidDomain(String), - #[error("Public parameters degree is to small for given dimensions: {0}")] - InvalidDegree(String), + #[error("Proof, data or commitment is not valid")] + InvalidData, + #[error("Evaluation domain is not valid for given dimensions")] + InvalidDomain, + #[error("Public parameters degree is to small for given dimensions")] + InvalidDegree, + #[error("Position isn't in domain")] + InvalidPositionInDomain, } +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +#[cfg(feature = "std")] impl From for Error { - fn from(error: dusk_bytes::Error) -> Self { - Error::InvalidData(format!("{error:?}")) + fn from(_: dusk_bytes::Error) -> Self { + Error::InvalidData } } /// Verifies proof for given cell +#[cfg(feature = "std")] pub fn verify( public_parameters: &PublicParameters, - dimensions: &Dimensions, + dimensions: Dimensions, commitment: &[u8; COMMITMENT_SIZE], cell: &Cell, ) -> Result { @@ -44,14 +53,15 @@ pub fn verify( commitment_to_polynomial, }; - let point = EvaluationDomain::new(dimensions.cols().into()) - .map_err(|error| Error::InvalidDomain(format!("{error:?}")))? + let cols: usize = dimensions.width(); + let point = EvaluationDomain::new(cols) + .map_err(|_| Error::InvalidDomain)? .elements() .nth(cell.position.col.into()) - .ok_or_else(|| Error::InvalidDomain("Position isn't in domain".to_string()))?; + .ok_or(Error::InvalidPositionInDomain)?; public_parameters - .trim(dimensions.cols().into()) + .trim(cols) .map(|(_, verifier_key)| verifier_key.check(point, proof)) - .map_err(|error| Error::InvalidDegree(format!("{error:?}"))) + .map_err(|_| Error::InvalidDegree) } diff --git a/kate/recovery/src/sparse_slice_read.rs b/kate/recovery/src/sparse_slice_read.rs new file mode 100644 index 00000000..7a1bdb8a --- /dev/null +++ b/kate/recovery/src/sparse_slice_read.rs @@ -0,0 +1,51 @@ +use core::iter::FromIterator; +use std::{ + collections::VecDeque, + io::{Read, Result}, +}; + +/// It is a Codec Reader which allows decoding from non-sequential data. +pub struct SparseSliceRead<'a> { + parts: VecDeque<&'a [u8]>, +} + +impl<'a> FromIterator<&'a [u8]> for SparseSliceRead<'a> { + fn from_iter>(iter: I) -> Self { + let parts = VecDeque::from_iter(iter); + Self { parts } + } +} + +impl<'a> Read for SparseSliceRead<'a> { + fn read(&mut self, mut buf: &mut [u8]) -> Result { + let mut bytes = 0usize; + + loop { + let buf_len = buf.len(); + if buf_len == 0 || self.parts.is_empty() { + break; + } + + if let Some(next_part) = self.parts.pop_front() { + // Define max copied bytes and pending for next iteration. + let copied_len = std::cmp::min(next_part.len(), buf_len); + bytes += copied_len; + + // Copy data into `buf`. + let (source, pending_next_part) = next_part.split_at(copied_len); + let (dest, pending_buf) = buf.split_at_mut(copied_len); + dest.copy_from_slice(source); + + // Advance output buffer. + buf = pending_buf; + + // Reinsert if it is still pending + if !pending_next_part.is_empty() { + self.parts.push_front(pending_next_part); + } + } + } + + Ok(bytes) + } +} diff --git a/kate/recovery/src/testnet.rs b/kate/recovery/src/testnet.rs index 4739490c..0ead1dca 100644 --- a/kate/recovery/src/testnet.rs +++ b/kate/recovery/src/testnet.rs @@ -2,8 +2,6 @@ use std::{collections::HashMap, sync::Mutex}; use dusk_plonk::commitment_scheme::kzg10::PublicParameters; use once_cell::sync::Lazy; -use rand::SeedableRng; -use rand_chacha::ChaChaRng; static SRS_DATA: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); @@ -13,6 +11,8 @@ pub fn public_params(max_degree: usize) -> PublicParameters { srs_data_locked .entry(max_degree) .or_insert_with(|| { + use rand_chacha::{rand_core::SeedableRng as _, ChaChaRng}; + let mut rng = ChaChaRng::seed_from_u64(42); PublicParameters::setup(max_degree, &mut rng).unwrap() }) diff --git a/kate/src/com.rs b/kate/src/com.rs index 22e8a02a..4a513143 100644 --- a/kate/src/com.rs +++ b/kate/src/com.rs @@ -1,14 +1,16 @@ +use core::num::NonZeroU32; use std::{ convert::{TryFrom, TryInto}, mem::size_of, + num::TryFromIntError, time::Instant, }; -use codec::Encode; -use da_primitives::{ - asdr::{AppExtrinsic, AppId}, - BlockLengthColumns, BlockLengthRows, +use avail_core::{ + data_lookup::Error as DataLookupError, ensure, AppExtrinsic, AppId, BlockLengthColumns, + BlockLengthRows, DataLookup, }; +use codec::Encode; use derive_more::Constructor; use dusk_bytes::Serializable; use dusk_plonk::{ @@ -17,44 +19,80 @@ use dusk_plonk::{ fft::{EvaluationDomain, Evaluations}, prelude::{BlsScalar, CommitKey}, }; -use frame_support::{ensure, sp_runtime::SaturatedConversion}; #[cfg(feature = "std")] -use kate_recovery::{com::app_specific_rows, index, matrix}; -use rand::{Rng, SeedableRng}; -use rand_chacha::ChaChaRng; +use kate_recovery::matrix::Dimensions; +use nalgebra::base::DMatrix; +use rand_chacha::{ + rand_core::{Error as ChaChaError, RngCore, SeedableRng}, + ChaChaRng, +}; use rayon::prelude::*; +#[cfg(feature = "std")] use serde::{Deserialize, Serialize}; +use sp_arithmetic::traits::SaturatedConversion; use static_assertions::const_assert_eq; +use thiserror_no_std::Error; use crate::{ + com::kzg10::commitment::Commitment, config::{ - DATA_CHUNK_SIZE, EXTENSION_FACTOR, MAXIMUM_BLOCK_SIZE, MINIMUM_BLOCK_SIZE, PROOF_SIZE, - PROVER_KEY_SIZE, SCALAR_SIZE, + COL_EXTENSION, DATA_CHUNK_SIZE, EXTENSION_FACTOR, MAXIMUM_BLOCK_SIZE, MINIMUM_BLOCK_SIZE, + PROOF_SIZE, ROW_EXTENSION, SCALAR_SIZE, }, metrics::Metrics, - padded_len_of_pad_iec_9797_1, BlockDimensions, Seed, LOG_TARGET, + padded_len_of_pad_iec_9797_1, BlockDimensions, Seed, TryFromBlockDimensionsError, LOG_TARGET, + U32_USIZE_ERR, }; #[cfg(feature = "std")] use kate_recovery::testnet; -#[derive(Serialize, Deserialize, Constructor, Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Constructor, Clone, Copy, PartialEq, Eq, Debug)] pub struct Cell { pub row: BlockLengthRows, pub col: BlockLengthColumns, } -#[derive(Debug)] +#[derive(Error, Debug)] pub enum Error { - PlonkError(PlonkError), - CellLenghtExceeded, + PlonkError(#[from] PlonkError), + DuskBytesError(#[from] dusk_bytes::Error), + MultiproofError(#[from] poly_multiproof::Error), + CellLengthExceeded, BadHeaderHash, BlockTooBig, InvalidChunkLength, + DimensionsMismatch, + ZeroDimension, + InvalidDimensionExtension, + DomainSizeInvalid, + InvalidDataLookup(#[from] DataLookupError), + Rng(#[from] ChaChaError), + /// The base grid width, before extension, does not fit cleanly into a domain for FFTs + BaseGridDomainSizeInvalid(usize), + /// The extended grid width does not fit cleanly into a domain for FFTs + ExtendedGridDomianSizeInvalid(usize), +} + +impl From for Error { + fn from(_: TryFromIntError) -> Self { + Self::ZeroDimension + } } -impl From for Error { - fn from(error: PlonkError) -> Self { - Self::PlonkError(error) +impl From for Error { + fn from(_: TryFromBlockDimensionsError) -> Self { + Self::BlockTooBig + } +} + +/// We cannot derive `PartialEq` becasue `PlonkError` does not support it in the current version. +/// and we only need to double check its discriminat for testing. +/// Only needed on tests by now. +#[cfg(test)] +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + std::mem::discriminant(self) == std::mem::discriminant(other) } } @@ -75,54 +113,10 @@ fn app_extrinsics_group_by_app_id(extrinsics: &[AppExtrinsic]) -> Vec<(AppId, Ve }) } -#[cfg(feature = "std")] -pub fn scalars_to_rows( - rows: &[u32], - dimensions: &matrix::Dimensions, - data: &[BlsScalar], -) -> Vec>> { - let extended_rows = BlockLengthRows(dimensions.extended_rows()); - let cols = BlockLengthColumns(dimensions.cols() as u32); - dimensions - .iter_extended_rows() - .map(|i| { - rows.contains(&i).then(|| { - row(data, i as usize, cols, extended_rows) - .iter() - .flat_map(BlsScalar::to_bytes) - .collect::>() - }) - }) - .collect::>>>() -} - -#[cfg(feature = "std")] -pub fn scalars_to_app_rows( - app_id: u32, - index: &index::AppDataIndex, - dimensions: &matrix::Dimensions, - data: &[BlsScalar], -) -> Vec>> { - let extended_rows = BlockLengthRows(dimensions.extended_rows()); - let cols = BlockLengthColumns(dimensions.cols() as u32); - let app_rows = app_specific_rows(index, dimensions, app_id); - dimensions - .iter_extended_rows() - .map(|i| { - app_rows.iter().find(|&&row| row == i).map(|_| { - row(data, i as usize, cols, extended_rows) - .iter() - .flat_map(BlsScalar::to_bytes) - .collect::>() - }) - }) - .collect::>>>() -} - pub fn flatten_and_pad_block( max_rows: BlockLengthRows, max_cols: BlockLengthColumns, - chunk_size: u32, + chunk_size: NonZeroU32, extrinsics: &[AppExtrinsic], rng_seed: Seed, ) -> Result<(XtsLayout, FlatData, BlockDimensions), Error> { @@ -130,19 +124,19 @@ pub fn flatten_and_pad_block( let mut extrinsics = extrinsics.to_vec(); extrinsics.sort_by(|a, b| a.app_id.cmp(&b.app_id)); - let extrinsics = app_extrinsics_group_by_app_id(&extrinsics) - .iter() - .map(|e| (e.0, e.1.encode())) - .collect::>(); - // Pad data before determining exact block size // Padding occurs both inside a single chunk and with additional chunk (if needed) - let (tx_layout, padded_chunks): (Vec<_>, Vec<_>) = extrinsics + let (tx_layout, padded_chunks): (Vec<_>, Vec<_>) = app_extrinsics_group_by_app_id(&extrinsics) .iter() - .map(|(app_id, data)| { - let chunks = pad_iec_9797_1(data.clone()); - ((*app_id, chunks.len() as u32), chunks) + .map(|e| { + let app_id = e.0; + let data = e.1.encode(); + let chunks = pad_iec_9797_1(data); + let chunks_len = u32::try_from(chunks.len()).map_err(|_| Error::BlockTooBig)?; + Ok(((app_id, chunks_len), chunks)) }) + .collect::, Error>>()? + .into_iter() .unzip(); let mut padded_block = padded_chunks @@ -160,15 +154,30 @@ pub fn flatten_and_pad_block( // Determine the block size after padding let block_dims = get_block_dimensions(padded_block_len, max_rows, max_cols, chunk_size)?; + let chunk_size = usize::try_from(NonZeroU32::get(block_dims.chunk_size)).expect(U32_USIZE_ERR); - ensure!(padded_block.len() <= block_dims.size(), Error::BlockTooBig); + let block_dims_size = block_dims.size(); + ensure!(padded_block.len() <= block_dims_size, Error::BlockTooBig); let mut rng = ChaChaRng::from_seed(rng_seed); - assert!((block_dims.size() - padded_block.len()) % block_dims.chunk_size as usize == 0); + // SAFETY: `padded_block.len() <= block_dims.size()` checked some lines above. + if cfg!(debug_assertions) { + let dims_sub_pad = block_dims_size + .checked_sub(padded_block.len()) + .expect("`padded_block.len() <= block_dims.size() .qed"); + let rem = dims_sub_pad + .checked_rem(chunk_size) + .expect("`chunk_size != 0 .qed"); + assert_eq!(rem, 0); + } - for _ in 0..((block_dims.size() - padded_block.len()) / block_dims.chunk_size as usize) { - let rnd_values: DataChunk = rng.gen(); + #[allow(clippy::integer_arithmetic)] + // SAFETY: `chunk_size` comes from `NonZeroU32::get(...)` so we can safetly use `/`. + let last = block_dims_size.saturating_sub(padded_block.len()) / chunk_size; + for _ in 0..last { + let mut rnd_values = DataChunk::default(); + rng.try_fill_bytes(&mut rnd_values)?; padded_block.append(&mut pad_with_zeroes(rnd_values.to_vec(), chunk_size)); } @@ -179,15 +188,16 @@ pub fn get_block_dimensions( block_size: u32, max_rows: BlockLengthRows, max_cols: BlockLengthColumns, - chunk_size: u32, + chunk_size: NonZeroU32, ) -> Result { - let max_block_dimensions = BlockDimensions::new(max_rows, max_cols, chunk_size); - ensure!( - block_size as usize <= max_block_dimensions.size(), - Error::BlockTooBig - ); + let max_block_dimensions = + BlockDimensions::new(max_rows, max_cols, chunk_size).ok_or(Error::BlockTooBig)?; + let max_block_dimensions_size = max_block_dimensions.size(); + + let block_size = usize::try_from(block_size)?; + ensure!(block_size <= max_block_dimensions_size, Error::BlockTooBig); - if block_size as usize == max_block_dimensions.size() || MAXIMUM_BLOCK_SIZE { + if block_size == max_block_dimensions_size || MAXIMUM_BLOCK_SIZE { return Ok(max_block_dimensions); } @@ -198,38 +208,36 @@ pub fn get_block_dimensions( nearest_power_2_size = MINIMUM_BLOCK_SIZE; } - let total_cells = (nearest_power_2_size as f32 / chunk_size as f32).ceil() as u32; + let total_cells = (nearest_power_2_size as f32 / chunk_size.get() as f32).ceil() as u32; // we must minimize number of rows, to minimize header size // (performance wise it doesn't matter) + let nz_max_cols = NonZeroU32::new(max_cols.0).ok_or(Error::ZeroDimension)?; let (cols, rows) = if total_cells > max_cols.0 { - (max_cols, BlockLengthRows(total_cells / max_cols.0)) + (max_cols, BlockLengthRows(total_cells / nz_max_cols)) } else { - (total_cells.into(), 1.into()) + (BlockLengthColumns(total_cells), BlockLengthRows(1)) }; - Ok(BlockDimensions { - cols, - rows, - chunk_size, - }) + BlockDimensions::new(rows, cols, chunk_size).ok_or(Error::BlockTooBig) } #[inline] -fn pad_with_zeroes(mut chunk: Vec, length: u32) -> Vec { - chunk.resize(length as usize, 0); +fn pad_with_zeroes(mut chunk: Vec, len: usize) -> Vec { + chunk.resize(len, 0); chunk } -fn pad_to_chunk(chunk: DataChunk, chunk_size: u32) -> Vec { +fn pad_to_chunk(chunk: DataChunk, chunk_size: NonZeroU32) -> Vec { const_assert_eq!(DATA_CHUNK_SIZE, size_of::()); + let chunk_size = usize::try_from(chunk_size.get()).expect(U32_USIZE_ERR); debug_assert!( - chunk_size as usize >= DATA_CHUNK_SIZE, + chunk_size >= DATA_CHUNK_SIZE, "`BlockLength.chunk_size` is valid by design .qed" ); let mut padded = chunk.to_vec(); - padded.resize(chunk_size as usize, 0); + padded.resize(chunk_size, 0); padded } @@ -247,20 +255,25 @@ fn pad_iec_9797_1(mut data: Vec) -> Vec { .expect("Const assertion ensures this transformation to `DataChunk`. qed") } -fn extend_column_with_zeros( - column: &[BlsScalar], - extended_rows: BlockLengthRows, -) -> Vec { - let mut result = column.to_vec(); - result.resize(extended_rows.as_usize(), BlsScalar::zero()); - result +fn extend_column_with_zeros(column: &[BlsScalar], height: usize) -> Vec { + let mut extended = Vec::with_capacity(height); + let copied = core::cmp::min(height, column.len()); + + extended.extend_from_slice(&column[..copied]); + extended.resize(height, BlsScalar::zero()); + + extended } pub fn to_bls_scalar(chunk: &[u8]) -> Result { // TODO: Better error type for BlsScalar case? let scalar_size_chunk = <[u8; SCALAR_SIZE]>::try_from(chunk).map_err(|_| Error::InvalidChunkLength)?; - BlsScalar::from_bytes(&scalar_size_chunk).map_err(|_| Error::CellLenghtExceeded) + BlsScalar::from_bytes(&scalar_size_chunk).map_err(|_| Error::CellLengthExceeded) +} + +fn make_dims(bd: BlockDimensions) -> Result { + Dimensions::new_from(bd.rows.0, bd.cols.0).ok_or(Error::ZeroDimension) } /// Build extended data matrix, by columns. @@ -269,49 +282,60 @@ pub fn to_bls_scalar(chunk: &[u8]) -> Result { /// This means that extension factor has to be multiple of 2, /// and that original data will be interleaved with erasure codes, /// instead of being in first k chunks of a column. -#[cfg(feature = "std")] +/// +/// `block` should be the raw data of a matrix, stored in row-major orientation. +#[cfg(feature = "parallel")] pub fn par_extend_data_matrix( block_dims: BlockDimensions, block: &[u8], metrics: &M, -) -> Result, Error> { +) -> Result, Error> { let start = Instant::now(); - let dimensions: matrix::Dimensions = block_dims.try_into().map_err(|_| Error::BlockTooBig)?; - let rows_num: usize = dimensions.rows().into(); - let extended_rows_num = BlockLengthRows(dimensions.extended_rows()); - let chunks = block.par_chunks_exact(block_dims.chunk_size as usize); - assert!(chunks.remainder().is_empty()); + let dims = make_dims(block_dims)?; + let (ext_rows, _): (usize, usize) = dims + .extend(ROW_EXTENSION, COL_EXTENSION) + .ok_or(Error::InvalidDimensionExtension)? + .into(); + let (rows, cols) = dims.into(); + + // simple length with mod check would work... + let chunk_size = + usize::try_from(block_dims.chunk_size.get()).map_err(|_| Error::BlockTooBig)?; + + let chunks = block.par_chunks_exact(chunk_size); + ensure!(chunks.remainder().is_empty(), Error::DimensionsMismatch); let scalars = chunks .into_par_iter() .map(to_bls_scalar) .collect::, Error>>()?; - let mut row_wise_scalars = Vec::with_capacity(dimensions.size() as usize); - dimensions - .iter_cells() - .for_each(|cell_i| row_wise_scalars.push(scalars[cell_i as usize])); - - let mut chunk_elements = row_wise_scalars - .par_chunks_exact(rows_num) - .flat_map(|column| extend_column_with_zeros(column, extended_rows_num)) - .collect::>(); + let extended_column_eval_domain = EvaluationDomain::new(ext_rows)?; + let column_eval_domain = EvaluationDomain::new(rows)?; // rows_num = column_length - // extend data matrix, column by column - let extended_column_eval_domain = EvaluationDomain::new(extended_rows_num.as_usize())?; - let column_eval_domain = EvaluationDomain::new(rows_num)?; // rows_num = column_length + // The data is currently row-major, so we need to put it into column-major + let col_wise_scalars = DMatrix::from_row_iterator(rows, cols, scalars.into_iter()); - chunk_elements - .par_chunks_exact_mut(extended_rows_num.as_usize()) - .for_each(|col| { + let ext_columns_wise = (0..cols) + .into_par_iter() + .flat_map(|col| { + let col_view = col_wise_scalars.column(col).data.into_slice(); + debug_assert_eq!(col_view.len(), rows); + let mut ext_col = extend_column_with_zeros(col_view, ext_rows); // (i)fft functions input parameter slice size has to be a power of 2, otherwise it panics - column_eval_domain.ifft_slice(&mut col[0..rows_num]); - extended_column_eval_domain.fft_slice(col); - }); + column_eval_domain.ifft_slice(&mut ext_col[0..rows]); + extended_column_eval_domain.fft_slice(ext_col.as_mut_slice()); + debug_assert_eq!(ext_col.len(), ext_rows); + ext_col + }) + .collect::>(); + debug_assert_eq!(Some(ext_columns_wise.len()), cols.checked_mul(ext_rows)); + + let ext_matrix = DMatrix::from_iterator(ext_rows, cols, ext_columns_wise.into_iter()); metrics.extended_block_time(start.elapsed()); - Ok(chunk_elements) + Ok(ext_matrix) } //TODO cache extended data matrix @@ -319,31 +343,26 @@ pub fn par_extend_data_matrix( pub fn build_proof( public_params: &kzg10::PublicParameters, block_dims: BlockDimensions, - ext_data_matrix: &[BlsScalar], + ext_data_matrix: &DMatrix, cells: &[Cell], metrics: &M, ) -> Result, Error> { - let cols_num = block_dims.cols.as_usize(); - let extended_rows_num = block_dims - .rows - .0 - .checked_mul(EXTENSION_FACTOR) - .ok_or(Error::BlockTooBig)?; + let dims = make_dims(block_dims)?; + let (ext_rows, ext_cols): (usize, usize) = dims + .extend(ROW_EXTENSION, COL_EXTENSION) + .ok_or(Error::InvalidDimensionExtension)? + .into(); + let (_, cols): (usize, usize) = dims.into(); const SPROOF_SIZE: usize = PROOF_SIZE + SCALAR_SIZE; - let (prover_key, _) = public_params.trim(cols_num).map_err(Error::from)?; + let (prover_key, _) = public_params.trim(cols).map_err(Error::from)?; // Generate all the x-axis points of the domain on which all the row polynomials reside - let row_eval_domain = EvaluationDomain::new(cols_num).map_err(Error::from)?; - let mut row_dom_x_pts = Vec::with_capacity(row_eval_domain.size()); - row_dom_x_pts.extend(row_eval_domain.elements()); - - let mut result_bytes: Vec = Vec::new(); - result_bytes.reserve_exact(SPROOF_SIZE * cells.len()); - unsafe { - result_bytes.set_len(SPROOF_SIZE * cells.len()); - } + let row_eval_domain = EvaluationDomain::new(cols)?; + let row_dom_x_pts = row_eval_domain.elements().collect::>(); + + let mut result_bytes: Vec = vec![0u8; SPROOF_SIZE.saturating_mul(cells.len())]; let prover_key = &prover_key; let row_dom_x_pts = &row_dom_x_pts; @@ -352,39 +371,50 @@ pub fn build_proof( let total_start = Instant::now(); // attempt to parallelly compute proof for all requested cells - cells - .into_par_iter() - .zip(result_bytes.par_chunks_exact_mut(SPROOF_SIZE)) - .for_each(|(cell, res)| { - let r_index = cell.row.as_usize(); - if (r_index >= extended_rows_num as usize) || (cell.col >= block_dims.cols) { - res.fill(0); // for bad cell identifier, fill whole proof with zero bytes ! - } else { - let c_index = cell.col.as_usize(); - - // construct polynomial per extended matrix row - let row = (0..cols_num) + let cell_iter = cells.iter().zip(result_bytes.chunks_exact_mut(SPROOF_SIZE)); + + for (cell, res) in cell_iter { + let r_index = usize::try_from(cell.row.0)?; + if r_index >= ext_rows || cell.col >= block_dims.cols { + res.fill(0); // for bad cell identifier, fill whole proof with zero bytes ! + } else { + let c_index = usize::try_from(cell.col.0)?; + let get_ext_data_matrix = + |j: usize| ext_data_matrix[r_index.saturating_add(j.saturating_mul(ext_rows))]; + + // construct polynomial per extended matrix row + #[cfg(feature = "parallel")] + let row = { + let mut row = + Vec::with_capacity(ext_cols.checked_add(1).ok_or(Error::BlockTooBig)?); + (0..ext_cols) .into_par_iter() - .map(|j| ext_data_matrix[r_index + j * extended_rows_num as usize]) - .collect::>(); - - // row has to be a power of 2, otherwise interpolate() function panics - let poly = Evaluations::from_vec_and_domain(row, row_eval_domain).interpolate(); - let witness = prover_key.compute_single_witness(&poly, &row_dom_x_pts[c_index]); - match prover_key.commit(&witness) { - Ok(commitment_to_witness) => { - let evaluated_point = - ext_data_matrix[r_index + c_index * extended_rows_num as usize]; - - res[0..PROOF_SIZE].copy_from_slice(&commitment_to_witness.to_bytes()); - res[PROOF_SIZE..].copy_from_slice(&evaluated_point.to_bytes()); - }, - Err(_) => { - res.fill(0); // for bad cell identifier, fill whole proof with zero bytes ! - }, - }; - } - }); + .map(get_ext_data_matrix) + .collect_into_vec(&mut row); + row + }; + #[cfg(not(feature = "parallel"))] + let row = (0..ext_cols) + .map(get_ext_data_matrix) + .collect::>(); + + // row has to be a power of 2, otherwise interpolate() function panics TODO: cache evaluations + let poly = Evaluations::from_vec_and_domain(row, row_eval_domain).interpolate(); + let witness = prover_key.compute_single_witness(&poly, &row_dom_x_pts[c_index]); + match prover_key.commit(&witness) { + Ok(commitment_to_witness) => { + let evaluated_point = + ext_data_matrix[r_index.saturating_add(c_index.saturating_mul(ext_rows))]; + + res[0..PROOF_SIZE].copy_from_slice(&commitment_to_witness.to_bytes()); + res[PROOF_SIZE..].copy_from_slice(&evaluated_point.to_bytes()); + }, + Err(_) => { + res.fill(0); // for bad cell identifier, fill whole proof with zero bytes ! + }, + }; + } + } metrics.proof_build_time(total_start.elapsed(), cells.len().saturated_into()); @@ -395,33 +425,34 @@ pub fn build_proof( pub fn par_build_commitments( rows: BlockLengthRows, cols: BlockLengthColumns, - chunk_size: u32, + chunk_size: NonZeroU32, extrinsics_by_key: &[AppExtrinsic], rng_seed: Seed, metrics: &M, -) -> Result<(XtsLayout, Vec, BlockDimensions, Vec), Error> { +) -> Result<(XtsLayout, Vec, BlockDimensions, DMatrix), Error> { let start = Instant::now(); // generate data matrix first let (tx_layout, block, block_dims) = flatten_and_pad_block(rows, cols, chunk_size, extrinsics_by_key, rng_seed)?; - metrics.block_dims_and_size(&block_dims, block.len().saturated_into()); + metrics.block_dims_and_size(block_dims, block.len().saturated_into()); + + let ext_matrix = par_extend_data_matrix(block_dims, &block, metrics)?; - let ext_data_matrix = par_extend_data_matrix(block_dims, &block, metrics)?; - let extended_rows_num = block_dims - .rows - .0 - .checked_mul(EXTENSION_FACTOR) + let block_dims_cols = usize::try_from(block_dims.cols.0)?; + let block_dims_rows = usize::try_from(block_dims.rows.0)?; + let extended_rows = block_dims_rows + .checked_mul(EXTENSION_FACTOR as usize) .ok_or(Error::BlockTooBig)?; metrics.preparation_block_time(start.elapsed()); - let public_params = testnet::public_params(block_dims.cols.as_usize()); + let public_params = testnet::public_params(block_dims_cols); if log::log_enabled!(target: LOG_TARGET, log::Level::Debug) { let raw_pp = public_params.to_raw_var_bytes(); - let hash_pp = hex::encode(sp_core::blake2_128(&raw_pp)); + let hash_pp = hex::encode(sp_core::hashing::blake2_128(&raw_pp)); let hex_pp = hex::encode(raw_pp); log::debug!( target: LOG_TARGET, @@ -431,86 +462,91 @@ pub fn par_build_commitments( ); } - let (prover_key, _) = public_params - .trim(block_dims.cols.as_usize()) - .map_err(Error::from)?; - let row_eval_domain = EvaluationDomain::new(block_dims.cols.as_usize()).map_err(Error::from)?; - - let mut result_bytes: Vec = Vec::new(); - let result_bytes_len = extended_rows_num - .checked_mul(PROVER_KEY_SIZE) - .ok_or(Error::BlockTooBig)? as usize; - result_bytes.reserve_exact(result_bytes_len); - unsafe { - result_bytes.set_len(result_bytes_len); - } + let (prover_key, _) = public_params.trim(block_dims_cols)?; + let row_eval_domain = EvaluationDomain::new(block_dims_cols)?; let start = Instant::now(); - - (0..extended_rows_num) + let mut commitments = + Vec::with_capacity(extended_rows.checked_add(1).ok_or(Error::BlockTooBig)?); + (0..extended_rows) .into_par_iter() - .map(|i| { - row( - &ext_data_matrix, - i as usize, - block_dims.cols, - BlockLengthRows(extended_rows_num), - ) + .map(|row_idx| { + let ext_row = get_row(&ext_matrix, row_idx); + commit(&prover_key, row_eval_domain, ext_row) }) - .zip(result_bytes.par_chunks_exact_mut(PROVER_KEY_SIZE as usize)) - .map(|(row, res)| commit(&prover_key, row_eval_domain, row, res)) - .collect::>()?; + .collect_into_vec(&mut commitments); + + let commitments = commitments.into_iter().collect::, _>>()?; + let commitments_bytes = commitments + .into_par_iter() + .flat_map(|c| c.to_bytes()) + .collect(); metrics.commitment_build_time(start.elapsed()); - Ok((tx_layout, result_bytes, block_dims, ext_data_matrix)) + Ok((tx_layout, commitments_bytes, block_dims, ext_matrix)) } #[cfg(feature = "std")] -fn row( - matrix: &[BlsScalar], - i: usize, - cols: BlockLengthColumns, - extended_rows: BlockLengthRows, -) -> Vec { - let mut row = Vec::with_capacity(cols.as_usize()); - (0..cols.as_usize() * extended_rows.as_usize()) - .step_by(extended_rows.as_usize()) - .for_each(|idx| row.push(matrix[i + idx])); - - row +fn get_row(m: &DMatrix, row_idx: usize) -> Vec { + m.row(row_idx).iter().cloned().collect() } #[cfg(feature = "std")] -// Generate a commitment and store it into result +// Generate a commitment fn commit( prover_key: &CommitKey, domain: EvaluationDomain, row: Vec, - result: &mut [u8], -) -> Result<(), Error> { +) -> Result { let poly = Evaluations::from_vec_and_domain(row, domain).interpolate(); - let commitment = prover_key.commit(&poly).map_err(Error::from)?; - result.copy_from_slice(&commitment.to_bytes()); - Ok(()) + prover_key.commit(&poly).map_err(Error::from) +} + +#[cfg(feature = "std")] +pub fn scalars_to_app_rows( + id: AppId, + lookup: &DataLookup, + dimensions: Dimensions, + matrix: &DMatrix, +) -> Vec>> { + let app_rows = kate_recovery::com::app_specific_rows(lookup, dimensions, id); + dimensions + .iter_extended_rows() + .map(|i| { + app_rows.iter().find(|&&row| row == i).map(|_| { + let row = get_row(matrix, i as usize); + row.iter() + .flat_map(BlsScalar::to_bytes) + .collect::>() + }) + }) + .collect() +} + +#[cfg(feature = "std")] +pub fn scalars_to_rows(rows: &[u32], data: &DMatrix) -> Vec> { + rows.iter() + .map(|i| { + let row = get_row(data, *i as usize); + row.iter() + .flat_map(BlsScalar::to_bytes) + .collect::>() + }) + .collect::>>() } #[cfg(test)] mod tests { - use std::{convert::TryInto, iter::repeat, str::from_utf8}; - - use da_primitives::asdr::AppExtrinsic; + use avail_core::DataLookup; use dusk_bytes::Serializable; use dusk_plonk::bls12_381::BlsScalar; use hex_literal::hex; use kate_recovery::{ - com::{ - app_specific_cells, decode_app_extrinsics, reconstruct_app_extrinsics, - reconstruct_extrinsics, unflatten_padded_data, ReconstructionError, - }, + com::*, commitments, config, + config::CHUNK_SIZE, data::{self, DataCell}, - index::{AppDataIndex, AppDataIndexError}, matrix::{Dimensions, Position}, proof, }; @@ -519,6 +555,9 @@ mod tests { prelude::*, }; use rand::{prelude::IteratorRandom, Rng, SeedableRng}; + use sp_arithmetic::Percent; + use static_assertions::const_assert; + use std::{convert::TryInto, iter::repeat}; use test_case::test_case; use super::*; @@ -529,89 +568,69 @@ mod tests { padded_len, }; - fn app_data_index_try_from_layout( - layout: Vec<(AppId, u32)>, - ) -> Result { - let mut index = Vec::new(); - // transactions are ordered by application id - // skip transactions with 0 application id - it's not a data txs - let mut size = 0u32; - let mut prev_app_id = AppId(0u32); - - for (app_id, data_len) in layout { - if app_id.0 != 0 && prev_app_id != app_id { - index.push((app_id.0, size)); - } - - size = size - .checked_add(data_len) - .ok_or(AppDataIndexError::SizeOverflow)?; - if prev_app_id > app_id { - return Err(AppDataIndexError::UnsortedLayout); - } - prev_app_id = app_id; - } - - Ok(AppDataIndex { size, index }) - } - - #[test_case(0, 256, 256 => BlockDimensions::new(1, 4, 32) ; "block size zero")] - #[test_case(11, 256, 256 => BlockDimensions::new(1, 4, 32) ; "below minimum block size")] - #[test_case(300, 256, 256 => BlockDimensions::new(1, 16, 32) ; "regular case")] - #[test_case(513, 256, 256 => BlockDimensions::new(1, 32, 32) ; "minimum overhead after 512")] - #[test_case(8192, 256, 256 => BlockDimensions::new(1, 256, 32) ; "maximum cols")] - #[test_case(8224, 256, 256 => BlockDimensions::new(2, 256, 32) ; "two rows")] - #[test_case(2097152, 256, 256 => BlockDimensions::new(256, 256, 32) ; "max block size")] + const TCHUNK: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(32) }; + #[test_case(0, 256, 256 => (1, 4, 32) ; "block size zero")] + #[test_case(11, 256, 256 => (1, 4, 32) ; "below minimum block size")] + #[test_case(300, 256, 256 => (1, 16, 32) ; "regular case")] + #[test_case(513, 256, 256 => (1, 32, 32) ; "minimum overhead after 512")] + #[test_case(8192, 256, 256 => (1, 256, 32) ; "maximum cols")] + #[test_case(8224, 256, 256 => (2, 256, 32) ; "two rows")] + #[test_case(2097152, 256, 256 => (256, 256, 32) ; "max block size")] #[test_case(2097155, 256, 256 => panics "BlockTooBig" ; "too much data")] - fn test_get_block_dimensions(size: u32, rows: R, cols: C) -> BlockDimensions - where - R: Into, - C: Into, - { - get_block_dimensions(size, rows.into(), cols.into(), 32).unwrap() + // newapi done + fn test_get_block_dimensions(size: u32, rows: u32, cols: u32) -> (u32, u32, u32) { + let dims = get_block_dimensions( + size, + BlockLengthRows(rows), + BlockLengthColumns(cols), + TCHUNK, + ) + .unwrap(); + + (dims.rows.0, dims.cols.0, dims.chunk_size.get()) } + // newapi done #[test] fn test_extend_data_matrix() { - let expected_result = vec![ - b"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e00", - b"bc1c6b8b4b02ca677b825ec9dace9aa706813f3ec47abdf9f03c680f4468555e", - b"7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a00", - b"c16115f73784be22106830c9bc6bbb469bf5026ee80325e403efe5ccc3f55016", - b"1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d00", - b"db3b8aaa6a21e9869aa17de8f9edb9c625a05e5de399dc18105c872e6387745e", - b"9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b900", - b"e080341657a3dd412f874fe8db8ada65ba14228d07234403230e05ece2147016", - b"3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c00", - b"fa5aa9c9894008a6b9c09c07190dd9e544bf7d7c02b9fb372f7ba64d82a6935e", - b"babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d800", - b"ff9f533576c2fc604ea66e07fba9f984d93341ac26426322422d240b02348f16", - b"5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b00", - b"197ac8e8a85f27c5d8dfbb26382cf80464de9c9b21d81a574e9ac56ca1c5b25e", - b"d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f700", - b"1ebf725495e11b806dc58d261ac918a4f85260cb45618241614c432a2153ae16", + let expected = [ + // Col 0 + hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e00"), + hex!("bc1c6b8b4b02ca677b825ec9dace9aa706813f3ec47abdf9f03c680f4468555e"), + hex!("7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a00"), + hex!("c16115f73784be22106830c9bc6bbb469bf5026ee80325e403efe5ccc3f55016"), + // Col 1 + hex!("1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d00"), + hex!("db3b8aaa6a21e9869aa17de8f9edb9c625a05e5de399dc18105c872e6387745e"), + hex!("9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b900"), + hex!("e080341657a3dd412f874fe8db8ada65ba14228d07234403230e05ece2147016"), + // Col 2 + hex!("3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c00"), + hex!("fa5aa9c9894008a6b9c09c07190dd9e544bf7d7c02b9fb372f7ba64d82a6935e"), + hex!("babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d800"), + hex!("ff9f533576c2fc604ea66e07fba9f984d93341ac26426322422d240b02348f16"), + // Col 3 + hex!("5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b00"), + hex!("197ac8e8a85f27c5d8dfbb26382cf80464de9c9b21d81a574e9ac56ca1c5b25e"), + hex!("d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f700"), + hex!("1ebf725495e11b806dc58d261ac918a4f85260cb45618241614c432a2153ae16"), ] - .into_iter() - .map(|e| { - e.chunks_exact(2) - .map(|h| u8::from_str_radix(from_utf8(h).unwrap(), 16).unwrap()) - .collect::>() - }) - .map(|e| { - BlsScalar::from_bytes(e.as_slice().try_into().expect("wrong number of elems")).unwrap() - }) - .collect::>(); - - let block_dims = BlockDimensions::new(BlockLengthRows(2), BlockLengthColumns(4), 32); + .iter() + .map(BlsScalar::from_bytes) + .collect::, _>>() + .expect("Invalid Expected result"); + let expected = DMatrix::from_iterator(4, 4, expected.into_iter()); + + let block_dims = + BlockDimensions::new(BlockLengthRows(2), BlockLengthColumns(4), TCHUNK).unwrap(); + let chunk_size = usize::try_from(block_dims.chunk_size.get()).unwrap(); let block = (0..=247) .collect::>() .chunks_exact(DATA_CHUNK_SIZE) - .flat_map(|chunk| pad_with_zeroes(chunk.to_vec(), block_dims.chunk_size)) + .flat_map(|chunk| pad_with_zeroes(chunk.to_vec(), chunk_size)) .collect::>(); - let res = par_extend_data_matrix(block_dims, &block, &IgnoreMetrics {}); - eprintln!("result={:?}", res); - eprintln!("expect={:?}", expected_result); - assert_eq!(res.unwrap(), expected_result); + let ext_matrix = par_extend_data_matrix(block_dims, &block, &IgnoreMetrics {}).unwrap(); + assert_eq!(ext_matrix, expected); } #[test_case( 1..=29 => "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d8000" ; "chunk more than 3 values shorter")] @@ -620,6 +639,7 @@ mod tests { #[test_case( 1..=32 => "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20800000000000000000000000000000000000000000000000000000000000" ; "Chunk same size")] #[test_case( 1..=33 => "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20218000000000000000000000000000000000000000000000000000000000" ; "Chunk 1 value longer")] #[test_case( 1..=34 => "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212280000000000000000000000000000000000000000000000000000000" ; "Chunk 2 value longer")] + // newapi ignore fn test_padding>(block: I) -> String { let padded = pad_iec_9797_1(block.collect()) .iter() @@ -629,99 +649,94 @@ mod tests { hex::encode(padded) } + // newapi done #[test] fn test_flatten_block() { - let chunk_size = 32; let extrinsics: Vec = vec![ - AppExtrinsic { - app_id: 0.into(), - data: (1..=29).collect(), - }, - AppExtrinsic { - app_id: 1.into(), - data: (1..=30).collect(), - }, - AppExtrinsic { - app_id: 2.into(), - data: (1..=31).collect(), - }, - AppExtrinsic { - app_id: 3.into(), - data: (1..=60).collect(), - }, + AppExtrinsic::new(AppId(0), (1..=29).collect()), + AppExtrinsic::new(AppId(1), (1..=30).collect()), + AppExtrinsic::new(AppId(2), (1..=31).collect()), + AppExtrinsic::new(AppId(3), (1..=60).collect()), ]; - let expected_dims = BlockDimensions::new(1, 16, chunk_size); + let expected_dims = + BlockDimensions::new(BlockLengthRows(1), BlockLengthColumns(16), TCHUNK).unwrap(); let (layout, data, dims) = flatten_and_pad_block( - 128.into(), - 256.into(), - chunk_size, + BlockLengthRows(128), + BlockLengthColumns(256), + TCHUNK, extrinsics.as_slice(), Seed::default(), ) .unwrap(); - let expected_layout = vec![(0.into(), 2), (1.into(), 2), (2.into(), 2), (3.into(), 3)]; + let expected_layout = vec![(AppId(0), 2), (AppId(1), 2), (AppId(2), 2), (AppId(3), 3)]; assert_eq!(layout, expected_layout, "The layouts don't match"); - let expected_data = hex!("04740102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d00800000000000000000000000000000000000000000000000000000000000000004780102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e80000000000000000000000000000000000000000000000000000000000000047c0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e1f80000000000000000000000000000000000000000000000000000000000004f00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c00800000000000000000000000000000000000000000000000000000000000000076a04053bda0a88bda5177b86a15c3b29f559873cb481232299cd5743151ac004b2d63ae198e7bb0a9011f28e473c95f4013d7d53ec5fbc3b42df8ed101f6d00e831e52bfb76e51cca8b4e9016838657edfae09cb9a71eb219025c4c87a67c004aaa86f20ac0aa792bc121ee42e2c326127061eda15599cb5db3db870bea5a00ecf353161c3cb528b0c5d98050c4570bfc942d8b19ed7b0cbba5725e03e5f000b7e30db36b6df82ac151f668f5f80a5e2a9cac7c64991dd6a6ce21c060175800edb9260d2a86c836efc05f17e5c59525e404c6a93d051651fe2e4eefae281300"); + let expected_data = hex!("04740102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d00800000000000000000000000000000000000000000000000000000000000000004780102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e80000000000000000000000000000000000000000000000000000000000000047c0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e1f80000000000000000000000000000000000000000000000000000000000004f00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c00800000000000000000000000000000000000000000000000000000000000000076b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770d00da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee65009f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7a0029b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d002d09a0e663266ce1ae7ed1081968a0758e718e997bd362c6b0c34634a9a0b300012737681f7b5d0f281e3afde458bc1e73d2d313c9cf94c05ff3716240a248001320a058d7b3566bd520daaa3ed2bf0ac5b8b120fb852773c3639734b45c9100"); assert_eq!(dims, expected_dims, "Dimensions don't match the expected"); assert_eq!(data, expected_data, "Data doesn't match the expected data"); - let index = app_data_index_try_from_layout(layout).unwrap(); - let res = unflatten_padded_data(index.data_ranges(), data).unwrap(); + let lookup = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + + const_assert!((CHUNK_SIZE as u64) <= (u32::MAX as u64)); + let data_lookup = lookup.projected_ranges(CHUNK_SIZE as u32).unwrap(); + let res = unflatten_padded_data(data_lookup, data).unwrap(); assert_eq!( res.len(), extrinsics.len(), "Number of extrinsics is not as expected." ); - for (res, exp) in res.iter().zip(extrinsics.iter()) { - assert_eq!(res.0, *exp.app_id); - assert_eq!(res.1[0], exp.data); + for ((id, data), exp) in res.iter().zip(extrinsics.iter()) { + assert_eq!(id.0, *exp.app_id); + assert_eq!(data[0], exp.data); } } fn sample_cells_from_matrix( - matrix: &[BlsScalar], - dimensions: &BlockDimensions, + matrix: &DMatrix, columns: Option<&[u16]>, ) -> Vec { - fn random_indexes(length: usize, seed: Seed) -> Vec { + fn random_indexes(length: usize, seed: Seed) -> Vec { // choose random len/2 (unique) indexes let mut idx = (0..length).collect::>(); - let mut chosen_idx = Vec::::new(); + let mut chosen_idx = Vec::::new(); let mut rng = ChaChaRng::from_seed(seed); for _ in 0..length / 2 { let i = rng.gen_range(0..idx.len()); let v = idx.remove(i); - chosen_idx.push(v as u16); + chosen_idx.push(v); } chosen_idx } - const RNG_SEED: Seed = [42u8; 32]; - matrix - .chunks_exact(dimensions.rows.as_usize() * 2) - .enumerate() - .map(|(col, e)| (col as u16, e)) - .flat_map(|(col, e)| { - random_indexes(e.len(), RNG_SEED) - .into_iter() - .map(|row| DataCell { - position: Position { - row: row as u32, - col, - }, - data: e[row as usize].to_bytes(), - }) - .filter(|cell| { - columns.is_none() || columns.unwrap_or(&[]).contains(&cell.position.col) + + let (rows, cols) = matrix.shape(); + let cols = u16::try_from(cols).unwrap(); + let indexes = random_indexes(rows, RNG_SEED); + + (0u16..cols) + .filter(|col_idx| match &columns { + None => true, + Some(allowed) => allowed.contains(&col_idx), + }) + .flat_map(|col_idx| { + let col_view = matrix.column(col_idx.into()).data.into_slice(); + + indexes + .iter() + .map(|row_idx| { + let row_pos = u32::try_from(*row_idx).unwrap(); + let position = Position::new(row_pos, col_idx); + debug_assert!(*row_idx < col_view.len()); + let data = col_view[*row_idx].to_bytes(); + DataCell::new(position, data) }) .collect::>() }) - .collect::>() + .collect() } fn app_extrinsic_strategy() -> impl Strategy { @@ -730,7 +745,7 @@ mod tests { any_with::>(size_range(1..2048).lift()), ) .prop_map(|(app_id, data)| AppExtrinsic { - app_id: app_id.into(), + app_id: AppId(app_id), data, }) } @@ -746,14 +761,15 @@ mod tests { fn random_cells( max_cols: BlockLengthColumns, max_rows: BlockLengthRows, - percents: usize, + percents: Percent, ) -> Vec { - assert!(percents > 0 && percents <= 100); let max_cols = max_cols.into(); let max_rows = max_rows.into(); let rng = &mut ChaChaRng::from_seed([0u8; 32]); - let amount = ((max_cols * max_rows) as f32 * (percents as f32 / 100.0)).ceil() as usize; + let amount: usize = percents + .mul_ceil::(max_cols * max_rows) + .saturated_into(); (0..max_cols) .flat_map(move |col| { @@ -764,25 +780,27 @@ mod tests { } proptest! { - #![proptest_config(ProptestConfig::with_cases(20))] + #![proptest_config(ProptestConfig::with_cases(10))] #[test] + // newapi done fn test_build_and_reconstruct(ref xts in app_extrinsics_strategy()) { let metrics = IgnoreMetrics {}; let (layout, commitments, dims, matrix) = par_build_commitments( - BlockLengthRows(64), BlockLengthColumns(16), 32, xts, Seed::default(), &metrics).unwrap(); + BlockLengthRows(64), BlockLengthColumns(16), TCHUNK, xts, Seed::default(), &metrics).unwrap(); - let columns = sample_cells_from_matrix(&matrix, &dims, None); + let columns = sample_cells_from_matrix(&matrix, None); let extended_dims = dims.try_into().unwrap(); - let index = app_data_index_try_from_layout(layout).unwrap(); - let reconstructed = reconstruct_extrinsics(&index, &extended_dims, columns).unwrap(); - for (result, xt) in reconstructed.iter().zip(xts) { - prop_assert_eq!(result.0, *xt.app_id); - prop_assert_eq!(result.1[0].as_slice(), &xt.data); + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let reconstructed = reconstruct_extrinsics(&index, extended_dims, columns).unwrap(); + for ((app_id, data), xt) in reconstructed.iter().zip(xts) { + prop_assert_eq!(app_id.0, *xt.app_id); + prop_assert_eq!(data[0].as_slice(), &xt.data); } - let public_params = testnet::public_params(dims.cols.as_usize()); - for cell in random_cells(dims.cols, dims.rows, 1) { - let row = cell.row.as_usize(); + let dims_cols = usize::try_from(dims.cols.0).unwrap(); + let public_params = testnet::public_params(dims_cols); + for cell in random_cells(dims.cols, dims.rows, Percent::one() ) { + let row = usize::try_from(cell.row.0).unwrap(); let proof = build_proof(&public_params, dims, &matrix, &[cell], &metrics).unwrap(); prop_assert!(proof.len() == 80); @@ -793,7 +811,7 @@ mod tests { let extended_dims = dims.try_into().unwrap(); let commitment = commitments::from_slice(&commitments).unwrap()[row]; - let verification = proof::verify(&public_params, &extended_dims, &commitment, &cell); + let verification = proof::verify(&public_params, extended_dims, &commitment, &cell); prop_assert!(verification.is_ok()); prop_assert!(verification.unwrap()); } @@ -803,16 +821,18 @@ mod tests { proptest! { #![proptest_config(ProptestConfig::with_cases(20))] #[test] + // newapi done fn test_commitments_verify(ref xts in app_extrinsics_strategy()) { - let (layout, commitments, dims, matrix) = par_build_commitments(BlockLengthRows(64), BlockLengthColumns(16), 32, xts, Seed::default(), &IgnoreMetrics{}).unwrap(); + let (layout, commitments, dims, matrix) = par_build_commitments(BlockLengthRows(64), BlockLengthColumns(16), TCHUNK, xts, Seed::default(), &IgnoreMetrics{}).unwrap(); - let index = app_data_index_try_from_layout(layout).unwrap(); - let public_params = testnet::public_params(dims.cols.as_usize()); + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let dims_cols = usize::try_from(dims.cols.0).unwrap(); + let public_params = testnet::public_params(dims_cols); let extended_dims = dims.try_into().unwrap(); let commitments = commitments::from_slice(&commitments).unwrap(); for xt in xts { - let rows = &scalars_to_app_rows(xt.app_id.0, &index, &extended_dims, &matrix); - let (_, missing) = commitments::verify_equality(&public_params, &commitments, rows, &index, &extended_dims, xt.app_id.0).unwrap(); + let rows = scalars_to_app_rows(xt.app_id, &index, extended_dims, &matrix); + let (_, missing) = commitments::verify_equality(&public_params, &commitments, rows.as_slice(), &index, extended_dims, xt.app_id).unwrap(); prop_assert!(missing.is_empty()); } } @@ -821,18 +841,20 @@ mod tests { proptest! { #![proptest_config(ProptestConfig::with_cases(20))] #[test] + // newapi done fn verify_commitmnets_missing_row(ref xts in app_extrinsics_strategy()) { - let (layout, commitments, dims, matrix) = par_build_commitments(BlockLengthRows(64), BlockLengthColumns(16), 32, xts, Seed::default(), &IgnoreMetrics{}).unwrap(); + let (layout, commitments, dims, matrix) = par_build_commitments(BlockLengthRows(64), BlockLengthColumns(16), TCHUNK, xts, Seed::default(), &IgnoreMetrics{}).unwrap(); - let index = app_data_index_try_from_layout(layout).unwrap(); - let public_params = testnet::public_params(dims.cols.as_usize()); + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let dims_cols = usize::try_from(dims.cols.0).unwrap(); + let public_params = testnet::public_params(dims_cols); let extended_dims = dims.try_into().unwrap(); let commitments = commitments::from_slice(&commitments).unwrap(); for xt in xts { - let mut rows = scalars_to_app_rows(xt.app_id.0, &index, &extended_dims, &matrix); + let mut rows = scalars_to_app_rows(xt.app_id, &index, extended_dims, &matrix); let app_row_index = rows.iter().position(Option::is_some).unwrap(); rows.remove(app_row_index); - let (_, missing) = commitments::verify_equality(&public_params, &commitments, &rows,&index,&extended_dims,xt.app_id.0).unwrap(); + let (_, missing) = commitments::verify_equality(&public_params, &commitments, &rows,&index, extended_dims,xt.app_id).unwrap(); prop_assert!(!missing.is_empty()); } } @@ -840,20 +862,17 @@ mod tests { #[test] // Test build_commitments() function with a predefined input + // newapi done fn test_build_commitments_simple_commitment_check() { let block_rows = BlockLengthRows(256); let block_cols = BlockLengthColumns(256); - let chunk_size = 32; let original_data = br#"test"#; - let hash: Seed = [ - 76, 41, 174, 145, 187, 12, 97, 32, 75, 111, 149, 209, 243, 195, 165, 10, 166, 172, 47, - 41, 218, 24, 212, 66, 62, 5, 187, 191, 129, 5, 105, 3, - ]; + let hash: Seed = hex!("4c29ae91bb0c61204b6f95d1f3c3a50aa6ac2f29da18d4423e05bbbf81056903"); let (_, commitments, dimensions, _) = par_build_commitments( block_rows, block_cols, - chunk_size, + TCHUNK, &[AppExtrinsic::from(original_data.to_vec())], hash, &IgnoreMetrics {}, @@ -862,18 +881,15 @@ mod tests { assert_eq!( dimensions, - BlockDimensions { - rows: 1.into(), - cols: 4.into(), - chunk_size: 32 - } + BlockDimensions::new(BlockLengthRows(1), BlockLengthColumns(4), TCHUNK).unwrap(), ); - let expected_commitments = hex!("960F08F97D3A8BD21C3F5682366130132E18E375A587A1E5900937D7AA5F33C4E20A1C0ACAE664DCE1FD99EDC2693B8D960F08F97D3A8BD21C3F5682366130132E18E375A587A1E5900937D7AA5F33C4E20A1C0ACAE664DCE1FD99EDC2693B8D"); + let expected_commitments = hex!("9046c691ce4c7ba93c9860746d6ff3dfb5560e119f1eac26aa9a10b6fe29d5c8e2b90f23e2ef3a7a950965b08035470d9046c691ce4c7ba93c9860746d6ff3dfb5560e119f1eac26aa9a10b6fe29d5c8e2b90f23e2ef3a7a950965b08035470d"); assert_eq!(commitments, expected_commitments); } #[test] - fn test_reconstruct_app_extrinsics_with_app_id() { + // newapi wip + fn test_reconstruct_app_extrinsics_with_app_id() -> Result<(), Error> { let app_id_1_data = br#""This is mocked test data. It will be formatted as a matrix of BLS scalar cells and then individual columns get erasure coded to ensure redundancy."#; @@ -881,49 +897,38 @@ get erasure coded to ensure redundancy."#; let hash = Seed::default(); let xts = vec![ - AppExtrinsic { - app_id: 0.into(), - data: vec![0], - }, - AppExtrinsic { - app_id: 1.into(), - data: app_id_1_data.to_vec(), - }, - AppExtrinsic { - app_id: 2.into(), - data: app_id_2_data.to_vec(), - }, + AppExtrinsic::new(AppId(0), vec![0]), + AppExtrinsic::new(AppId(1), app_id_1_data.to_vec()), + AppExtrinsic::new(AppId(2), app_id_2_data.to_vec()), ]; - let chunk_size = 32; - let (layout, data, dims) = flatten_and_pad_block( BlockLengthRows(32), BlockLengthColumns(4), - chunk_size, + TCHUNK, &xts, hash, - ) - .unwrap(); - let coded: Vec = - par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {}).unwrap(); + )?; + let matrix = par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {})?; - let cols_1 = sample_cells_from_matrix(&coded, &dims, Some(&[0, 1, 2, 3])); + let cols_1 = sample_cells_from_matrix(&matrix, Some(&[0, 1, 2, 3])); - let extended_dims = dims.try_into().unwrap(); + let extended_dims = dims.try_into()?; - let index = app_data_index_try_from_layout(layout).unwrap(); - let res_1 = reconstruct_app_extrinsics(&index, &extended_dims, cols_1, 1).unwrap(); + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let res_1 = reconstruct_app_extrinsics(&index, extended_dims, cols_1, AppId(1)).unwrap(); assert_eq!(res_1[0], app_id_1_data); - let cols_2 = sample_cells_from_matrix(&coded, &dims, Some(&[0, 2, 3])); + let cols_2 = sample_cells_from_matrix(&matrix, Some(&[0, 2, 3])); - let res_2 = reconstruct_app_extrinsics(&index, &extended_dims, cols_2, 2).unwrap(); + let res_2 = reconstruct_app_extrinsics(&index, extended_dims, cols_2, AppId(2)).unwrap(); assert_eq!(res_2[0], app_id_2_data); + Ok(()) } #[test] - fn test_decode_app_extrinsics() { + // newapi done + fn test_decode_app_extrinsics() -> Result<(), Error> { let app_id_1_data = br#""This is mocked test data. It will be formatted as a matrix of BLS scalar cells and then individual columns get erasure coded to ensure redundancy."#; @@ -934,150 +939,123 @@ get erasure coded to ensure redundancy."#; let hash = Seed::default(); let xts = (0..=2) .zip(data) - .map(|(app_id, data)| AppExtrinsic { - app_id: app_id.into(), - data, - }) + .map(|(app_id, data)| AppExtrinsic::new(AppId(app_id), data)) .collect::>(); - let chunk_size = 32; - let (layout, data, dims) = flatten_and_pad_block( BlockLengthRows(32), BlockLengthColumns(4), - chunk_size, + TCHUNK, &xts, hash, - ) - .unwrap(); - let coded = par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {}).unwrap(); - - let dimensions: Dimensions = dims.try_into().unwrap(); - let extended_matrix = coded - .chunks(dimensions.extended_rows() as usize) - .collect::>(); + )?; + let matrix = par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {})?; + let dimensions: Dimensions = dims.try_into()?; - let index = app_data_index_try_from_layout(layout).unwrap(); + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); for xt in xts { - let positions = app_specific_cells(&index, &dimensions, xt.app_id.0).unwrap(); + let positions = app_specific_cells(&index, dimensions, xt.app_id).unwrap(); let cells = positions - .iter() - .map(|position| DataCell { - position: position.clone(), - data: extended_matrix[position.col as usize][position.row as usize].to_bytes(), + .into_iter() + .map(|position| { + let col: usize = position.col.into(); + let row = usize::try_from(position.row).unwrap(); + let data = matrix.get((row, col)).map(BlsScalar::to_bytes).unwrap(); + DataCell::new(position, data) }) .collect::>(); - let data = &decode_app_extrinsics(&index, &dimensions, cells, xt.app_id.0).unwrap()[0]; + let data = &decode_app_extrinsics(&index, dimensions, cells, xt.app_id).unwrap()[0]; assert_eq!(data, &xt.data); } assert!(matches!( - decode_app_extrinsics(&index, &dimensions, vec![], 0), + decode_app_extrinsics(&index, dimensions, vec![], AppId(0)), Err(ReconstructionError::MissingCell { .. }) )); + Ok(()) } #[test] - fn test_extend_mock_data() { + // newapi done + fn test_extend_mock_data() -> Result<(), Error> { let orig_data = br#"This is mocked test data. It will be formatted as a matrix of BLS scalar cells and then individual columns get erasure coded to ensure redundancy. Let's see how this gets encoded and then reconstructed by sampling only some data."#; // The hash is used for seed for padding the block to next power of two value let hash = Seed::default(); - let chunk_size = 32; let (layout, data, dims) = flatten_and_pad_block( BlockLengthRows(128), BlockLengthColumns(2), - chunk_size, + TCHUNK, &[AppExtrinsic::from(orig_data.to_vec())], hash, - ) - .unwrap(); + )?; - let coded: Vec = - par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {}).unwrap(); + let matrix = par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {})?; - let cols = sample_cells_from_matrix(&coded, &dims, None); + let cols = sample_cells_from_matrix(&matrix, None); - let extended_dims = dims.try_into().unwrap(); - let index = app_data_index_try_from_layout(layout).unwrap(); - let res = reconstruct_extrinsics(&index, &extended_dims, cols).unwrap(); + let extended_dims = dims.try_into()?; + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let res = reconstruct_extrinsics(&index, extended_dims, cols).unwrap(); let s = String::from_utf8_lossy(res[0].1[0].as_slice()); assert_eq!(res[0].1[0], orig_data); - eprintln!("Decoded: {}", s); + Ok(()) } #[test] - fn test_multiple_extrinsics_for_same_app_id() { + // newapi done + fn test_multiple_extrinsics_for_same_app_id() -> Result<(), Error> { let xt1 = vec![5, 5]; let xt2 = vec![6, 6]; let xts = [ - AppExtrinsic { - app_id: 1.into(), - data: xt1.clone(), - }, - AppExtrinsic { - app_id: 1.into(), - data: xt2.clone(), - }, + AppExtrinsic::new(AppId(1), xt1.clone()), + AppExtrinsic::new(AppId(1), xt2.clone()), ]; // The hash is used for seed for padding the block to next power of two value let hash = Seed::default(); - let chunk_size = 32; let (layout, data, dims) = flatten_and_pad_block( BlockLengthRows(128), BlockLengthColumns(2), - chunk_size, + TCHUNK, &xts, hash, - ) - .unwrap(); + )?; - let coded: Vec = - par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {}).unwrap(); + let matrix = par_extend_data_matrix(dims, &data[..], &IgnoreMetrics {})?; - let cols = sample_cells_from_matrix(&coded, &dims, None); + let cols = sample_cells_from_matrix(&matrix, None); let extended_dims = dims.try_into().unwrap(); - let index = app_data_index_try_from_layout(layout).unwrap(); - let res = reconstruct_extrinsics(&index, &extended_dims, cols).unwrap(); + let index = DataLookup::from_id_and_len_iter(layout.into_iter()).unwrap(); + let res = reconstruct_extrinsics(&index, extended_dims, cols).unwrap(); assert_eq!(res[0].1[0], xt1); assert_eq!(res[0].1[1], xt2); + Ok(()) } #[test] + // newapi ignore fn test_extrinsics_grouping() { let xt1 = vec![5, 5]; let xt2 = vec![6, 6]; let xt3 = vec![7]; let xt4 = vec![]; let xts = [ - AppExtrinsic { - app_id: 1.into(), - data: xt1.clone(), - }, - AppExtrinsic { - app_id: 1.into(), - data: xt2.clone(), - }, - AppExtrinsic { - app_id: 2.into(), - data: xt3.clone(), - }, - AppExtrinsic { - app_id: 3.into(), - data: xt4.clone(), - }, + AppExtrinsic::new(AppId(1), xt1.clone()), + AppExtrinsic::new(AppId(1), xt2.clone()), + AppExtrinsic::new(AppId(2), xt3.clone()), + AppExtrinsic::new(AppId(3), xt4.clone()), ]; let expected = vec![ - (1.into(), vec![xt1, xt2]), - (2.into(), vec![xt3]), - (3.into(), vec![xt4]), + (AppId(1), vec![xt1, xt2]), + (AppId(2), vec![xt3]), + (AppId(3), vec![xt4]), ]; let rez = app_extrinsics_group_by_app_id(&xts); println!("{:?}", rez); @@ -1092,6 +1070,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat } fn padded_len_group(lens: &[u32], chunk_size: u32) -> u32 { + let chunk_size = NonZeroU32::new(chunk_size).unwrap(); lens.iter().map(|len| padded_len(*len, chunk_size)).sum() } @@ -1101,6 +1080,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat #[test_case( build_extrinsics(&[]), 32 => padded_len_group(&[], 32) ; "Empty chunk list")] #[test_case( build_extrinsics(&[4096]), 32 => padded_len_group(&[4096], 32) ; "4K chunk")] fn test_padding_len(extrinsics: Vec>, chunk_size: u32) -> u32 { + let chunk_size = NonZeroU32::new(chunk_size).expect("Invalid chunk size .qed"); extrinsics .into_iter() .flat_map(pad_iec_9797_1) @@ -1110,6 +1090,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat } #[test] + // newapi ignore fn par_build_commitments_column_wise_constant_row() { // This test will fail once we switch to row-wise orientation. // We should move `should_panic` to next test, until constant line issue is fixed. @@ -1125,7 +1106,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat par_build_commitments( BlockLengthRows(4), BlockLengthColumns(4), - 32, + TCHUNK, &xts, hash, &IgnoreMetrics {}, @@ -1134,6 +1115,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat } #[test] + // newapi done fn par_build_commitments_row_wise_constant_row() { // Due to scale encoding, first line is not constant. // We will use second line to ensure constant row. @@ -1145,7 +1127,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat par_build_commitments( BlockLengthRows(4), BlockLengthColumns(4), - 32, + TCHUNK, &xts, hash, &IgnoreMetrics {}, @@ -1155,6 +1137,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat #[test_case( ([1,1,1,1]).to_vec(); "All values are non-zero but same")] #[test_case( ([0,0,0,0]).to_vec(); "All values are zero")] #[test_case( ([0,5,2,1]).to_vec(); "All values are different")] + // newapi done fn test_zero_deg_poly_commit(row_values: Vec) { // There are two main cases that generate a zero degree polynomial. One is for data that is non-zero, but the same. // The other is for all-zero data. They differ, as the former yields a polynomial with one coefficient, and latter generates zero coefficients. @@ -1173,13 +1156,16 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat }) .collect::>(); - assert_eq!(row.len(), len as usize); - let mut result_bytes: Vec = vec![0u8; config::COMMITMENT_SIZE]; - commit(&prover_key, row_eval_domain, row.clone(), &mut result_bytes).unwrap(); - println!("Commitment: {result_bytes:?}"); + assert_eq!(row.len(), len); + println!("Row: {:?}", row); + let commitment = commit(&prover_key, row_eval_domain, row.clone()) + .map(|com| <[u8; config::COMMITMENT_SIZE]>::try_from(com.to_bytes()).unwrap()) + .unwrap(); + println!("Commitment: {commitment:?}"); // We artificially extend the matrix by doubling values, this is not proper erasure coding. - let ext_m = row.into_iter().flat_map(|e| vec![e, e]).collect::>(); + let ext_m = + DMatrix::from_row_iterator(1, row.len() * 2, row.into_iter().flat_map(|e| vec![e, e])); let rows: u16 = len.try_into().expect("rows length should be valid `u16`"); let metrics = IgnoreMetrics {}; @@ -1192,11 +1178,7 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat }; let proof = build_proof( &public_params, - BlockDimensions { - rows: BlockLengthRows(1), - cols: BlockLengthColumns(4), - chunk_size: 32, - }, + BlockDimensions::new(BlockLengthRows(1), BlockLengthColumns(4), TCHUNK).unwrap(), &ext_m, &[cell], &metrics, @@ -1204,22 +1186,22 @@ Let's see how this gets encoded and then reconstructed by sampling only some dat .unwrap(); println!("Proof: {proof:?}"); - assert!(proof.len() == 80); + assert_eq!(proof.len(), 80); - let commitment = result_bytes.clone().try_into().unwrap(); let dims = Dimensions::new(1, 4).unwrap(); let cell = data::Cell { position: Position { row: 0, col }, content: proof.try_into().unwrap(), }; - let verification = proof::verify(&public_params, &dims, &commitment, &cell); + let verification = proof::verify(&public_params, dims, &commitment, &cell); assert!(verification.is_ok()); assert!(verification.unwrap()) } } - #[test_case( r#"{ "row": 42, "col": 99 }"# => Cell::new(42.into(),99.into()) ; "Simple" )] - #[test_case( r#"{ "row": 4294967295, "col": 99 }"# => Cell::new(4_294_967_295.into(),99.into()) ; "Max row" )] + #[test_case( r#"{ "row": 42, "col": 99 }"# => Cell::new(BlockLengthRows(42), BlockLengthColumns(99)) ; "Simple" )] + #[test_case( r#"{ "row": 4294967295, "col": 99 }"# => Cell::new(BlockLengthRows(4_294_967_295),BlockLengthColumns(99)) ; "Max row" )] + // newapi ignore fn serde_block_length_types_untagged(data: &str) -> Cell { serde_json::from_str(data).unwrap() } diff --git a/kate/src/gridgen/mod.rs b/kate/src/gridgen/mod.rs new file mode 100644 index 00000000..70dc3fbf --- /dev/null +++ b/kate/src/gridgen/mod.rs @@ -0,0 +1,562 @@ +use crate::pmp::{ + ark_poly::{EvaluationDomain, GeneralEvaluationDomain}, + m1_blst::{Bls12_381, M1NoPrecomp}, + merlin::Transcript, + traits::Committer, +}; +use avail_core::{ensure, AppExtrinsic, AppId, DataLookup}; +use codec::Encode; +use core::{ + cmp::{max, min}, + iter, + num::NonZeroU16, +}; +use kate_recovery::{config::PADDING_TAIL_VALUE, matrix::Dimensions}; +use nalgebra::base::DMatrix; +use poly_multiproof::{ + m1_blst::Proof, + traits::{KZGProof, PolyMultiProofNoPrecomp}, +}; +use rand_chacha::{ + rand_core::{RngCore, SeedableRng}, + ChaChaRng, +}; +use static_assertions::const_assert; +use std::collections::BTreeMap; +use thiserror_no_std::Error; + +use crate::{ + com::{Cell, Error}, + config::DATA_CHUNK_SIZE, + Seed, +}; + +#[cfg(feature = "parallel")] +use rayon::prelude::*; + +macro_rules! cfg_iter { + ($e: expr) => {{ + #[cfg(feature = "parallel")] + let result = $e.par_iter(); + #[cfg(not(feature = "parallel"))] + let result = $e.iter(); + result + }}; +} + +pub const SCALAR_SIZE: usize = 32; +pub type ArkScalar = crate::pmp::m1_blst::Fr; +pub type Commitment = crate::pmp::Commitment; +pub use poly_multiproof::traits::AsBytes; + +#[cfg(test)] +mod tests; + +pub struct EvaluationGrid { + lookup: DataLookup, + evals: DMatrix, +} + +#[derive(Error, Debug, Clone, Copy)] +pub enum AppRowError { + #[error("Original dimensions are not divisible by current ones")] + OrigDimNotDivisible, + #[error("AppId({0}) not found")] + IdNotFound(AppId), + #[error("Lineal index overflows")] + LinealIndexOverflows, +} + +impl EvaluationGrid { + /// From the app extrinsics, create a data grid of Scalars + pub fn from_extrinsics( + extrinsics: Vec, + min_width: usize, + max_width: usize, + max_height: usize, + rng_seed: Seed, + ) -> Result { + // Group extrinsics by app id, also sorted by app id. + // Using a BTreeMap here will still iter in sorted order. Sweet! + let grouped = extrinsics.into_iter().fold::>, _>( + BTreeMap::default(), + |mut acc, e| { + acc.entry(e.app_id).or_default().push(e.data); + acc + }, + ); + + // Convert each grup of extrinsics into scalars + let scalars_by_app = grouped + .into_iter() + .map(|(id, datas)| { + let mut enc = datas.encode(); + enc.push(PADDING_TAIL_VALUE); // TODO: remove 9797 padding stuff + enc.chunks(DATA_CHUNK_SIZE) + .map(pad_to_bls_scalar) + .collect::, _>>() + .map(|scalars| (id, scalars)) + }) + .collect::, _>>()?; + + let len_by_app = scalars_by_app + .iter() + .map(|(app, scalars)| (*app, scalars.len())); + + // make the index of app info + let lookup = DataLookup::from_id_and_len_iter(len_by_app)?; + let grid_size = usize::try_from(lookup.len())?; + let (rows, cols): (usize, usize) = + get_block_dims(grid_size, min_width, max_width, max_height)?.into(); + + // Flatten the grid + let mut rng = ChaChaRng::from_seed(rng_seed); + let grid = scalars_by_app + .into_iter() + .flat_map(|(_, scalars)| scalars) + .chain(iter::repeat_with(|| random_scalar(&mut rng))); + + let row_major_evals = DMatrix::from_row_iterator(rows, cols, grid); + + Ok(EvaluationGrid { + lookup, + evals: row_major_evals, + }) + } + + /// Get the row `y` of the evaluation. + pub fn row(&self, y: usize) -> Option> { + let (rows, _cols) = self.evals.shape(); + (y < rows).then(|| self.evals.row(y).iter().cloned().collect()) + } + + pub fn dims(&self) -> Dimensions { + let (rows, cols) = self.evals.shape(); + // SAFETY: We cannot construct an `EvaluationGrid` with any dimension `< 1` or `> u16::MAX` + debug_assert!(rows <= usize::from(u16::MAX) && cols <= usize::from(u16::MAX)); + unsafe { Dimensions::new_unchecked(rows as u16, cols as u16) } + } + + #[inline] + pub fn get(&self, row: R, col: C) -> Option<&ArkScalar> + where + usize: From, + usize: From, + { + self.evals.get::<(usize, usize)>((row.into(), col.into())) + } + + /// Returns a list of `(index, row)` pairs for the underlying rows of an application. + /// Returns `None` if the `app_id` cannot be found, or if the provided `orig_dims` are invalid. + pub fn app_rows( + &self, + app_id: AppId, + maybe_orig_dims: Option, + ) -> Result)>>, AppRowError> { + let dims = self.dims(); + let (rows, _cols): (usize, usize) = dims.into(); + + // Ensure `origin_dims` is divisible by `dims` if some. + let orig_dims = match maybe_orig_dims { + Some(d) => { + ensure!(d.divides(&dims), AppRowError::OrigDimNotDivisible); + d + }, + None => dims, + }; + + // SAFETY: `origin_dims.rows is NonZeroU16` + // Compiler checks that `Dimensions::rows()` returns a `NonZeroU16` using the expression + // `NonZeroU16::get(x)` instead of `x.get()`. + #[allow(clippy::integer_arithmetic)] + let h_mul: usize = rows / usize::from(NonZeroU16::get(orig_dims.rows())); + #[allow(clippy::integer_arithmetic)] + let row_from_lineal_index = |cols, lineal_index| { + let lineal_index = + usize::try_from(lineal_index).map_err(|_| AppRowError::LinealIndexOverflows)?; + let cols = usize::from(NonZeroU16::get(cols)); + + Ok(lineal_index / cols) + }; + + let range = self + .lookup + .range_of(app_id) + .ok_or(AppRowError::IdNotFound(app_id))?; + let start_y: usize = row_from_lineal_index(orig_dims.cols(), range.start)?; + let end_y: usize = row_from_lineal_index(orig_dims.cols(), range.end.saturating_sub(1))?; + + // SAFETY: This won't overflow because `h_mul = rows / orig_dim.rows()` and `*_y < rows) + debug_assert!(start_y < rows); + debug_assert!(end_y < rows); + #[allow(clippy::integer_arithmetic)] + let (new_start_y, new_end_y) = (start_y * h_mul, end_y * h_mul); + + let app_rows = (new_start_y..=new_end_y) + .step_by(h_mul) + .map(|y| self.row(y).map(|a| (y, a))) + .collect(); + + Ok(app_rows) + } + + pub fn extend_columns(&self, row_factor: NonZeroU16) -> Result { + let dims = self.dims(); + let (new_rows, new_cols): (usize, usize) = dims + .extend(row_factor, unsafe { NonZeroU16::new_unchecked(1) }) + .ok_or(Error::CellLengthExceeded)? + .into(); + let (rows, _cols): (usize, usize) = dims.into(); + + let domain = + GeneralEvaluationDomain::::new(rows).ok_or(Error::DomainSizeInvalid)?; + let domain_new = + GeneralEvaluationDomain::::new(new_rows).ok_or(Error::DomainSizeInvalid)?; + ensure!(domain_new.size() == new_rows, Error::DomainSizeInvalid); + + let new_data = self.evals.column_iter().flat_map(|col| { + let mut col = col.iter().cloned().collect::>(); + domain.ifft_in_place(&mut col); + domain_new.fft_in_place(&mut col); + col + }); + + let row_major_evals = DMatrix::from_iterator(new_rows, new_cols, new_data); + debug_assert!(row_major_evals.shape() == (new_rows, new_cols)); + Ok(Self { + lookup: self.lookup.clone(), + evals: row_major_evals, + }) + } + + pub fn make_polynomial_grid(&self) -> Result { + let (_rows, cols): (usize, usize) = self.evals.shape(); + let domain = + GeneralEvaluationDomain::::new(cols).ok_or(Error::DomainSizeInvalid)?; + + let inner = self + .evals + .row_iter() + .map(|view| { + let row = view.iter().cloned().collect::>(); + domain.ifft(&row) + }) + .collect::>(); + + Ok(PolynomialGrid { + dims: self.dims(), + points: domain.elements().collect(), + inner, + }) + } +} + +pub struct PolynomialGrid { + inner: Vec>, + points: Vec, + dims: Dimensions, +} + +impl PolynomialGrid { + pub fn commitments( + &self, + srs: &(impl Committer + Sync), + ) -> Result, Error> { + cfg_iter!(self.inner) + .map(|poly| srs.commit(poly).map_err(Error::MultiproofError)) + .collect() + } + + /// Computes the commitments of the grid for the given extension by committing, then fft-ing + /// the commitments. + // TODO: fix this all up without the gross conversions after moving to arkworks + pub fn extended_commitments( + &self, + srs: &(impl Committer + Sync), + extension_factor: usize, + ) -> Result, Error> { + let res = cfg_iter!(self.inner) + .map(|coeffs| srs.commit(coeffs).map_err(Error::MultiproofError)) + .collect::, _>>()?; + poly_multiproof::Commitment::::extend_commitments( + &res, + res.len().saturating_mul(extension_factor), + ) + .map_err(Error::MultiproofError) + } + + pub fn commitment( + &self, + srs: &impl Committer, + row: usize, + ) -> Result { + self.inner + .get(row) + .ok_or(Error::CellLengthExceeded) + .and_then(|poly| srs.commit(poly).map_err(Error::MultiproofError)) + } + + pub fn proof(&self, srs: &M1NoPrecomp, cell: &Cell) -> Result { + let x = cell.col.0 as usize; + let y = cell.row.0 as usize; + let poly = self.inner.get(y).ok_or(Error::CellLengthExceeded)?; + let witness = KZGProof::compute_witness_polynomial(srs, poly.clone(), self.points[x])?; + Ok(KZGProof::open(srs, witness)?) + } + + pub fn multiproof( + &self, + srs: &M1NoPrecomp, + cell: &Cell, + eval_grid: &EvaluationGrid, + target_dims: Dimensions, + ) -> Result { + let block = multiproof_block( + cell.col.0 as usize, + cell.row.0 as usize, + self.dims, + target_dims, + ) + .ok_or(Error::CellLengthExceeded)?; + let polys = &self.inner[block.start_y..block.end_y]; + let evals: Vec> = (block.start_y..block.end_y) + .map(|y| { + eval_grid.row(y).expect("Already bounds checked .qed")[block.start_x..block.end_x] + .to_vec() + }) + .collect::>(); + let evals_view = evals.iter().map(|row| row.as_slice()).collect::>(); + + let points = &self.points[block.start_x..block.end_x]; + let mut ts = Transcript::new(b"avail-mp"); + let proof = PolyMultiProofNoPrecomp::open(srs, &mut ts, &evals_view, polys, points) + .map_err(Error::MultiproofError)?; + + Ok(Multiproof { + proof, + evals, + block, + }) + } +} + +#[derive(Debug, Clone)] +pub struct Multiproof { + pub proof: poly_multiproof::m1_blst::Proof, + pub evals: Vec>, + pub block: CellBlock, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CellBlock { + pub start_x: usize, + pub start_y: usize, + pub end_x: usize, + pub end_y: usize, +} + +/// Computes the `x, y`-th multiproof block of a grid of size `grid_dims`. +/// `mp_grid_dims` is the size of the multiproof grid, which `x,y` lies in. +/// For example, a 256x256 grid could be converted to a 4x4 target size multiproof grid, by making 16 multiproofs +/// of size 64x64. +#[allow(clippy::integer_arithmetic)] +pub fn multiproof_block( + x: usize, + y: usize, + grid: Dimensions, + target: Dimensions, +) -> Option { + let mp_grid_dims = multiproof_dims(grid, target)?; + let (g_rows, g_cols): (usize, usize) = grid.into(); + if x >= mp_grid_dims.width() || y >= mp_grid_dims.height() { + return None; + } + + // SAFETY: Division is safe because `cols() != 0 && rows() != 0`. + let block_width = g_cols / usize::from(NonZeroU16::get(mp_grid_dims.cols())); + let block_height = g_rows / usize::from(NonZeroU16::get(mp_grid_dims.rows())); + + // SAFETY: values never overflow since `x` and `y` are always less than grid_dims.{width,height}(). + // This is because x,y < mp_grid_dims.{width, height} and block width is the quotient of + // grid_dims and mp_grid_dims. + Some(CellBlock { + start_x: x * block_width, + start_y: y * block_height, + end_x: (x + 1) * block_width, + end_y: (y + 1) * block_height, + }) +} + +/// Dimensions of the multiproof grid. These are guarenteed to cleanly divide `grid_dims`. +/// `target_dims` must cleanly divide `grid_dims`. +pub fn multiproof_dims(grid: Dimensions, target: Dimensions) -> Option { + let cols = min(grid.cols(), target.cols()); + let rows = min(grid.rows(), target.rows()); + if grid.cols().get() % cols != 0 || grid.rows().get() % rows != 0 { + return None; + } + + Dimensions::new(rows, cols) +} + +pub fn get_block_dims( + n_scalars: usize, + min_width: usize, + max_width: usize, + max_height: usize, +) -> Result { + // Less than max_width wide block + if n_scalars < max_width { + let current_width = n_scalars; + // Don't let the width get lower than the minimum provided + let width = max( + current_width + .checked_next_power_of_two() + .ok_or(Error::BlockTooBig)?, + min_width, + ); + let height = unsafe { NonZeroU16::new_unchecked(1) }; + + Dimensions::new_from(height, width).ok_or(Error::ZeroDimension) + } else { + let width = NonZeroU16::try_from(u16::try_from(max_width)?)?; + let current_height = round_up_to_multiple(n_scalars, width) + .checked_div(max_width) + .expect("`max_width` is non zero, checked one line before"); + // Round the height up to a power of 2 for ffts + let height = current_height + .checked_next_power_of_two() + .ok_or(Error::BlockTooBig)?; + // Error if height too big + ensure!(height <= max_height, Error::BlockTooBig); + + Dimensions::new_from(height, width).ok_or(Error::ZeroDimension) + } +} + +pub fn domain_points(n: usize) -> Result, Error> { + let domain = GeneralEvaluationDomain::::new(n).ok_or(Error::DomainSizeInvalid)?; + Ok(domain.elements().collect()) +} + +/// SAFETY: As `multiple` is a `NonZeroU16` we can safetly make the following ops. +#[allow(clippy::integer_arithmetic)] +fn round_up_to_multiple(input: usize, multiple: NonZeroU16) -> usize { + let multiple: usize = multiple.get().into(); + let n_multiples = input.saturating_add(multiple - 1) / multiple; + n_multiples.saturating_mul(multiple) +} + +pub(crate) fn pad_to_bls_scalar(a: impl AsRef<[u8]>) -> Result { + let bytes = a.as_ref(); + ensure!(bytes.len() <= DATA_CHUNK_SIZE, Error::InvalidChunkLength); + const_assert!(DATA_CHUNK_SIZE <= SCALAR_SIZE); + + let mut buf = [0u8; SCALAR_SIZE]; + buf[0..bytes.len()].copy_from_slice(bytes); + + ArkScalar::from_bytes(&buf).map_err(Error::MultiproofError) +} + +#[allow(clippy::integer_arithmetic)] +pub(crate) fn random_scalar(rng: &mut ChaChaRng) -> ArkScalar { + let mut raw_scalar = [0u8; SCALAR_SIZE]; + + const_assert!(SCALAR_SIZE >= 1); + rng.try_fill_bytes(&mut raw_scalar[..SCALAR_SIZE - 1]) + .expect("ChaChaRng::try_fill_bytes failed"); + debug_assert!(raw_scalar[SCALAR_SIZE - 1] == 0u8); + + ArkScalar::from_bytes(&raw_scalar) + .expect("ArkScalar can be generated from SCALAR_SIZE -1 bytes .qed") +} + +#[cfg(test)] +#[allow(clippy::integer_arithmetic)] +mod unit_tests { + use super::*; + use proptest::{prop_assert_eq, proptest}; + use test_case::test_case; + + // parameters that will split a 256x256 grid into pieces of size 4x16 + const TARGET: Dimensions = unsafe { Dimensions::new_unchecked(16, 64) }; + const GRID: Dimensions = unsafe { Dimensions::new_unchecked(256, 256) }; + + fn cb(start_x: usize, start_y: usize, end_x: usize, end_y: usize) -> CellBlock { + CellBlock { + start_x, + start_y, + end_x, + end_y, + } + } + #[test_case(0, 0 => Some(cb(0, 0, 4, 16)))] + #[test_case(1, 0 => Some(cb(4, 0, 8, 16)))] + #[test_case(0, 1 => Some(cb(0, 16, 4, 32)))] + #[test_case(1, 1 => Some(cb(4, 16, 8, 32)))] + #[test_case(64, 0 => None)] + #[test_case(0, 16 => None)] + fn multiproof_max_grid_size(x: usize, y: usize) -> Option { + multiproof_block(x, y, GRID.clone(), TARGET) + } + + #[test_case(256, 256, 64, 16 => Some((64, 16)))] + #[test_case(256, 256, 32, 32 => Some((32, 32)))] + #[test_case(256, 256, 7, 32 => None)] + #[test_case(32 , 32, 32, 32 => Some((32, 32)))] + #[test_case(256, 8, 32, 32 => Some((32, 8)))] + #[test_case(4 , 1, 32, 32 => Some((4, 1)))] + fn test_multiproof_dims( + grid_w: u16, + grid_h: u16, + target_w: u16, + target_h: u16, + ) -> Option<(usize, usize)> { + let grid = unsafe { Dimensions::new_unchecked(grid_w, grid_h) }; + let target = unsafe { Dimensions::new_unchecked(target_w, target_h) }; + + multiproof_dims(grid, target).map(Into::into) + } + + use proptest::prelude::*; + proptest! { + #![proptest_config(ProptestConfig { + cases: 200, .. ProptestConfig::default() + })] + #[test] + fn test_round_up_to_multiple(i in 1..1000usize, m in 1..32u16) { + for k in 0..usize::from(m) { + let a :usize = i * usize::from(m) - k; + let output = round_up_to_multiple(a, m.try_into().unwrap()); + let expected :usize = i * usize::from(m); + prop_assert_eq!( output, expected) + } + } + } + #[test_case(0 => 1)] + #[test_case(1 => 1)] + #[test_case(2 => 2)] + #[test_case(3 => 4)] + #[test_case(6 => 8)] + #[test_case(972 => 1024)] + fn test_round_up_to_2(i: usize) -> usize { + i.next_power_of_two() + } + + fn new_dim(rows: u16, cols: u16) -> Result { + Dimensions::new(rows, cols).ok_or(Error::BlockTooBig) + } + + #[test_case(0 => new_dim(1,4) ; "block size zero")] + #[test_case(1 => new_dim(1,4) ; "below minimum block size")] + #[test_case(10 => new_dim(1, 16) ; "regular case")] + #[test_case(17 => new_dim(1, 32) ; "minimum overhead after 512")] + #[test_case(256 => new_dim(1, 256) ; "maximum cols")] + #[test_case(257 => new_dim(2, 256) ; "two rows")] + #[test_case(256 * 256 => new_dim(256, 256) ; "max block size")] + #[test_case(256 * 256 + 1 => Err(Error::BlockTooBig) ; "too much data")] + fn test_get_block_dims(size: usize) -> Result +where { + get_block_dims(size, 4, 256, 256) + } +} diff --git a/kate/src/gridgen/tests/commitments.rs b/kate/src/gridgen/tests/commitments.rs new file mode 100644 index 00000000..ccdd46f2 --- /dev/null +++ b/kate/src/gridgen/tests/commitments.rs @@ -0,0 +1,187 @@ +use super::*; +use crate::{gridgen::*, testnet, Seed}; +use avail_core::{AppExtrinsic, AppId, BlockLengthColumns, BlockLengthRows}; +use hex_literal::hex; +use kate_recovery::{ + commitments::verify_equality, + matrix::{Dimensions, Position}, +}; +use test_case::test_case; + +#[test] +fn test_build_commitments_simple_commitment_check() { + let original_data = br#"test"#; + let block_height = 256usize; + let block_width = 256usize; + let hash: Seed = [ + 76, 41, 174, 145, 187, 12, 97, 32, 75, 111, 149, 209, 243, 195, 165, 10, 166, 172, 47, 41, + 218, 24, 212, 66, 62, 5, 187, 191, 129, 5, 105, 3, + ]; + let pmp_pp = crate::testnet::multiproof_params(256, 256); + + let evals = EvaluationGrid::from_extrinsics( + vec![AppExtrinsic::from(original_data.to_vec())], + 4, + block_width, + block_height, + hash, + ) + .unwrap(); + let ext_evals = evals + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + let polys = ext_evals.make_polynomial_grid().unwrap(); + let commits = polys + .commitments(&*PMP) + .unwrap() + .into_iter() + .flat_map(|p| p.to_bytes().unwrap()) + .collect::>(); + let commits_fft_extended = evals + .make_polynomial_grid() + .unwrap() + .extended_commitments(&pmp_pp, 2) + .unwrap() + .into_iter() + .flat_map(|p| p.to_bytes().unwrap()) + .collect::>(); + + assert_eq!(ext_evals.dims(), Dimensions::new_from(2, 4).unwrap()); + let expected_commitments = hex!("9046c691ce4c7ba93c9860746d6ff3dfb5560e119f1eac26aa9a10b6fe29d5c8e2b90f23e2ef3a7a950965b08035470d9046c691ce4c7ba93c9860746d6ff3dfb5560e119f1eac26aa9a10b6fe29d5c8e2b90f23e2ef3a7a950965b08035470d"); + assert_eq!(commits, expected_commitments); + assert_eq!(commits_fft_extended, expected_commitments); +} + +#[test] +fn par_build_commitments_row_wise_constant_row() { + // Due to scale encoding, first line is not constant. + // We will use second line to ensure constant row. + let hash = Seed::default(); + let xts = vec![AppExtrinsic { + app_id: AppId(0), + data: vec![0; 31 * 8], + }]; + + let evals = EvaluationGrid::from_extrinsics(xts, 4, 4, 4, hash).unwrap(); + let evals = evals + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + let polys = evals.make_polynomial_grid().unwrap(); + polys.commitments(&*PMP).unwrap(); +} + +proptest! { + #![proptest_config(ProptestConfig::with_cases(20))] + #[test] + fn commitments_verify(ref exts in app_extrinsics_strategy()) { + //let (layout, commitments, dims, matrix) = par_build_commitments(BlockLengthRows(64), BlockLengthColumns(16), 32, xts, Seed::default()).unwrap(); + let grid = EvaluationGrid::from_extrinsics(exts.clone(), 4, 16, 64, Seed::default()).unwrap(); + let grid = grid.extend_columns( unsafe { NonZeroU16::new_unchecked(2)}).unwrap(); + let (g_rows, g_cols) :(u16,u16) = grid.dims().into(); + let orig_dims = Dimensions::new(g_rows / 2, g_cols).unwrap(); + let polys = grid.make_polynomial_grid().unwrap(); + let commits = polys.commitments(&*PMP) + .unwrap() + .iter() + .map(|c| c.to_bytes().unwrap()) + .collect::>(); + + let public_params = testnet::public_params(BlockLengthColumns(g_cols as u32)); + + for xt in exts.iter() { + let rows = grid.app_rows(xt.app_id, Some(orig_dims)).unwrap().unwrap(); + // Have to put the rows we find in this funky data structure + let mut app_rows = vec![None; g_rows.into()]; + for (row_i, row) in rows { + app_rows[row_i] = Some(row.iter().flat_map(|s| s.to_bytes().unwrap()).collect()); + } + // Need to provide the original dimensions here too + let extended_dims = orig_dims.clone(); + let (_, missing) = verify_equality(&public_params, &commits, &app_rows, &grid.lookup, extended_dims, xt.app_id).unwrap(); + prop_assert!(missing.is_empty()); + } + } + + fn verify_commitments_missing_row(ref xts in app_extrinsics_strategy()) { + let grid = EvaluationGrid::from_extrinsics(xts.clone(), 4, 16, 64, Seed::default()).unwrap().extend_columns( unsafe { NonZeroU16::new_unchecked(2) }).unwrap(); + let (g_rows, g_cols):(u16,u16) = grid.dims().into(); + let orig_dims = Dimensions::new_from(g_rows / 2, g_cols).unwrap(); + let polys = grid.make_polynomial_grid().unwrap(); + let commits = polys.commitments(&*PMP) + .unwrap() + .iter() + .map(|c| c.to_bytes().unwrap()) + .collect::>(); + + let public_params = testnet::public_params( BlockLengthColumns(g_cols.into())); + + for xt in xts { + let rows = grid.app_rows(xt.app_id, Some(orig_dims)).unwrap().unwrap(); + let mut row_elems = vec![None; g_rows.into()]; + for (i, data) in &rows { + row_elems[*i] = Some(data.iter().flat_map(|s| s.to_bytes().unwrap()).collect()); + } + let first_index = rows.iter().map(|(i, _)| *i).min().unwrap(); + row_elems.remove(first_index); + + let extended_dims = orig_dims.transpose(); + let (_, missing) = verify_equality(&public_params, &commits, &row_elems,&grid.lookup,extended_dims,xt.app_id).unwrap(); + prop_assert!(!missing.is_empty()); + } + } +} + +#[test_case( vec![1;4]; "All values are non-zero but same")] +#[test_case( vec![0;4]; "All values are zero")] +#[test_case( vec![0,5,2,1]; "All values are different")] +fn test_zero_deg_poly_commit(row_values: Vec) { + // There are two main cases that generate a zero degree polynomial. One is for data that is non-zero, but the same. + // The other is for all-zero data. They differ, as the former yields a polynomial with one coefficient, and latter generates zero coefficients. + let len = row_values.len(); + let row = row_values + .iter() + .map(|val| pad_to_bls_scalar(&[*val]).unwrap()) + .collect::>(); + + //let ae = AppExtrinsic { 0.into(), vec![} + let ev = EvaluationGrid { + lookup: Default::default(), // Shouldn't need to care about this + evals: DMatrix::from_row_iterator(len, 1, row.into_iter()).transpose(), + }; + + println!("Row: {:?}", ev.evals); + + let pg = ev.make_polynomial_grid().unwrap(); + println!("Poly: {:?}", pg.inner[0]); + let commitment = pg.commitment(&*PMP, 0).unwrap().to_bytes().unwrap(); + + for x in 0..len { + // Randomly chosen cell to prove, probably should test all of them + let cell = Cell { + col: BlockLengthColumns(x.try_into().unwrap()), + row: BlockLengthRows(0), + }; + + let proof = pg.proof(&*PMP, &cell).unwrap(); + + let proof_bytes = proof.to_bytes().unwrap(); + let cell_bytes = ev.get(0usize, x).unwrap().to_bytes().unwrap(); + let content = [&proof_bytes[..], &cell_bytes[..]].concat(); + let dims = Dimensions::new(1, 4).unwrap(); + let cell = kate_recovery::data::Cell { + position: Position { + row: 0, + col: x as u16, + }, + content: content.try_into().unwrap(), + }; + let verification = kate_recovery::proof::verify( + &kate_recovery::testnet::public_params(256), + dims, + &commitment, + &cell, + ); + assert!(verification.is_ok()); + assert!(verification.unwrap()) + } +} diff --git a/kate/src/gridgen/tests/formatting.rs b/kate/src/gridgen/tests/formatting.rs new file mode 100644 index 00000000..c8cef4c1 --- /dev/null +++ b/kate/src/gridgen/tests/formatting.rs @@ -0,0 +1,169 @@ +use avail_core::{AppExtrinsic, AppId, DataLookup}; +use hex_literal::hex; +use kate_recovery::{ + com::{app_specific_cells, decode_app_extrinsics, reconstruct_extrinsics}, + data::DataCell, + matrix::Dimensions, +}; +use nalgebra::base::DMatrix; +use poly_multiproof::traits::AsBytes; + +use crate::{ + config::DATA_CHUNK_SIZE, + gridgen::{tests::sample_cells, ArkScalar, EvaluationGrid}, + Seed, +}; +use core::num::NonZeroU16; + +#[test] +fn newapi_test_flatten_block() { + let extrinsics: Vec = vec![ + AppExtrinsic::new(AppId(0), (1..=29).collect()), + AppExtrinsic::new(AppId(1), (1..=30).collect()), + AppExtrinsic::new(AppId(2), (1..=31).collect()), + AppExtrinsic::new(AppId(3), (1..=60).collect()), + ]; + + let expected_dims = Dimensions::new_from(1, 16).unwrap(); + let evals = EvaluationGrid::from_extrinsics(extrinsics, 4, 256, 256, Seed::default()).unwrap(); + + let id_lens: Vec<(u32, usize)> = vec![(0, 2), (1, 2), (2, 2), (3, 3)]; + let expected_lookup = DataLookup::from_id_and_len_iter(id_lens.into_iter()).unwrap(); + + assert_eq!(evals.lookup, expected_lookup, "The layouts don't match"); + assert_eq!( + evals.dims(), + expected_dims, + "Dimensions don't match the expected" + ); + + let expected_data = hex!("04740102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d00800000000000000000000000000000000000000000000000000000000000000004780102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e80000000000000000000000000000000000000000000000000000000000000047c0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e1f80000000000000000000000000000000000000000000000000000000000004f00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d001e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c00800000000000000000000000000000000000000000000000000000000000000076b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770d00da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee65009f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7a0029b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d002d09a0e663266ce1ae7ed1081968a0758e718e997bd362c6b0c34634a9a0b300012737681f7b5d0f281e3afde458bc1e73d2d313c9cf94c05ff3716240a248001320a058d7b3566bd520daaa3ed2bf0ac5b8b120fb852773c3639734b45c9100"); + + let data = evals + .evals + .row_iter() + .flat_map(|row| { + row.iter() + .flat_map(|s| s.to_bytes().unwrap()) + .collect::>() + }) + .collect::>(); + assert_eq!(data, expected_data, "Data doesn't match the expected data"); +} + +#[test] +fn newapi_test_extend_data_matrix() { + // This test expects this result in column major + let expected_data = vec![ + hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e00"), + hex!("bc1c6b8b4b02ca677b825ec9dace9aa706813f3ec47abdf9f03c680f4468555e"), + hex!("7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a00"), + hex!("c16115f73784be22106830c9bc6bbb469bf5026ee80325e403efe5ccc3f55016"), + hex!("1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d00"), + hex!("db3b8aaa6a21e9869aa17de8f9edb9c625a05e5de399dc18105c872e6387745e"), + hex!("9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b900"), + hex!("e080341657a3dd412f874fe8db8ada65ba14228d07234403230e05ece2147016"), + hex!("3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c00"), + hex!("fa5aa9c9894008a6b9c09c07190dd9e544bf7d7c02b9fb372f7ba64d82a6935e"), + hex!("babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d800"), + hex!("ff9f533576c2fc604ea66e07fba9f984d93341ac26426322422d240b02348f16"), + hex!("5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b00"), + hex!("197ac8e8a85f27c5d8dfbb26382cf80464de9c9b21d81a574e9ac56ca1c5b25e"), + hex!("d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f700"), + hex!("1ebf725495e11b806dc58d261ac918a4f85260cb45618241614c432a2153ae16"), + ] + .iter() + .map(ArkScalar::from_bytes) + .collect::, _>>() + .expect("Invalid Expected result"); + + let expected_result = DMatrix::from_column_slice(4, 4, &expected_data); + + let scalars = (0..=247) + .collect::>() + .chunks_exact(DATA_CHUNK_SIZE) + .flat_map(crate::gridgen::pad_to_bls_scalar) + .collect::>(); + + let grid = EvaluationGrid { + lookup: DataLookup::default(), + evals: DMatrix::from_row_iterator(2, 4, scalars.into_iter()), + }; + let extend = grid + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + + assert_eq!(extend.evals, expected_result); +} + +#[test] +fn test_decode_app_extrinsics() { + let app_id_1_data = br#""This is mocked test data. It will be formatted as a matrix of BLS scalar cells and then individual columns +get erasure coded to ensure redundancy."#; + + let app_id_2_data = + br#""Let's see how this gets encoded and then reconstructed by sampling only some data."#; + + let data = [vec![0], app_id_1_data.to_vec(), app_id_2_data.to_vec()]; + + let hash = Seed::default(); + let xts = (0..=2) + .zip(data) + .map(|(id, data)| AppExtrinsic::new(AppId(id), data)) + .collect::>(); + + let grid = EvaluationGrid::from_extrinsics(xts.clone(), 4, 32, 4, hash) + .unwrap() + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + + let bdims = grid.dims(); + for xt in &xts { + let positions = app_specific_cells(&grid.lookup, bdims, xt.app_id).unwrap(); + let cells = positions + .iter() + .map(|pos| DataCell { + position: pos.clone(), + data: grid + .evals + .get((pos.row as usize, pos.col as usize)) + .unwrap() + .to_bytes() + .unwrap(), + }) + .collect::>(); + let data = &decode_app_extrinsics(&grid.lookup, bdims, cells, xt.app_id).unwrap()[0]; + assert_eq!(data, &xt.data); + } + + assert!(matches!( + decode_app_extrinsics(&grid.lookup, bdims, vec![], AppId(0)), + Err(kate_recovery::com::ReconstructionError::MissingCell { .. }) + )); +} + +#[test] +fn test_extend_mock_data() { + let orig_data = r#"This is mocked test data. It will be formatted as a matrix of BLS scalar cells and then individual columns +get erasure coded to ensure redundancy. +Let's see how this gets encoded and then reconstructed by sampling only some data."#; + let exts = vec![AppExtrinsic::from(orig_data.as_bytes().to_vec())]; + + // The hash is used for seed for padding the block to next power of two value + let hash = Seed::default(); + let grid = EvaluationGrid::from_extrinsics(exts.clone(), 4, 128, 2, hash) + .unwrap() + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + + let cols = sample_cells(&grid, None); + let bdims = grid.dims(); + + let res = reconstruct_extrinsics(&grid.lookup, bdims, cols).unwrap(); + let s = String::from_utf8_lossy(res[0].1[0].as_slice()); + + assert_eq!(s, orig_data); + assert_eq!(res[0].1[0], orig_data.as_bytes()); + + eprintln!("Decoded: {}", s); +} diff --git a/kate/src/gridgen/tests/mod.rs b/kate/src/gridgen/tests/mod.rs new file mode 100644 index 00000000..5475647e --- /dev/null +++ b/kate/src/gridgen/tests/mod.rs @@ -0,0 +1,74 @@ +use avail_core::{AppExtrinsic, AppId}; +use kate_recovery::{data::DataCell, matrix::Position}; +use once_cell::sync::Lazy; +use poly_multiproof::{m1_blst::M1NoPrecomp, traits::AsBytes}; +use proptest::{collection, prelude::*, sample::size_range}; +use rand::{distributions::Uniform, prelude::Distribution, SeedableRng}; +use rand_chacha::ChaChaRng; + +use crate::{gridgen::ArkScalar, testnet}; + +use super::EvaluationGrid; + +mod commitments; +mod formatting; +mod reconstruction; + +pub static PMP: Lazy = Lazy::new(|| testnet::multiproof_params(256, 256)); + +fn app_extrinsic_strategy() -> impl Strategy { + ( + any::(), + any_with::>(size_range(1..2048).lift()), + ) + .prop_map(|(app_id, data)| AppExtrinsic { + app_id: AppId(app_id), + data, + }) +} + +fn app_extrinsics_strategy() -> impl Strategy> { + collection::vec(app_extrinsic_strategy(), size_range(1..16)).prop_map(|xts| { + let mut new_xts = xts; + new_xts.sort_by(|a1, a2| a1.app_id.cmp(&a2.app_id)); + new_xts + }) +} + +fn sample_unique(rng: &mut impl Rng, n_samples: usize, n: usize) -> Vec { + let mut sampled = vec![]; + let u = Uniform::from(0..n); + while sampled.len() < n_samples || sampled.len() < n { + let t = u.sample(rng); + if !sampled.contains(&t) { + sampled.push(t) + } + } + sampled +} + +fn sample_cells(grid: &EvaluationGrid, columns: Option>) -> Vec { + let mut rng = ChaChaRng::from_seed([42u8; 32]); + let (g_rows, g_cols): (usize, usize) = grid.dims().into(); + let cols = columns.unwrap_or_else(|| (0..g_cols).into_iter().collect()); + + cols.iter() + .flat_map(|x| { + debug_assert!(*x < g_cols); + sample_unique(&mut rng, g_rows / 2, g_rows) + .into_iter() + .map(move |y| { + let data = grid + .evals + .get((y, *x)) + .and_then(|s: &ArkScalar| s.to_bytes().ok()) + .unwrap(); + // SAFETY: `y` and `x` can be casted safetly becasue `x < g_cols (u16)` and `y + // < g_rows(u16)` + let position = Position::from((y as u32, *x as u16)); + + DataCell::new(position, data) + }) + }) + .collect::>() +} diff --git a/kate/src/gridgen/tests/reconstruction.rs b/kate/src/gridgen/tests/reconstruction.rs new file mode 100644 index 00000000..716a2352 --- /dev/null +++ b/kate/src/gridgen/tests/reconstruction.rs @@ -0,0 +1,115 @@ +use super::PMP; +use crate::{ + com::Cell, + gridgen::{tests::sample_cells, EvaluationGrid}, + Seed, +}; +use avail_core::{AppExtrinsic, AppId, BlockLengthColumns, BlockLengthRows}; +use core::num::NonZeroU16; +use kate_recovery::{ + com::{reconstruct_app_extrinsics, reconstruct_extrinsics}, + data::Cell as DCell, + matrix::{Dimensions, Position}, +}; +use poly_multiproof::traits::AsBytes; +use proptest::prelude::*; +use rand::{distributions::Uniform, prelude::Distribution, SeedableRng}; +use rand_chacha::ChaChaRng; + +#[test] +fn test_multiple_extrinsics_for_same_app_id() { + let xt1 = vec![5, 5]; + let xt2 = vec![6, 6]; + let xts = [ + AppExtrinsic::new(AppId(1), xt1.clone()), + AppExtrinsic::new(AppId(1), xt2.clone()), + ]; + // The hash is used for seed for padding the block to next power of two value + let hash = Seed::default(); + let ev = EvaluationGrid::from_extrinsics(xts.into(), 4, 128, 2, hash) + .unwrap() + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + + let cells = sample_cells(&ev, None); + let (rows, cols): (u16, u16) = ev.dims().into(); + let bdims = Dimensions::new_from(rows, cols).unwrap(); + let res = reconstruct_extrinsics(&ev.lookup, bdims, cells).unwrap(); + + assert_eq!(res[0].1[0], xt1); + assert_eq!(res[0].1[1], xt2); +} + +proptest! { +#![proptest_config(ProptestConfig::with_cases(5))] +#[test] +fn test_build_and_reconstruct(exts in super::app_extrinsics_strategy()) { + let grid = EvaluationGrid::from_extrinsics(exts.clone(), 4, 256, 256, Seed::default()).unwrap().extend_columns(unsafe { NonZeroU16::new_unchecked(2)}).unwrap(); + let (rows, cols) :(usize,usize)= grid.dims().into(); + //let (layout, commitments, dims, matrix) = par_build_commitments( + // BlockLengthRows(64), BlockLengthColumns(16), 32, xts, Seed::default()).unwrap(); + const RNG_SEED: Seed = [42u8; 32]; + + let cells = sample_cells(&grid, None); + let bdims = Dimensions::new_from(rows, cols).unwrap(); + let reconstructed = reconstruct_extrinsics(&grid.lookup, bdims, cells).unwrap(); + for ((id,data), xt) in reconstructed.iter().zip(exts) { + prop_assert_eq!(id.0, *xt.app_id); + prop_assert_eq!(data[0].as_slice(), &xt.data); + } + + let pp = &*PMP; + let polys = grid.make_polynomial_grid().unwrap(); + let commitments = polys.commitments(pp).unwrap(); + let indices = (0..cols).flat_map(|x| (0..rows).map(move |y| (x, y))).collect::>(); + + // Sample some number 10 of the indices, all is too slow for tests... + let mut rng = ChaChaRng::from_seed(RNG_SEED); + let sampled = Uniform::from(0..indices.len()).sample_iter(&mut rng).take(10).map(|i| indices[i]); + for (x, y) in sampled { + let row = BlockLengthRows(u32::try_from(y).unwrap()); + let col = BlockLengthColumns(u32::try_from(x).unwrap()); + let cell = Cell::new( row, col); + let proof = polys.proof(pp, &cell).unwrap(); + let mut content = [0u8; 80]; + content[..48].copy_from_slice(&proof.to_bytes().unwrap()[..]); + content[48..].copy_from_slice(&grid.get(y, x).unwrap().to_bytes().unwrap()[..]); + + let dcell = DCell{position: Position { row: y as u32, col: x as u16 }, content }; + let verification = kate_recovery::proof::verify(&kate_recovery::testnet::public_params(256), bdims, &commitments[y].to_bytes().unwrap(), &dcell); + prop_assert!(verification.is_ok()); + prop_assert!(verification.unwrap()); + } +} +} + +#[test] +fn test_reconstruct_app_extrinsics_with_app_id() { + let app_id_1_data = br#""This is mocked test data. It will be formatted as a matrix of BLS scalar cells and then individual columns +get erasure coded to ensure redundancy."#; + + let app_id_2_data = + br#""Let's see how this gets encoded and then reconstructed by sampling only some data."#; + + let xts = vec![ + AppExtrinsic::new(AppId(0), vec![0]), + AppExtrinsic::new(AppId(1), app_id_1_data.to_vec()), + AppExtrinsic::new(AppId(2), app_id_2_data.to_vec()), + ]; + + let grid = EvaluationGrid::from_extrinsics(xts.clone(), 4, 4, 32, Seed::default()) + .unwrap() + .extend_columns(unsafe { NonZeroU16::new_unchecked(2) }) + .unwrap(); + + let cols_1 = sample_cells(&grid, Some(vec![0, 1, 2, 3])); + + let bdims = grid.dims(); + let res_1 = reconstruct_app_extrinsics(&grid.lookup, bdims, cols_1, AppId(1)).unwrap(); + assert_eq!(res_1[0], app_id_1_data); + + let cols_2 = sample_cells(&grid, Some(vec![0, 2, 3])); + + let res_2 = reconstruct_app_extrinsics(&grid.lookup, bdims, cols_2, AppId(2)).unwrap(); + assert_eq!(res_2[0], app_id_2_data); +} diff --git a/kate/src/lib.rs b/kate/src/lib.rs index 16370ce6..fe936054 100644 --- a/kate/src/lib.rs +++ b/kate/src/lib.rs @@ -1,25 +1,42 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![deny(clippy::integer_arithmetic)] -use da_primitives::{BlockLengthColumns, BlockLengthRows}; +use avail_core::{BlockLengthColumns, BlockLengthRows}; +use core::{ + convert::TryInto, + num::{NonZeroU32, TryFromIntError}, +}; #[cfg(feature = "std")] pub use dusk_plonk::{commitment_scheme::kzg10::PublicParameters, prelude::BlsScalar}; -use frame_support::sp_runtime::SaturatedConversion; -#[cfg(feature = "std")] use kate_recovery::matrix::Dimensions; +use sp_arithmetic::traits::SaturatedConversion; use static_assertions::const_assert_ne; +use thiserror_no_std::Error; use crate::config::DATA_CHUNK_SIZE; pub const LOG_TARGET: &str = "kate"; +pub const U32_USIZE_ERR: &str = "`u32` cast to `usize` overflows, unsupported platform"; + pub type Seed = [u8; 32]; +#[cfg(feature = "std")] +pub use dusk_bytes::Serializable; +#[cfg(feature = "std")] +pub use poly_multiproof as pmp; + pub mod config { use super::{BlockLengthColumns, BlockLengthRows}; + use core::num::NonZeroU16; + // TODO: Delete this? not used anywhere pub const SCALAR_SIZE_WIDE: usize = 64; + pub const SCALAR_SIZE: usize = 32; pub const DATA_CHUNK_SIZE: usize = 31; // Actual chunk size is 32 after 0 padding is done pub const EXTENSION_FACTOR: u32 = 2; + pub const ROW_EXTENSION: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(2) }; + pub const COL_EXTENSION: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(1) }; pub const PROVER_KEY_SIZE: u32 = 48; pub const PROOF_SIZE: usize = 48; // MINIMUM_BLOCK_SIZE, MAX_BLOCK_ROWS and MAX_BLOCK_COLUMNS have to be a power of 2 because of the FFT functions requirements @@ -41,37 +58,128 @@ pub mod config { /// - Dedup this from `kate-recovery` once that library support `no-std`. #[cfg(feature = "std")] pub mod testnet { - use super::{BlockLengthColumns, PublicParameters}; + use super::*; + use hex_literal::hex; use once_cell::sync::Lazy; - use rand::SeedableRng; - use rand_chacha::ChaChaRng; + use poly_multiproof::ark_ff::{BigInt, Fp}; + use poly_multiproof::ark_serialize::CanonicalDeserialize; + use poly_multiproof::m1_blst; + use poly_multiproof::m1_blst::{Fr, G1, G2}; + use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use std::{collections::HashMap, sync::Mutex}; static SRS_DATA: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); pub fn public_params(max_degree: BlockLengthColumns) -> PublicParameters { + let max_degree: u32 = max_degree.into(); let mut srs_data_locked = SRS_DATA.lock().unwrap(); srs_data_locked - .entry(max_degree.0) + .entry(max_degree) .or_insert_with(|| { let mut rng = ChaChaRng::seed_from_u64(42); - PublicParameters::setup(max_degree.as_usize(), &mut rng).unwrap() + let max_degree = usize::try_from(max_degree).unwrap(); + PublicParameters::setup(max_degree, &mut rng).unwrap() }) .clone() } + + const SEC_LIMBS: [u64; 4] = [ + 16526363067508752668, + 17870878028964021343, + 15693365399533249662, + 1020900941429372507, + ]; + const G1_BYTES: [u8; 48] = hex!("a45f754a9e94cccbb2cbe9d7c441b8b527026ef05e2a3aff4aa4bb1c57df3767fb669cc4c7639bd37e683653bdc50b5a"); + const G2_BYTES: [u8; 96] = hex!("b845ac5e7b4ec8541d012660276772e001c1e0475e60971884481d43fcbd44de2a02e9862dbf9f536c211814f6cc5448100bcda5dc707854af8e3829750d1fb18b127286aaa4fc959e732e2128a8a315f2f8f419bf5774fe043af46fbbeb4b27"); + + pub fn multiproof_params(max_degree: usize, max_pts: usize) -> m1_blst::M1NoPrecomp { + let x: Fr = Fp(BigInt(SEC_LIMBS), core::marker::PhantomData); + + let g1 = G1::deserialize_compressed(&G1_BYTES[..]).unwrap(); + let g2 = G2::deserialize_compressed(&G2_BYTES[..]).unwrap(); + + m1_blst::M1NoPrecomp::new_from_scalar(x, g1, g2, max_degree.saturating_add(1), max_pts) + } + + #[cfg(test)] + mod tests { + use core::marker::PhantomData; + + use super::*; + use dusk_bytes::Serializable; + use dusk_plonk::{ + fft::{EvaluationDomain as PlonkED, Evaluations as PlonkEV}, + prelude::BlsScalar, + }; + use poly_multiproof::{ + ark_ff::{BigInt, Fp}, + ark_poly::{EvaluationDomain, GeneralEvaluationDomain}, + ark_serialize::{CanonicalDeserialize, CanonicalSerialize}, + m1_blst::Fr, + traits::Committer, + }; + use rand::thread_rng; + + use crate::testnet; + #[test] + fn test_consistent_testnet_params() { + let x: Fr = Fp(BigInt(SEC_LIMBS), core::marker::PhantomData); + let mut out = [0u8; 32]; + x.serialize_compressed(&mut out[..]).unwrap(); + const SEC_BYTES: [u8; 32] = + hex!("7848b5d711bc9883996317a3f9c90269d56771005d540a19184939c9e8d0db2a"); + assert_eq!(SEC_BYTES, out); + + let g1 = G1::deserialize_compressed(&G1_BYTES[..]).unwrap(); + let g2 = G2::deserialize_compressed(&G2_BYTES[..]).unwrap(); + + let pmp = poly_multiproof::m1_blst::M1NoPrecomp::new_from_scalar(x, g1, g2, 1024, 256); + + let dp_evals = (0..30) + .map(|_| BlsScalar::random(&mut thread_rng())) + .collect::>(); + + let pmp_evals = dp_evals + .iter() + .map(|i| Fp(BigInt(i.0), PhantomData)) + .collect::>(); + + let dp_poly = + PlonkEV::from_vec_and_domain(dp_evals, PlonkED::new(1024).unwrap()).interpolate(); + let pmp_ev = GeneralEvaluationDomain::::new(1024).unwrap(); + let pmp_poly = pmp_ev.ifft(&pmp_evals); + + let pubs = testnet::public_params(BlockLengthColumns(1024)); + + let dp_commit = pubs.commit_key().commit(&dp_poly).unwrap().0.to_bytes(); + let mut pmp_commit = [0u8; 48]; + pmp.commit(pmp_poly) + .unwrap() + .0 + .serialize_compressed(&mut pmp_commit[..]) + .unwrap(); + + assert_eq!(dp_commit, pmp_commit); + } + } } pub mod metrics; #[cfg(feature = "std")] pub mod com; + +#[cfg(feature = "std")] +pub mod gridgen; + /// Precalculate the length of padding IEC 9797 1. /// /// # NOTE /// There is a unit test to ensure this formula match with the current /// IEC 9797 1 algorithm we implemented. See `fn pad_iec_9797_1` #[inline] +#[allow(clippy::integer_arithmetic)] fn padded_len_of_pad_iec_9797_1(len: u32) -> u32 { let len_plus_one = len.saturating_add(1); let offset = (DATA_CHUNK_SIZE - (len_plus_one as usize % DATA_CHUNK_SIZE)) % DATA_CHUNK_SIZE; @@ -81,15 +189,16 @@ fn padded_len_of_pad_iec_9797_1(len: u32) -> u32 { } /// Calculates the padded len based of initial `len`. -pub fn padded_len(len: u32, chunk_size: u32) -> u32 { +#[allow(clippy::integer_arithmetic)] +pub fn padded_len(len: u32, chunk_size: NonZeroU32) -> u32 { let iec_9797_1_len = padded_len_of_pad_iec_9797_1(len); const_assert_ne!(DATA_CHUNK_SIZE, 0); debug_assert!( - chunk_size >= DATA_CHUNK_SIZE as u32, + chunk_size.get() >= DATA_CHUNK_SIZE as u32, "`BlockLength.chunk_size` is valid by design .qed" ); - let diff_per_chunk = chunk_size - DATA_CHUNK_SIZE as u32; + let diff_per_chunk = chunk_size.get() - DATA_CHUNK_SIZE as u32; let pad_to_chunk_extra = if diff_per_chunk != 0 { let chunks_count = iec_9797_1_len / DATA_CHUNK_SIZE as u32; chunks_count * diff_per_chunk @@ -100,55 +209,60 @@ pub fn padded_len(len: u32, chunk_size: u32) -> u32 { iec_9797_1_len + pad_to_chunk_extra } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct BlockDimensions { - pub rows: BlockLengthRows, - pub cols: BlockLengthColumns, - pub chunk_size: u32, + rows: BlockLengthRows, + cols: BlockLengthColumns, + chunk_size: NonZeroU32, + size: usize, } impl BlockDimensions { + pub fn new( + rows: BlockLengthRows, + cols: BlockLengthColumns, + chunk_size: NonZeroU32, + ) -> Option { + let rows_cols = rows.0.checked_mul(cols.0)?; + let size_u32 = rows_cols.checked_mul(chunk_size.get())?; + let size = usize::try_from(size_u32).ok()?; + + Some(Self { + rows, + cols, + chunk_size, + size, + }) + } + + #[inline] pub fn size(&self) -> usize { + self.size + } + + #[inline] + pub fn rows(&self) -> BlockLengthRows { self.rows - .0 - .saturating_mul(self.cols.0) - .saturating_mul(self.chunk_size) as usize } - pub fn new(rows: R, cols: C, chunk_size: u32) -> Self - where - R: Into, - C: Into, - { - Self { - rows: rows.into(), - cols: cols.into(), - chunk_size, - } + #[inline] + pub fn cols(&self) -> BlockLengthColumns { + self.cols } } -#[derive(PartialEq, Eq, Debug)] +#[derive(Error, Copy, Clone, PartialEq, Eq, Debug)] pub enum TryFromBlockDimensionsError { - InvalidRowsOrColumns(sp_std::num::TryFromIntError), + InvalidRowsOrColumns(#[from] TryFromIntError), InvalidDimensions, } -impl From for TryFromBlockDimensionsError { - fn from(error: sp_std::num::TryFromIntError) -> Self { - TryFromBlockDimensionsError::InvalidRowsOrColumns(error) - } -} - -#[cfg(feature = "std")] -impl sp_std::convert::TryInto for BlockDimensions { +impl TryInto for BlockDimensions { type Error = TryFromBlockDimensionsError; fn try_into(self) -> Result { - let rows = self.rows.0.try_into()?; - let cols = self.cols.0.try_into()?; - - Dimensions::new(rows, cols).ok_or(TryFromBlockDimensionsError::InvalidDimensions) + Dimensions::new_from(self.rows.0, self.cols.0).ok_or(Self::Error::InvalidDimensions) } } diff --git a/kate/src/metrics.rs b/kate/src/metrics.rs index b823e2be..eefd2a0f 100644 --- a/kate/src/metrics.rs +++ b/kate/src/metrics.rs @@ -1,5 +1,5 @@ use crate::BlockDimensions; -use sp_std::time::Duration; +use core::time::Duration; /// Trait for measurements during the header built process. pub trait Metrics { @@ -7,7 +7,7 @@ pub trait Metrics { fn preparation_block_time(&self, elapsed: Duration); fn commitment_build_time(&self, elapsed: Duration); fn proof_build_time(&self, elapsed: Duration, cells: u32); - fn block_dims_and_size(&self, block_dims: &BlockDimensions, block_len: u32); + fn block_dims_and_size(&self, block_dims: BlockDimensions, block_len: u32); } /// Adapter to ignore any measurements. @@ -20,5 +20,5 @@ impl Metrics for IgnoreMetrics { fn preparation_block_time(&self, _: Duration) {} fn commitment_build_time(&self, _: Duration) {} fn proof_build_time(&self, _: Duration, _: u32) {} - fn block_dims_and_size(&self, _: &BlockDimensions, _: u32) {} + fn block_dims_and_size(&self, _: BlockDimensions, _: u32) {} } diff --git a/primitives/nomad/nomad-base/Cargo.toml b/nomad/base/Cargo.toml similarity index 56% rename from primitives/nomad/nomad-base/Cargo.toml rename to nomad/base/Cargo.toml index 74e78694..65907b40 100644 --- a/primitives/nomad/nomad-base/Cargo.toml +++ b/nomad/base/Cargo.toml @@ -1,22 +1,20 @@ [package] name = "nomad-base" -version = "0.1.3" +version = "0.1.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nomad-core = { path = "../nomad-core", default-features = false } +nomad-core = { path = "../core", default-features = false } nomad-signature = { path = "../signature", default-features = false } # Substrate codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false } -primitive-types = { version = "0.12", default-features = false, features = ["scale-info", "codec"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-core = { version = "7.0.0", default-features = false } -sp-io = { version = "7.0.0", default-features = false } -sp-std = { version = "4.0.0", default-features = false } +scale-info = { version = "2", default-features = false, features = ["derive"] } +sp-core = { version = "*", default-features = false } + +sp-runtime = { version = "7", default-features = false, optional = true } # Eth ethers-signers = { version = "1", optional = true } @@ -31,12 +29,10 @@ std = [ "serde", "ethers-signers", "once_cell", - "primitive-types/serde", "codec/std", "nomad-signature/std", "scale-info/std", - "frame-support/std", "nomad-core/std", - "sp-std/std", "sp-core/std", + "sp-runtime/std", ] diff --git a/primitives/nomad/nomad-base/src/lib.rs b/nomad/base/src/lib.rs similarity index 94% rename from primitives/nomad/nomad-base/src/lib.rs rename to nomad/base/src/lib.rs index c5878520..cd98456a 100644 --- a/primitives/nomad/nomad-base/src/lib.rs +++ b/nomad/base/src/lib.rs @@ -1,16 +1,17 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::pallet_prelude::*; +use codec::{Decode, Encode, MaxEncodedLen}; use nomad_core::{home_domain_hash, to_eth_signed_message_hash, NomadState, SignedUpdate, Update}; use nomad_signature::SignatureError; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; +use scale_info::TypeInfo; use sp_core::{H160, H256}; #[cfg(feature = "std")] pub mod testing; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive(Clone, Copy, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct NomadBase { pub state: NomadState, diff --git a/primitives/nomad/nomad-base/src/testing.rs b/nomad/base/src/testing.rs similarity index 100% rename from primitives/nomad/nomad-base/src/testing.rs rename to nomad/base/src/testing.rs diff --git a/primitives/nomad/nomad-core/Cargo.toml b/nomad/core/Cargo.toml similarity index 70% rename from primitives/nomad/nomad-core/Cargo.toml rename to nomad/core/Cargo.toml index 2e719a28..b1aa67c5 100644 --- a/primitives/nomad/nomad-core/Cargo.toml +++ b/nomad/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nomad-core" -version = "0.1.3" +version = "0.1.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -10,13 +10,12 @@ nomad-signature = { path = "../signature", default-features = false } # Substrate codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false } primitive-types = { version = "0.12", default-features = false, features = ["scale-info", "codec"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-core = { version = "7.0.0", default-features = false } -sp-io = { version = "7.0.0", default-features = false } -sp-runtime = { version = "7.0.0", default-features = false } -sp-std = { version = "4.0.0", default-features = false } +scale-info = { version = "2", default-features = false, features = ["derive"] } +sp-core = { version = "*", default-features = false } +sp-std = { version = "*", default-features = false } + +sp-runtime = { version = "7", default-features = false, optional = true } # Eth ethers-core = { version = "1", optional = true } @@ -39,8 +38,8 @@ std = [ "nomad-signature/std", "codec/std", "scale-info/std", - "frame-support/std", "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [] diff --git a/primitives/nomad/nomad-core/src/lib.rs b/nomad/core/src/lib.rs similarity index 100% rename from primitives/nomad/nomad-core/src/lib.rs rename to nomad/core/src/lib.rs diff --git a/primitives/nomad/nomad-core/src/nomad_message.rs b/nomad/core/src/nomad_message.rs similarity index 87% rename from primitives/nomad/nomad-core/src/nomad_message.rs rename to nomad/core/src/nomad_message.rs index 23572259..af4915fd 100644 --- a/primitives/nomad/nomad-core/src/nomad_message.rs +++ b/nomad/core/src/nomad_message.rs @@ -1,12 +1,13 @@ -use frame_support::{pallet_prelude::*, traits::Get}; -use sp_core::H256; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::{bounded::BoundedVec, Get, H256}; use sp_std::{mem::size_of, vec::Vec}; /// Size of `NomadMessage` fields except `body`. pub const NON_BODY_LENGTH: usize = 3 * size_of::() + 2 * size_of::(); /// A full Nomad message -#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] pub struct NomadMessage> { /// 4 SLIP-44 ID pub origin: u32, @@ -53,16 +54,11 @@ impl> NomadMessage { #[cfg(test)] mod tests { - use core::convert::TryInto; - - use frame_support::{parameter_types, BoundedVec}; + use super::*; + use sp_core::ConstU32; use sp_std::mem::size_of_val; - use super::{NomadMessage, NON_BODY_LENGTH}; - - parameter_types! { - const MaxBodyLen :u32 = 1024; - } + type MaxBodyLen = ConstU32<1024>; /// Double checks that constant `NON_BODY_LENGTH` will be synchronized with actual #[test] diff --git a/primitives/nomad/nomad-core/src/state.rs b/nomad/core/src/state.rs similarity index 65% rename from primitives/nomad/nomad-core/src/state.rs rename to nomad/core/src/state.rs index 7691b781..289d4656 100644 --- a/primitives/nomad/nomad-core/src/state.rs +++ b/nomad/core/src/state.rs @@ -1,8 +1,10 @@ -use frame_support::pallet_prelude::*; +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum NomadState { /// Contract is active diff --git a/primitives/nomad/nomad-core/src/test_utils.rs b/nomad/core/src/test_utils.rs similarity index 100% rename from primitives/nomad/nomad-core/src/test_utils.rs rename to nomad/core/src/test_utils.rs diff --git a/primitives/nomad/nomad-core/src/typed_message.rs b/nomad/core/src/typed_message.rs similarity index 100% rename from primitives/nomad/nomad-core/src/typed_message.rs rename to nomad/core/src/typed_message.rs diff --git a/primitives/nomad/nomad-core/src/update.rs b/nomad/core/src/update.rs similarity index 95% rename from primitives/nomad/nomad-core/src/update.rs rename to nomad/core/src/update.rs index befe19d0..3b0a3cd5 100644 --- a/primitives/nomad/nomad-core/src/update.rs +++ b/nomad/core/src/update.rs @@ -1,8 +1,9 @@ -use frame_support::pallet_prelude::*; +use codec::{Decode, Encode}; use nomad_signature::{hash_message, Signature, SignatureError}; +use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_core::{H160, H256}; +use sp_core::{RuntimeDebug, H160, H256}; use crate::utils::home_domain_hash; diff --git a/primitives/nomad/nomad-core/src/update_v2.rs b/nomad/core/src/update_v2.rs similarity index 91% rename from primitives/nomad/nomad-core/src/update_v2.rs rename to nomad/core/src/update_v2.rs index 6c6d277f..e1cfba14 100644 --- a/primitives/nomad/nomad-core/src/update_v2.rs +++ b/nomad/core/src/update_v2.rs @@ -1,7 +1,8 @@ #![allow(dead_code)] -use frame_support::pallet_prelude::*; +use codec::{Decode, Encode}; use nomad_signature::{hash_message, Signature, SignatureError}; +use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::{H160, H256}; @@ -9,7 +10,7 @@ use sp_core::{H160, H256}; use crate::utils::home_domain_hash; /// Nomad update -#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct UpdateV2 { /// The home chain @@ -30,7 +31,7 @@ impl UpdateV2 { } /// A Signed Nomad Update -#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct SignedUpdateV2 { /// The update diff --git a/primitives/nomad/nomad-core/src/utils.rs b/nomad/core/src/utils.rs similarity index 100% rename from primitives/nomad/nomad-core/src/utils.rs rename to nomad/core/src/utils.rs diff --git a/primitives/nomad/merkle/Cargo.toml b/nomad/merkle/Cargo.toml similarity index 56% rename from primitives/nomad/merkle/Cargo.toml rename to nomad/merkle/Cargo.toml index 451e457f..87d3aba2 100644 --- a/primitives/nomad/merkle/Cargo.toml +++ b/nomad/merkle/Cargo.toml @@ -1,22 +1,24 @@ [package] name = "nomad-merkle" -version = "0.1.1" +version = "0.1.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# Internal +avail-core = { path = "../../core", default-features = false } +nomad-core = { path = "../core", default-features = false } + +# Substrate codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false } +scale-info = { version = "2", default-features = false, features = ["derive"] } +sp-core = { version = "*", default-features = false } + +frame-support = { version = "4.0.0-dev", default-features = false, optional = true } + +# 3rd-party hex-literal = "0.3.4" -nomad-core = { path = "../nomad-core", default-features = false } -# parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] } -primitive-types = { version = "0.12", default-features = false, features = ["scale-info", "codec"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-core = { version = "7.0.0", default-features = false } -sp-io = { version = "7.0.0", default-features = false } -sp-runtime = { version = "7.0.0", default-features = false } -sp-std = { version = "4.0.0-dev", default-features = false } static_assertions = "1.1.0" thiserror-no-std = "2.0.2" tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } @@ -37,8 +39,9 @@ default = ["std"] std = [ "serde", "nomad-core/std", - "primitive-types/serde", + "avail-core/std", "codec/std", "scale-info/std", + "sp-core/std", "frame-support/std", ] diff --git a/primitives/nomad/merkle/fixtures/merkle.json b/nomad/merkle/fixtures/merkle.json similarity index 100% rename from primitives/nomad/merkle/fixtures/merkle.json rename to nomad/merkle/fixtures/merkle.json diff --git a/primitives/nomad/merkle/src/error.rs b/nomad/merkle/src/error.rs similarity index 100% rename from primitives/nomad/merkle/src/error.rs rename to nomad/merkle/src/error.rs diff --git a/primitives/nomad/merkle/src/lib.rs b/nomad/merkle/src/lib.rs similarity index 99% rename from primitives/nomad/merkle/src/lib.rs rename to nomad/merkle/src/lib.rs index a9237ead..b5a288d2 100644 --- a/primitives/nomad/merkle/src/lib.rs +++ b/nomad/merkle/src/lib.rs @@ -20,7 +20,7 @@ pub mod proof; #[cfg(test)] pub(crate) mod test_utils; -use frame_support::ensure; +use avail_core::ensure; use sp_core::H256; /// Tree depth diff --git a/primitives/nomad/merkle/src/light.rs b/nomad/merkle/src/light.rs similarity index 99% rename from primitives/nomad/merkle/src/light.rs rename to nomad/merkle/src/light.rs index ef43f629..eabfd154 100644 --- a/primitives/nomad/merkle/src/light.rs +++ b/nomad/merkle/src/light.rs @@ -1,5 +1,5 @@ +use avail_core::ensure; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::ensure; use nomad_core::keccak256_concat; use scale_info::TypeInfo; #[cfg(feature = "std")] diff --git a/primitives/nomad/merkle/src/proof.rs b/nomad/merkle/src/proof.rs similarity index 100% rename from primitives/nomad/merkle/src/proof.rs rename to nomad/merkle/src/proof.rs diff --git a/primitives/nomad/merkle/src/test_utils.rs b/nomad/merkle/src/test_utils.rs similarity index 100% rename from primitives/nomad/merkle/src/test_utils.rs rename to nomad/merkle/src/test_utils.rs diff --git a/primitives/nomad/merkle/src/utils.rs b/nomad/merkle/src/utils.rs similarity index 100% rename from primitives/nomad/merkle/src/utils.rs rename to nomad/merkle/src/utils.rs diff --git a/primitives/nomad/signature/Cargo.toml b/nomad/signature/Cargo.toml similarity index 69% rename from primitives/nomad/signature/Cargo.toml rename to nomad/signature/Cargo.toml index edeb8d37..b0d51a0c 100644 --- a/primitives/nomad/signature/Cargo.toml +++ b/nomad/signature/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nomad-signature" -version = "0.1.1" +version = "0.1.2" authors = ["Luke Tchang "] edition = "2021" license = "MIT OR Apache-2.0" @@ -18,14 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate & Parity codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } +sp-core = { version = "*", default-features = false } + frame-support = { version = "4.0.0-dev", default-features = false } -primitive-types = { version = "0.12", default-features = false, features = ["scale-info", "codec"] } -rlp = { version = "0.5.0", default-features = false } -rlp-derive = { version = "0.1.0", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-core = { version = "7.0.0", default-features = false } -sp-io = { version = "7.0.0", default-features = false } -sp-std = { version = "4.0.0", default-features = false } +sp-runtime = { version = "7", default-features = false } # Eth ethers-core = { version = "1", default-features = false, optional = true } @@ -37,7 +34,7 @@ hex = { version = "0.4.3", default-features = false } k256 = { version = "0.11.5", default-features = false, features = ["keccak256", "ecdsa"] } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } thiserror-no-std = "2.0.2" -tiny-keccak = { version = "2.0.2", default-features = false } +tiny-keccak = { version = "2.0.2", default-features = false, features = ["keccak"] } [dev-dependencies] byte-slice-cast = "1.2.1" @@ -47,9 +44,10 @@ default = ["std"] std = [ "serde", "hex/std", - "primitive-types/serde", - "codec/std", "scale-info/std", + "codec/std", + "sp-core/std", + "sp-runtime/std", "frame-support/std", "ethers-core", ] diff --git a/primitives/nomad/signature/README.md b/nomad/signature/README.md similarity index 100% rename from primitives/nomad/signature/README.md rename to nomad/signature/README.md diff --git a/primitives/nomad/signature/src/lib.rs b/nomad/signature/src/lib.rs similarity index 100% rename from primitives/nomad/signature/src/lib.rs rename to nomad/signature/src/lib.rs diff --git a/primitives/nomad/signature/src/signature.rs b/nomad/signature/src/signature.rs similarity index 96% rename from primitives/nomad/signature/src/signature.rs rename to nomad/signature/src/signature.rs index 9969fac1..6c87b074 100644 --- a/primitives/nomad/signature/src/signature.rs +++ b/nomad/signature/src/signature.rs @@ -1,10 +1,11 @@ // Code adapted from: https://github.com/gakonst/ethers-rs/blob/master/ethers-core/src/types/signature.rs +use crate::utils::hash_message; use alloc::{borrow::ToOwned, string::String, vec::Vec}; -use core::{convert::TryFrom, fmt, str::FromStr}; - +use codec::{Decode, Encode}; +use core::convert::TryFrom; use elliptic_curve::{consts::U32, sec1::ToEncodedPoint as _}; -use frame_support::{pallet_prelude::*, sp_runtime::traits::Keccak256}; +use frame_support::ensure; use generic_array::GenericArray; use k256::{ ecdsa::{ @@ -13,12 +14,15 @@ use k256::{ }, PublicKey as K256PublicKey, }; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use sp_core::{Hasher, H160, H256, U256}; +use scale_info::TypeInfo; +use sp_core::{Hasher as _, H160, H256, U256}; +use sp_runtime::{traits::Keccak256, RuntimeDebug}; use thiserror_no_std::Error; -use crate::utils::hash_message; +#[cfg(feature = "std")] +use core::{fmt, str::FromStr}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; type Address = H160; @@ -68,6 +72,7 @@ pub struct Signature { pub v: u64, } +#[cfg(feature = "std")] impl fmt::Display for Signature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let sig = <[u8; 65]>::from(self); @@ -189,6 +194,7 @@ impl<'a> TryFrom<&'a [u8]> for Signature { } } +#[cfg(feature = "std")] impl FromStr for Signature { type Err = SignatureError; diff --git a/primitives/nomad/signature/src/utils.rs b/nomad/signature/src/utils.rs similarity index 100% rename from primitives/nomad/signature/src/utils.rs rename to nomad/signature/src/utils.rs diff --git a/primitives/avail/Cargo.toml b/primitives/avail/Cargo.toml deleted file mode 100644 index 7ead9e70..00000000 --- a/primitives/avail/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -[package] -name = "da-primitives" -version = "0.4.6" -authors = [] -edition = "2021" - -[dependencies] -# Others -derive_more = "0.99.17" -log = { version = "0.4.8", default-features = false } -serde = { version = "1.0.121", optional = true, features = ["derive"] } -serde_json = { version = "1.0", optional = true } -thiserror-no-std = "2.0.2" - -# Substrate -beefy-merkle-tree = { git = "https://github.com/paritytech/substrate.git/", branch = "polkadot-v0.9.37", default-features = false } -codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false } -hash256-std-hasher = { version = "0.15.2", default-features = false } -parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -sp-core = { version = "7.0.0", default-features = false } -sp-io = { version = "7.0.0", default-features = false } -sp-runtime = { version = "7.0.0", default-features = false } -sp-runtime-interface = { version = "7.0.0", default-features = false } -sp-std = { version = "4.0.0", default-features = false } -sp-trie = { version = "7.0.0", default-features = false } - -[dev-dependencies] -hex-literal = "0.3.4" -test-case = "1.2.3" - -[features] -default = ["std"] -std = [ - "serde", - "serde_json", - "codec/std", - "scale-info/std", - "log/std", - "sp-core/std", - "sp-std/std", - "sp-io/std", - "sp-runtime/std", - "sp-trie/std", - "sp-runtime-interface/std", - "hash256-std-hasher/std", - "frame-support/std", - "parity-util-mem/std", - "beefy-merkle-tree/std", -] - -header-backward-compatibility-test = [] -try-runtime = [ - "sp-runtime/try-runtime", -] diff --git a/primitives/avail/src/asdr/data_lookup.rs b/primitives/avail/src/asdr/data_lookup.rs deleted file mode 100644 index 64f4181b..00000000 --- a/primitives/avail/src/asdr/data_lookup.rs +++ /dev/null @@ -1,145 +0,0 @@ -use codec::{Decode, Encode}; -use frame_support::ensure; -#[cfg(feature = "std")] -use parity_util_mem::{MallocSizeOf, MallocSizeOfOps}; -use scale_info::TypeInfo; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use sp_core::RuntimeDebug; -use sp_runtime::traits::Zero; -use sp_std::{convert::TryFrom, vec::Vec}; - -use crate::asdr::AppId; - -#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, Default, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct DataLookup { - /// size of the look up - #[codec(compact)] - pub size: u32, - /// sorted vector of tuples(key, start index) - pub index: Vec, -} - -#[derive(PartialEq, Eq, Copy, Clone, RuntimeDebug, Encode, Decode, Default, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct DataLookupIndexItem { - pub app_id: AppId, - #[codec(compact)] - pub start: u32, -} - -impl From<(A, S)> for DataLookupIndexItem -where - A: Into, - S: Into, -{ - fn from(value: (A, S)) -> Self { - Self { - app_id: value.0.into(), - start: value.1.into(), - } - } -} - -#[cfg(feature = "std")] -impl MallocSizeOf for DataLookupIndexItem { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.app_id.size_of(ops) + self.start.size_of(ops) - } -} - -#[derive(PartialEq, Eq, RuntimeDebug)] -/// Errors during the creation from `extrinsics`. -pub enum TryFromError { - /// Size overflows - SizeOverflow, - /// Extrinsics are not sorted. - UnsortedExtrinsics, -} - -impl TryFrom<&[(AppId, u32)]> for DataLookup { - type Error = TryFromError; - - fn try_from(extrinsics: &[(AppId, u32)]) -> Result { - let mut index = Vec::new(); - // transactions are order by application id - // skip transactions with 0 application id - it's not a data txs - let mut size = 0u32; - let mut prev_app_id = Zero::zero(); - - for (app_id, data_len) in extrinsics { - if !app_id.is_zero() && prev_app_id != *app_id { - index.push(DataLookupIndexItem { - app_id: *app_id, - start: size, - }); - } - - size = size - .checked_add(*data_len) - .ok_or(Self::Error::SizeOverflow)?; - ensure!(prev_app_id <= *app_id, Self::Error::UnsortedExtrinsics); - prev_app_id = *app_id; - } - - Ok(DataLookup { size, index }) - } -} - -#[cfg(feature = "std")] -impl MallocSizeOf for DataLookup { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.size.size_of(ops) + self.index.size_of(ops) - } -} - -#[cfg(test)] -mod test { - use super::*; - - fn into_app_ids(vals: I) -> Vec<(AppId, u32)> - where - I: IntoIterator, - T: Into, - { - vals.into_iter() - .map(|(id, idx)| (id.into(), idx)) - .collect::>() - } - fn into_lookup_items(vals: I) -> Vec - where - I: IntoIterator, - T: Into, - { - vals.into_iter().map(Into::into).collect::>() - } - - fn from_extrinsics_data() -> Vec<(Vec<(AppId, u32)>, Result)> { - vec![ - ( - into_app_ids([(0, 5), (0, 10), (1, 5), (1, 10), (2, 100), (2, 50)]), - Ok(DataLookup { - size: 180, - index: into_lookup_items([(1, 15), (2, 30)]), - }), - ), - ( - into_app_ids([(0, 5), (0, 10), (1, u32::MAX)]), - Err(TryFromError::SizeOverflow), - ), - ( - into_app_ids([(0, 5), (0, 10), (1, 5), (2, 100), (1, 10), (2, 50)]), - Err(TryFromError::UnsortedExtrinsics), - ), - ] - } - - #[test] - fn from_extrinsics() { - for (extrinsic, expected) in from_extrinsics_data() { - let data_lookup = DataLookup::try_from(extrinsic.as_slice()); - assert_eq!(data_lookup, expected); - } - } -} diff --git a/primitives/avail/src/keccak256.rs b/primitives/avail/src/keccak256.rs deleted file mode 100644 index d246e625..00000000 --- a/primitives/avail/src/keccak256.rs +++ /dev/null @@ -1,41 +0,0 @@ -use frame_support::RuntimeDebug; -use scale_info::TypeInfo; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use sp_core::{storage::StateVersion, Hasher}; -use sp_runtime::traits::Hash; -use sp_std::vec::Vec; -use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration as _}; - -/// Keccak 256 wrapper which supports `beefy-merkle-tree::Hasher`. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct Keccak256 {} - -impl Hasher for Keccak256 { - type Out = sp_core::H256; - type StdHasher = hash256_std_hasher::Hash256StdHasher; - const LENGTH: usize = 32; - - fn hash(s: &[u8]) -> Self::Out { - sp_io::hashing::keccak_256(s).into() - } -} - -impl Hash for Keccak256 { - type Output = sp_core::H256; - - fn trie_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> Self::Output { - match version { - StateVersion::V0 => LayoutV0::::trie_root(input), - StateVersion::V1 => LayoutV1::::trie_root(input), - } - } - - fn ordered_trie_root(input: Vec>, version: StateVersion) -> Self::Output { - match version { - StateVersion::V0 => LayoutV0::::ordered_trie_root(input), - StateVersion::V1 => LayoutV1::::ordered_trie_root(input), - } - } -} diff --git a/primitives/avail/src/lib.rs b/primitives/avail/src/lib.rs deleted file mode 100644 index c85951ba..00000000 --- a/primitives/avail/src/lib.rs +++ /dev/null @@ -1,150 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -use codec::{Decode, Encode, MaxEncodedLen}; -use derive_more::{Add, Constructor, Display, From, Into, Mul}; -use scale_info::TypeInfo; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use sp_runtime::Perbill; - -pub mod opaque_extrinsic; -pub use opaque_extrinsic::*; - -/// Customized headers. -pub mod header; -pub use header::*; - -/// Kate Commitment on Headers. -pub mod kate_commitment; -pub use kate_commitment::*; - -/// Application Specific Data Retrieval -pub mod asdr; - -pub mod keccak256; -pub mod traits; -pub use keccak256::Keccak256; - -pub mod data_proof; - -pub use data_proof::DataProof; - -pub mod well_known_keys { - /// Public params used to generate Kate commitment - pub const KATE_PUBLIC_PARAMS: &[u8] = b":kate_public_params:"; -} - -/// We allow `Normal` extrinsics to fill up the block up to 90%, the rest can be used -/// by Operational extrinsics. -pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(90); - -pub const BLOCK_CHUNK_SIZE: u32 = 32; - -/// Money matters. -pub mod currency { - - pub type Balance = u128; - - /// AVL has 18 decimal positions. - pub const AVL: Balance = 1_000_000_000_000_000_000; - - /// Cents of AVL has 16 decimal positions (100 Cents = $1) - /// 1 DOLLARS = 10_000_000_000_000_000 - pub const CENTS: Balance = AVL / 100; - - /// Millicent of AVL has 13 decimal positions( 100 mCents = 1 cent). - pub const MILLICENTS: Balance = CENTS / 1_000; -} - -#[repr(u8)] -pub enum InvalidTransactionCustomId { - /// The AppId is not registered. - InvalidAppId = 137, - /// Extrinsic is not allowed for the given `AppId`. - ForbiddenAppId, - /// Max padded length was exceeded. - MaxPaddedLenExceeded, - /// Max recursion was reached for a call with AppId != 0. - MaxRecursionExceeded, -} - -/// Provides an implementation of [`frame_support::traits::Randomness`] that should only be used in -/// on Benchmarks! -pub struct BenchRandomness(sp_std::marker::PhantomData); - -impl frame_support::traits::Randomness for BenchRandomness -where - Output: codec::Decode + Default, - T: Default, -{ - fn random(subject: &[u8]) -> (Output, T) { - use sp_runtime::traits::TrailingZeroInput; - - ( - Output::decode(&mut TrailingZeroInput::new(subject)).unwrap_or_default(), - T::default(), - ) - } -} - -/// Strong type for `BlockLength::cols` -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive( - Clone, - Copy, - Debug, - From, - Into, - Add, - Mul, - Display, - PartialEq, - Eq, - Encode, - Decode, - TypeInfo, - PartialOrd, - Ord, - Constructor, - MaxEncodedLen, -)] -#[mul(forward)] -pub struct BlockLengthColumns(#[codec(compact)] pub u32); - -impl BlockLengthColumns { - #[inline] - pub fn as_usize(&self) -> usize { - self.0 as usize - } -} - -/// Strong type for `BlockLength::rows` -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive( - Clone, - Copy, - Debug, - From, - Into, - Add, - Mul, - Display, - PartialEq, - Eq, - Encode, - Decode, - TypeInfo, - PartialOrd, - Ord, - Constructor, - MaxEncodedLen, -)] -#[mul(forward)] -pub struct BlockLengthRows(#[codec(compact)] pub u32); - -impl BlockLengthRows { - #[inline] - pub fn as_usize(&self) -> usize { - self.0 as usize - } -} diff --git a/primitives/avail/src/traits.rs b/primitives/avail/src/traits.rs deleted file mode 100644 index 5b951267..00000000 --- a/primitives/avail/src/traits.rs +++ /dev/null @@ -1,76 +0,0 @@ -use codec::{Codec, Decode}; -use sp_core::U256; -use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, Hash as HashT, MaybeDisplay, MaybeFromStr, MaybeSerializeDeserialize, - Member, SimpleBitOps, - }, - Digest, -}; -use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash as StdHash}; - -use crate::header::HeaderExtension; - -/// Header block number trait. -pub trait HeaderBlockNumber: - Member - + AtLeast32BitUnsigned - + Codec - + MaybeSerializeDeserialize - + MaybeDisplay - + MaybeFromStr - + MaybeFromStr - + StdHash - + Copy - + Into - + TryFrom - + Debug - + Eq -{ -} -impl< - T: Member - + AtLeast32BitUnsigned - + Codec - + MaybeSerializeDeserialize - + MaybeDisplay - + MaybeFromStr - + StdHash - + Copy - + Into - + TryFrom - + Debug - + Eq, - > HeaderBlockNumber for T -{ -} - -/// Header hash. -pub trait HeaderHash: HashT {} -impl HeaderHash for T {} - -pub trait HeaderHashOutput: MaybeDisplay + Decode + SimpleBitOps + Ord {} -impl HeaderHashOutput for T {} - -/// Extended header access -pub trait ExtendedHeader { - /// Header number. - type Number; - - /// Header hash type - type Hash; - - /// Creates new header. - fn new( - number: Self::Number, - extrinsics_root: Self::Hash, - state_root: Self::Hash, - parent_hash: Self::Hash, - digest: Digest, - extension: HeaderExtension, - ) -> Self; - - fn extension(&self) -> &HeaderExtension; - - fn set_extension(&mut self, extension: HeaderExtension); -}