diff --git a/.github/actions/label/build.js b/.github/actions/label/build.js index 8866bcf4e09..c4e80416e39 100644 --- a/.github/actions/label/build.js +++ b/.github/actions/label/build.js @@ -3,7 +3,7 @@ */ const [owner, repo] = ["gear-tech", "gear"]; -const { LABEL, REF, HEAD_SHA, TITLE, NUMBER } = process.env; +const { LABEL, REF, HEAD_SHA, TITLE, NUMBER, IS_FORK, REF_NAME } = process.env; const linux = LABEL === "A0-pleasereview" || LABEL === "A4-insubstantial" || @@ -20,8 +20,12 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); /** * If skipping this action. + * + * @returns {Promise<[boolean, string]>} [skip, String(check_runs)] **/ -const skip = async ({ core, github }) => { +const skip = async ({ github }) => { + if (!IS_FORK && REF_NAME.startsWith("dependabot")) return [true, ""] + const { data: { check_runs }, } = await github.rest.checks.listForRef({ @@ -142,7 +146,8 @@ const listJobs = async ({ github, core, run_id }) => { * The main function. **/ module.exports = async ({ github, core }) => { - const [skipAction, check_runs] = await skip({ core, github }); + const [skipAction, check_runs] = await skip({ github }); + if (skipAction) { core.info("Build has already been processed, check runs: " + check_runs); return; diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index cc3db9588b5..26b294de771 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -74,8 +74,10 @@ jobs: if: >- needs.status.outputs.skip-ci != '1' && ( - contains(github.event.pull_request.title, '[depbot]') - || ( + ( + github.event.pull_request.head.repo.full_name == 'gear-tech/gear' + && contains(github.event.pull_request.title, '[depbot]') + ) || ( contains(github.event.pull_request.labels.*.name, 'A0-pleasereview') || contains(github.event.pull_request.labels.*.name, 'A4-insubstantial') || contains(github.event.pull_request.labels.*.name, 'A2-mergeoncegreen') diff --git a/.github/workflows/crates-io.yml b/.github/workflows/crates-io.yml index 8d03d121436..eb7c0fd1b0f 100644 --- a/.github/workflows/crates-io.yml +++ b/.github/workflows/crates-io.yml @@ -2,6 +2,16 @@ name: Crates IO on: workflow_dispatch: + inputs: + publish: + description: "If publish packages" + type: boolean + default: false + version: + description: "Workspace version to publish" + type: string + pull_request: + branches: [master] env: CARGO_INCREMENTAL: 0 @@ -10,7 +20,7 @@ env: TERM: xterm-256color jobs: - publish: + check: runs-on: ubuntu-latest env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} @@ -21,5 +31,9 @@ jobs: - name: "Install: Rust toolchain" uses: dsherret/rust-toolchain-file@v1 + - name: "Check packages" + run: cargo run --release -p crates-io check + - name: "Publish packages" - run: cargo run --release -p crates-io-manager + if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }} + run: cargo run --release -p crates-io publish -v ${{ inputs.version }} diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index ae81d5e140f..1952652fcb1 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -22,8 +22,10 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha }} LABEL: ${{ github.event.label.name }} REF: ${{ github.head_ref || github.ref_name }} + REF_NAME: ${{ github.ref_name }} TITLE: ${{ github.event.pull_request.title }} NUMBER: ${{ github.event.number }} + IS_FORK: ${{ github.event.pull_request.head.repo.full_name != 'gear-tech/gear' }} with: script: | const script = require('./.github/actions/label/build.js'); diff --git a/Cargo.lock b/Cargo.lock index 3ad4570cb54..46a0c85a84a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,14 +167,15 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom 0.2.10", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -509,7 +510,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -526,7 +527,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1039,16 +1040,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cargo_toml" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" -dependencies = [ - "serde", - "toml 0.7.8", -] - [[package]] name = "cc" version = "1.0.83" @@ -1210,9 +1201,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.10" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive 4.4.7", @@ -1220,9 +1211,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.9" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -1252,7 +1243,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1324,11 +1315,10 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", "windows-sys 0.48.0", ] @@ -1612,28 +1602,14 @@ dependencies = [ [[package]] name = "crates-io" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876aa69b4afca5f2eb5e23daa3445930faf829bcb67075a20ffa884f11f8c57c" -dependencies = [ - "anyhow", - "curl", - "percent-encoding", - "serde", - "serde_json", - "url", -] - -[[package]] -name = "crates-io-manager" version = "1.0.3" dependencies = [ "anyhow", - "cargo_metadata 0.15.3", - "cargo_toml", - "crates-io", - "curl", - "toml 0.7.8", + "cargo_metadata 0.18.1", + "clap 4.4.11", + "reqwest", + "serde", + "toml_edit 0.21.0", ] [[package]] @@ -1780,36 +1756,6 @@ dependencies = [ "cipher 0.4.4", ] -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.4.9", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.68+curl-8.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a0d18d88360e374b16b2273c832b5e57258ffc1d4aa4f96b108e0738d5752f" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.48.0", -] - [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -1861,7 +1807,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1901,7 +1847,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1918,7 +1864,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1966,7 +1912,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1988,7 +1934,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2181,7 +2127,7 @@ dependencies = [ "gear-wasm-builder", "gmeta", "gstd", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "rand 0.8.5", "statrs", "tokio", @@ -2463,14 +2409,6 @@ dependencies = [ "wasm-dep-builder", ] -[[package]] -name = "demo-signal-wait" -version = "0.1.0" -dependencies = [ - "gstd", - "wasm-dep-builder", -] - [[package]] name = "demo-stack-allocations" version = "0.1.0" @@ -2663,7 +2601,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2830,7 +2768,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2839,18 +2777,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" -[[package]] -name = "dlmalloc" -version = "0.1.4" -source = "git+https://github.com/gear-tech/dlmalloc-rust.git#15352f969112faa463302f2490bbb7f6e1cb904d" -dependencies = [ - "libc", - "libc-print", - "page_size", - "static_assertions", - "str-buf", -] - [[package]] name = "document-features" version = "0.2.7" @@ -3096,7 +3022,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3137,7 +3063,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3158,7 +3084,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3391,6 +3317,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "fork-tree" version = "3.0.0" @@ -3447,7 +3388,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.4.10", + "clap 4.4.11", "comfy-table", "frame-benchmarking", "frame-support", @@ -3852,7 +3793,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3915,7 +3856,7 @@ dependencies = [ name = "galloc" version = "1.0.3" dependencies = [ - "dlmalloc", + "gear-dlmalloc", ] [[package]] @@ -3923,8 +3864,9 @@ name = "gcli" version = "1.0.3" dependencies = [ "anyhow", + "async-trait", "base64 0.21.5", - "clap 4.4.10", + "clap 4.4.11", "color-eyre", "demo-messager", "demo-new-meta", @@ -3932,6 +3874,7 @@ dependencies = [ "dirs", "env_logger", "etc", + "futures", "gear-core", "gear-core-errors", "gmeta", @@ -4061,7 +4004,7 @@ dependencies = [ name = "gear-bags-thresholds" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "generate-bags", "vara-runtime", ] @@ -4085,7 +4028,7 @@ dependencies = [ name = "gear-cli" version = "1.0.3" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -4143,7 +4086,7 @@ name = "gear-common-codegen" version = "1.0.3" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4158,7 +4101,7 @@ dependencies = [ "gear-core-errors", "gear-wasm-instrument", "gsys", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "hex", "log", "num-traits", @@ -4219,6 +4162,19 @@ dependencies = [ "scale-info", ] +[[package]] +name = "gear-dlmalloc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5c1d3d820d57acd0c4129b3551f5fe5b01e61c8cb2863bad2b183a4b32dc978" +dependencies = [ + "libc", + "libc-print", + "page_size", + "static_assertions", + "str-buf", +] + [[package]] name = "gear-key-finder" version = "1.0.3" @@ -4274,7 +4230,7 @@ name = "gear-node-loader" version = "1.0.3" dependencies = [ "anyhow", - "clap 4.4.10", + "clap 4.4.11", "futures", "futures-timer", "gclient", @@ -4336,11 +4292,22 @@ dependencies = [ "vara-runtime", ] +[[package]] +name = "gear-pwasm-utils" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea09901ce41f64d1be7369b8c2efc774e89b200ac434496ab24e6af96e68f97" +dependencies = [ + "byteorder", + "gear-wasm", + "log", +] + [[package]] name = "gear-replay-cli" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-remote-externalities", "frame-system", "gear-runtime-interface", @@ -4554,7 +4521,7 @@ dependencies = [ name = "gear-validator-checks" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "env_logger", "futures", "gsdk", @@ -4574,20 +4541,20 @@ checksum = "bbfbfa701dc65e683fcd2fb24f046bcef22634acbdf47ad14724637dc39ad05b" [[package]] name = "gear-wasm-builder" -version = "0.1.2" +version = "1.0.3" dependencies = [ "anyhow", - "cargo_metadata 0.15.3", + "cargo_metadata 0.18.1", "chrono", "colored", "dirs", "gear-core", + "gear-pwasm-utils", "gear-wasm-instrument", "gmeta", "log", "once_cell", "pathdiff", - "pwasm-utils", "regex", "thiserror", "toml 0.7.8", @@ -4637,7 +4604,7 @@ dependencies = [ name = "gear-weight-diff" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-support", "indexmap 2.1.0", "pallet-gear", @@ -4811,7 +4778,7 @@ dependencies = [ "proc-macro2", "quote", "scale-info", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4831,6 +4798,7 @@ version = "1.0.3" dependencies = [ "anyhow", "base64 0.21.5", + "colored", "demo-messager", "demo-new-meta", "demo-waiter", @@ -4875,7 +4843,7 @@ dependencies = [ "sp-io", "subxt-codegen", "subxt-metadata", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4884,7 +4852,7 @@ version = "1.0.3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4898,7 +4866,7 @@ dependencies = [ "gcore", "gear-core-errors", "gstd-codegen", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "hex", "parity-scale-codec", "primitive-types", @@ -4908,12 +4876,12 @@ dependencies = [ [[package]] name = "gstd-codegen" -version = "0.1.0" +version = "1.0.3" dependencies = [ "gstd", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "trybuild", ] @@ -5029,16 +4997,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", ] [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "allocator-api2", "serde", ] @@ -5257,6 +5225,19 @@ dependencies = [ "webpki-roots 0.23.1", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -5389,7 +5370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "serde", ] @@ -5868,9 +5849,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libc-print" @@ -7009,6 +6990,24 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nb-connect" version = "1.2.0" @@ -7287,7 +7286,7 @@ checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -7362,9 +7361,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -7378,6 +7377,32 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -7386,9 +7411,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.95" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", @@ -7672,7 +7697,6 @@ dependencies = [ "demo-rwlock", "demo-send-from-reservation", "demo-signal-entry", - "demo-signal-wait", "demo-state-rollback", "demo-sync-duplicate", "demo-wait", @@ -7805,7 +7829,7 @@ dependencies = [ "pallet-gear-scheduler", "pallet-timestamp", "parity-scale-codec", - "parity-wasm 0.45.0", + "parity-wasm", "primitive-types", "scale-info", "serde", @@ -7863,7 +7887,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "parity-scale-codec", - "parity-wasm 0.45.0", + "parity-wasm", "primitive-types", "scale-info", "serde", @@ -7879,7 +7903,7 @@ version = "1.0.3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -7890,7 +7914,7 @@ dependencies = [ "frame-system", "gear-common", "gear-core", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "log", "pallet-authorship", "pallet-balances", @@ -8033,7 +8057,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parity-wasm 0.45.0", + "parity-wasm", "primitive-types", "scale-info", "serde", @@ -8514,12 +8538,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -[[package]] -name = "parity-wasm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" - [[package]] name = "parity-wasm" version = "0.45.0" @@ -8684,7 +8702,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -8725,7 +8743,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -9126,17 +9144,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "pwasm-utils" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ecdabd73c8beaf98c66e45aff3032b56260ee49eb5d0d1222ecce269bfafda7" -dependencies = [ - "byteorder", - "log", - "parity-wasm 0.42.2", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -9411,7 +9418,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -9503,7 +9510,7 @@ dependencies = [ name = "regression-analysis" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-support", "junit-common", "pallet-gear", @@ -9540,10 +9547,12 @@ dependencies = [ "http-body", "hyper", "hyper-rustls 0.24.1", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite 0.2.13", @@ -9554,6 +9563,7 @@ dependencies = [ "serde_urlencoded", "system-configuration", "tokio", + "tokio-native-tls", "tokio-rustls 0.24.1", "tower-service", "url", @@ -9705,7 +9715,7 @@ version = "0.1.0" dependencies = [ "anyhow", "arbitrary", - "clap 4.4.10", + "clap 4.4.11", "frame-support", "frame-system", "gear-call-gen", @@ -10018,7 +10028,7 @@ source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0 dependencies = [ "array-bytes", "chrono", - "clap 4.4.10", + "clap 4.4.11", "fdlimit", "futures", "libp2p", @@ -10207,7 +10217,7 @@ name = "sc-consensus-grandpa" version = "0.10.0-dev" source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox-revert-oom-changes#27779e0eaaa2161ba165ff8f0b0ff103bb63e5a1" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "array-bytes", "async-trait", "dyn-clone", @@ -10481,7 +10491,7 @@ name = "sc-network-gossip" version = "0.10.0-dev" source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox-revert-oom-changes#27779e0eaaa2161ba165ff8f0b0ff103bb63e5a1" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "futures", "futures-timer", "libp2p", @@ -10796,7 +10806,7 @@ name = "sc-storage-monitor" version = "0.1.0" source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox-revert-oom-changes#27779e0eaaa2161ba165ff8f0b0ff103bb63e5a1" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "fs4 0.6.6", "futures", "log", @@ -11090,7 +11100,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "cfg-if", "hashbrown 0.13.2", ] @@ -11319,7 +11329,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -11341,7 +11351,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -11593,7 +11603,7 @@ dependencies = [ "fnv", "futures-channel", "futures-util", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "hex", "hmac 0.12.1", "itertools", @@ -11638,7 +11648,7 @@ dependencies = [ "fnv", "futures-channel", "futures-util", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "hex", "itertools", "log", @@ -12339,7 +12349,7 @@ name = "sp-trie" version = "7.0.0" source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox-revert-oom-changes#27779e0eaaa2161ba165ff8f0b0ff103bb63e5a1" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "hash-db", "hashbrown 0.12.3", "lazy_static", @@ -12364,7 +12374,7 @@ source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0 dependencies = [ "impl-serde", "parity-scale-codec", - "parity-wasm 0.45.0", + "parity-wasm", "scale-info", "serde", "sp-core-hashing-proc-macro", @@ -12774,7 +12784,7 @@ dependencies = [ "quote", "scale-info", "subxt-metadata", - "syn 2.0.39", + "syn 2.0.40", "thiserror", "tokio", ] @@ -12805,7 +12815,7 @@ dependencies = [ "darling 0.20.3", "proc-macro-error", "subxt-codegen", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -12834,9 +12844,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" dependencies = [ "proc-macro2", "quote", @@ -13001,7 +13011,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -13122,9 +13132,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -13147,7 +13157,17 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", ] [[package]] @@ -13216,14 +13236,14 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -13241,6 +13261,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -13318,7 +13349,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -13507,7 +13538,7 @@ version = "0.10.0-dev" source = "git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox-revert-oom-changes#27779e0eaaa2161ba165ff8f0b0ff103bb63e5a1" dependencies = [ "async-trait", - "clap 4.4.10", + "clap 4.4.11", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -13929,7 +13960,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-shared", ] @@ -13963,7 +13994,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -13995,9 +14026,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b09bc5df933a3dabbdb72ae4b6b71be8ae07f58774d5aa41bd20adcd41a235a" +checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f" dependencies = [ "leb128", ] @@ -14006,9 +14037,9 @@ dependencies = [ name = "wasm-info" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "hex", - "parity-wasm 0.45.0", + "parity-wasm", ] [[package]] @@ -14016,7 +14047,7 @@ name = "wasm-instrument" version = "0.3.0" source = "git+https://github.com/gear-tech/wasm-instrument?branch=v0.3.0-sign-ext#7d5226a805b39ed297e78427c21ee2cb39795139" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", ] [[package]] @@ -14064,11 +14095,11 @@ dependencies = [ name = "wasm-proc" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "env_logger", "gear-wasm-builder", "log", - "parity-wasm 0.45.0", + "parity-wasm", ] [[package]] @@ -14367,7 +14398,7 @@ name = "wasmi" version = "0.13.2" source = "git+https://github.com/gear-tech/wasmi?branch=v0.13.2-sign-ext#3a0b1022377919e62aadf4d78b762abd1c3e9a04" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", "wasmi-validation", "wasmi_core 0.2.1 (git+https://github.com/gear-tech/wasmi?branch=v0.13.2-sign-ext)", ] @@ -14415,7 +14446,7 @@ name = "wasmi-validation" version = "0.5.0" source = "git+https://github.com/gear-tech/wasmi?branch=v0.13.2-sign-ext#3a0b1022377919e62aadf4d78b762abd1c3e9a04" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", ] [[package]] @@ -14506,9 +14537,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.118.0" +version = "0.118.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbb91574de0011ded32b14db12777e7dd5e9ea2f9d7317a1ab51a9495c75924" +checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" dependencies = [ "indexmap 2.1.0", "semver 1.0.18", @@ -14531,12 +14562,12 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.2.74" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a7a046e6636d25c06a5df00bdc34e02f9e6e0e8a356d738299b961a6126114" +checksum = "3d027eb8294904fc715ac0870cebe6b0271e96b90605ee21511e7565c4ce568c" dependencies = [ "anyhow", - "wasmparser 0.118.0", + "wasmparser 0.118.1", ] [[package]] @@ -14720,21 +14751,21 @@ dependencies = [ [[package]] name = "wast" -version = "69.0.0" +version = "69.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa51b5ad1391943d1bfad537e50f28fe938199ee76b115be6bae83802cd5185" +checksum = "c1ee37317321afde358e4d7593745942c48d6d17e0e6e943704de9bbee121e7a" dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder 0.38.0", + "wasm-encoder 0.38.1", ] [[package]] name = "wat" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a4c2488d058326466e086a43f5d4ea448241a8d0975e3eb0642c0828be1eb3" +checksum = "aeb338ee8dee4d4cd05e6426683f21c5087dc7cfc8903e839ccf48d43332da3c" dependencies = [ "wast", ] @@ -15536,6 +15567,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "zerocopy" +version = "0.7.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d6f15f7ade05d2a4935e34a457b936c23dc70a05cc1d97133dc99e7a3fe0f0e" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbbad221e3f78500350ecbd7dfa4e63ef945c05f4c61cb7f4d3f84cd0bba649b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "zeroize" version = "1.6.0" @@ -15553,7 +15604,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5ecb840767d..24c32e760d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,6 @@ members = [ "examples/rwlock", "examples/send-from-reservation", "examples/signal-entry", - "examples/signal-wait", "examples/state-rollback", "examples/sync-duplicate", "examples/syscalls", @@ -102,16 +101,14 @@ base64 = "0.21.5" byteorder = { version = "1.5.0", default-features = false } blake2-rfc = { version = "0.2.18", default-features = false } bs58 = { version = "0.5.0", default-features = false } -# TODO: upgrade this package ( issue #2694 ) -cargo_metadata = "=0.15.3" -clap = { version = "4.4.10" } +cargo_metadata = "0.18.1" +clap = "4.4.11" codec = { package = "parity-scale-codec", version = "3.6.4", default-features = false } color-eyre = "0.6.2" -colored = "2.0.0" +colored = "2.1.0" const-str = "0.5" derive_more = "0.99.17" dirs = "4.0.0" -dlmalloc = { git = "https://github.com/gear-tech/dlmalloc-rust.git" } dyn-clonable = "0.9.0" enum-iterator = "1.4.0" env_logger = "0.10" @@ -119,7 +116,7 @@ environmental = "1.1.3" futures = { version = "0.3", default-features = false } futures-timer = "3.0.2" futures-util = "0.3.29" -hashbrown = "0.14.2" +hashbrown = "0.14.3" hex = { version = "0.4.3", default-features = false } hex-literal = "0.4.1" jsonrpsee = { version = "^0.16" } @@ -127,7 +124,7 @@ lazy_static = "1.4.0" libc = { version = "0.2", default-features = false } log = { version = "0.4.20", default-features = false } num_enum = { version = "0.6.1", default-features = false } -once_cell = "1.17.1" +once_cell = "1.19.0" parity-scale-codec = { version = "3.6.4", default-features = false } parity-wasm = "0.45.0" parking_lot = "0.12.1" @@ -148,27 +145,14 @@ serde_json = "^1" serde_yaml = "0.8.26" sha-1 = "0.10.1" static_assertions = "1" -# # NOTE -# -# 1. subxt v0.29.0 breaks the logging in gsdk, our fork is based on the -# unpublished v0.29.0 from the main repo with fixes. -# -# 2. subxt v0.29.0 upgrades the substrate dependencies which are not -# compatible with our current dependencies. -# -# 3. changing but patching the source here for making these work out of -# workspace. -# -# 4. subxt-metadata and subxt-codegen are just used by gsdk-codegen for now -# gathering them here for easy management. -subxt = { version = "0.32.1" } -subxt-metadata = { version = "0.32.1" } -subxt-codegen = { version = "0.32.1" } -syn = "2.0.39" +subxt = "0.32.1" +subxt-metadata = "0.32.1" +subxt-codegen = "0.32.1" +syn = "2.0.40" thiserror = "1.0.50" -tokio = { version = "1.34.0" } +tokio = { version = "1.35.0" } url = "2.5.0" -wat = "1.0.81" +wat = "1.0.82" wabt = "0.10.0" wasmer = "2.2" wasmer-cache = "2.2.1" @@ -182,15 +166,12 @@ tempfile = "3.8.1" # Published deps # -# fork of `parity-wasm` with sign-ext enabled by default. -# -# https://github.com/gear-tech/parity-wasm/tree/v0.45.1-sign-ext -# gear-wasm = "0.45.1" -# -# fork of `wasm-instrument` -# +# https://github.com/gear-tech/dlmalloc-rust/tree/v0.1.4 +dlmalloc = { package = "gear-dlmalloc", version = "0.1.4" } # https://github.com/gear-tech/wasm-instrument/tree/v0.2.3-sign-ext gwasm-instrument = { version = "0.2.3", default-features = false } +# https://github.com/gear-tech/wasm-utils/tree/v0.19.0 +pwasm-utils = { version = "0.19.0", package = "gear-pwasm-utils" } # Internal deps numerated = { path = "common/numerated" } @@ -420,7 +401,6 @@ demo-reserve-gas = { path = "examples/reserve-gas", default-features = false } demo-rwlock = { path = "examples/rwlock" } demo-send-from-reservation = { path = "examples/send-from-reservation" } demo-signal-entry = { path = "examples/signal-entry" } -demo-signal-wait = { path = "examples/signal-wait" } demo-state-rollback = { path = "examples/state-rollback" } demo-sync-duplicate = { path = "examples/sync-duplicate" } demo-vec = { path = "examples/vec" } @@ -447,7 +427,6 @@ mimalloc = { version = "0.1.39", default-features = false } # node nacl = "0.5.3" # gcli nonempty = "0.8.1" # utils/utils libfuzzer-sys = "0.4" # utils/runtime-fuzzer/fuzz -pwasm-utils = "0.19.0" # utils/wasm-builder page_size = { version = "0.6", default-features = false } # pallets/gear pathdiff = { version = "0.2.1", default-features = false } # utils/wasm-builder rand_pcg = "0.3.1" # pallets/gear @@ -467,9 +446,7 @@ fail = "0.5" # gear scale-value = "^0.12" # gsdk heck = "0.4.1" # gsdk-api-gen etc = "0.1.16" # gcli -cargo_toml = "0.15.3" # crates-io -crates-io = "0.37.0" # crates-io -curl = "0.4.44" # crates-io +toml_edit = "0.21.0" # crates-io scale-decode = "0.9.0" # gsdk directories = "5.0.1" # utils/key-finder num-traits = { version = "0.2", default-features = false } # gear-core diff --git a/common/src/benchmarking.rs b/common/src/benchmarking.rs index a8042a9456d..9d9cd19902a 100644 --- a/common/src/benchmarking.rs +++ b/common/src/benchmarking.rs @@ -29,7 +29,7 @@ use sp_std::borrow::ToOwned; pub fn account(name: &'static str, index: u32, seed: u32) -> AccountId { let entropy = (name, index, seed).using_encoded(blake2_256); - AccountId::from_origin(H256::from_slice(&entropy[..])) + H256::from_slice(&entropy[..]).cast() } // A wasm module that allocates `$num_pages` of memory in `init` function. diff --git a/common/src/lib.rs b/common/src/lib.rs index e8fdff55497..5c67ea3f18d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -84,6 +84,9 @@ pub type Gas = u64; pub trait Origin: Sized { fn into_origin(self) -> H256; fn from_origin(val: H256) -> Self; + fn cast(self) -> T { + T::from_origin(self.into_origin()) + } } impl Origin for u64 { @@ -347,19 +350,3 @@ where self.function.clone() } } - -pub trait PaymentVoucher { - type VoucherId; - type Error; - - fn voucher_id(who: AccountId, program: ProgramId) -> Self::VoucherId; -} - -impl PaymentVoucher for () { - type VoucherId = AccountId; - type Error = &'static str; - - fn voucher_id(_who: AccountId, _program: ProgramId) -> Self::VoucherId { - unimplemented!() - } -} diff --git a/common/src/storage/complex/mailbox.rs b/common/src/storage/complex/mailbox.rs index 0dd98ac590e..da73ebdba30 100644 --- a/common/src/storage/complex/mailbox.rs +++ b/common/src/storage/complex/mailbox.rs @@ -99,6 +99,11 @@ pub trait MailboxError { fn element_not_found() -> Self; } +impl MailboxError for () { + fn duplicate_key() -> Self {} + fn element_not_found() -> Self {} +} + /// `Mailbox` implementation based on `DoubleMapStorage`. /// /// Generic parameter `Error` requires `MailboxError` implementation. diff --git a/common/src/storage/primitives/key.rs b/common/src/storage/primitives/key.rs index e840e13ce78..facc438981b 100644 --- a/common/src/storage/primitives/key.rs +++ b/common/src/storage/primitives/key.rs @@ -54,10 +54,7 @@ impl KeyFor for MailboxKeyGen { type Value = UserStoredMessage; fn key_for(value: &Self::Value) -> Self::Key { - ( - T::from_origin(value.destination().into_origin()), - value.id(), - ) + (value.destination().cast(), value.id()) } } diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index f9d973d2b95..858cd8b395a 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -241,6 +241,7 @@ where builder.add_func(Alloc, wrap_syscall!(alloc)); builder.add_func(Free, wrap_syscall!(free)); + builder.add_func(FreeRange, wrap_syscall!(free_range)); } } diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 265a1aae110..e83f219811f 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -70,12 +70,6 @@ impl From for SyscallValue { } } -impl From for SyscallValue { - fn from(value: i64) -> Self { - SyscallValue(Value::I64(value)) - } -} - impl TryFrom for u32 { type Error = HostError; @@ -675,6 +669,32 @@ where }) } + pub fn free_range(start: u32, end: u32) -> impl Syscall { + InfallibleSyscall::new(RuntimeCosts::FreeRange, move |ctx: &mut CallerWrap| { + let page_err = |_| { + UndefinedTerminationReason::Actor(ActorTerminationReason::Trap( + TrapExplanation::Unknown, + )) + }; + + let start = WasmPage::new(start).map_err(page_err)?; + let end = WasmPage::new(end).map_err(page_err)?; + + let result = ctx.ext_mut().free_range(start, end); + + match ctx.process_alloc_func_result(result)? { + Ok(()) => { + log::trace!("Free range {start:?}:{end:?} success"); + Ok(0) + } + Err(e) => { + log::trace!("Free range {start:?}:{end:?} failed: {e}"); + Ok(1) + } + } + }) + } + pub fn env_vars(vars_ver: u32, vars_ptr: u32) -> impl Syscall { InfallibleSyscall::new(RuntimeCosts::EnvVars, move |ctx: &mut CallerWrap| { let vars = ctx.ext_mut().env_vars(vars_ver)?; diff --git a/core-backend/src/memory.rs b/core-backend/src/memory.rs index 626757962a5..5db2ce99655 100644 --- a/core-backend/src/memory.rs +++ b/core-backend/src/memory.rs @@ -534,7 +534,7 @@ mod tests { Ok(137.into()) ); - // if we have 2 in a row we can allocate even 2 + // if we free 2 in a row we can allocate even 2 ctx.free(117.into()).unwrap(); ctx.free(118.into()).unwrap(); @@ -543,6 +543,14 @@ mod tests { Ok(117.into()) ); + // same as above, if we free_range 2 in a row we can allocate 2 + ctx.free_range(117.into()..=118.into()).unwrap(); + + assert_eq!( + ctx.alloc::(2.into(), &mut mem_wrap, |_| Ok(())), + Ok(117.into()) + ); + // but if 2 are not in a row, bad luck ctx.free(117.into()).unwrap(); ctx.free(158.into()).unwrap(); diff --git a/core-backend/src/mock.rs b/core-backend/src/mock.rs index 84f55e70774..7f577544136 100644 --- a/core-backend/src/mock.rs +++ b/core-backend/src/mock.rs @@ -115,6 +115,9 @@ impl Externalities for MockExt { fn free(&mut self, _page: WasmPage) -> Result<(), Self::AllocError> { Err(Error) } + fn free_range(&mut self, _start: WasmPage, _end: WasmPage) -> Result<(), Self::AllocError> { + Err(Error) + } fn env_vars(&self, version: u32) -> Result { match version { 1 => Ok(EnvVars::V1(EnvVarsV1 { diff --git a/core-processor/src/ext.rs b/core-processor/src/ext.rs index 9c56457f97b..54e6b20f5bf 100644 --- a/core-processor/src/ext.rs +++ b/core-processor/src/ext.rs @@ -40,7 +40,7 @@ use gear_core::{ ContextOutcomeDrain, ContextStore, Dispatch, GasLimit, HandlePacket, InitPacket, MessageContext, Packet, ReplyPacket, }, - pages::{GearPage, PageU32Size, WasmPage}, + pages::{GearPage, PageNumber, PageU32Size, WasmPage}, program::MemoryInfix, reservation::GasReserver, }; @@ -799,6 +799,30 @@ impl Externalities for Ext { .map_err(Into::into) } + fn free_range(&mut self, start: WasmPage, end: WasmPage) -> Result<(), Self::AllocError> { + let page_count: u32 = end + .checked_sub(start) + .ok_or(AllocExtError::Alloc(AllocError::InvalidFreeRange( + start.into(), + end.into(), + )))? + .into(); + + Ext::charge_gas_if_enough( + &mut self.context.gas_counter, + &mut self.context.gas_allowance_counter, + self.context + .host_fn_weights + .free_range_per_page + .saturating_mul(page_count as u64), + )?; + + self.context + .allocations_context + .free_range(start..=end) + .map_err(Into::into) + } + fn env_vars(&self, version: u32) -> Result { match version { 1 => Ok(EnvVars::V1(EnvVarsV1 { @@ -1243,10 +1267,7 @@ impl Externalities for Ext { mod tests { use super::*; use alloc::vec; - use gear_core::{ - message::{ContextSettings, IncomingDispatch, Payload, MAX_PAYLOAD_SIZE}, - pages::PageNumber, - }; + use gear_core::message::{ContextSettings, IncomingDispatch, Payload, MAX_PAYLOAD_SIZE}; struct MessageContextBuilder { incoming_dispatch: IncomingDispatch, @@ -1363,12 +1384,12 @@ mod tests { ); // Freeing existing page. - // Counters still shouldn't be changed. + // Counters shouldn't be changed. assert!(ext.free(existing_page).is_ok()); assert_eq!(ext.gas_left(), gas_left); // Freeing non existing page. - // Counters shouldn't be changed. + // Counters still shouldn't be changed. assert_eq!( ext.free(non_existing_page), Err(AllocExtError::Alloc(AllocError::InvalidFree( diff --git a/core/src/costs.rs b/core/src/costs.rs index 52ba67d015c..9cbe724bfb4 100644 --- a/core/src/costs.rs +++ b/core/src/costs.rs @@ -94,9 +94,15 @@ pub struct HostFnWeights { /// Weight per allocated page for `alloc`. pub alloc_per_page: u64, - /// Weight of calling `alloc`. + /// Weight of calling `free`. pub free: u64, + /// Weight of calling `free_range` + pub free_range: u64, + + /// Weight of calling `free_range` per page + pub free_range_per_page: u64, + /// Weight of calling `gr_reserve_gas`. pub gr_reserve_gas: u64, @@ -326,6 +332,10 @@ pub enum RuntimeCosts { Alloc(u32), /// Weight of calling `free`. Free, + /// Base weight of calling `free_range` + FreeRange, + /// Weight of calling `free_range` per amount of pages. + FreeRangePerPage(u32), /// Weight of calling `gr_reserve_gas`. ReserveGas, /// Weight of calling `gr_unreserve_gas`. @@ -467,6 +477,8 @@ impl RuntimeCosts { Null => 0, Alloc(pages) => cost_with_weight_per_page(s.alloc, s.alloc_per_page, pages), Free => s.free, + FreeRange => s.free_range, + FreeRangePerPage(pages) => cost_with_weight_per_page(0, s.free_range_per_page, pages), ReserveGas => s.gr_reserve_gas, UnreserveGas => s.gr_unreserve_gas, SystemReserveGas => s.gr_system_reserve_gas, diff --git a/core/src/env.rs b/core/src/env.rs index 7f89688cd7e..dde033306e3 100644 --- a/core/src/env.rs +++ b/core/src/env.rs @@ -192,12 +192,12 @@ pub trait Externalities { mem: &mut impl Memory, ) -> Result; - /// Free specific memory page. - /// - /// Unlike traditional allocator, if multiple pages allocated via `alloc`, all pages - /// should be `free`-d separately. + /// Free specific page. fn free(&mut self, page: WasmPage) -> Result<(), Self::AllocError>; + /// Free specific memory range. + fn free_range(&mut self, start: WasmPage, end: WasmPage) -> Result<(), Self::AllocError>; + /// Get environment variables currently set in the system and in the form /// corresponded to the requested version. fn env_vars(&self, version: u32) -> Result; diff --git a/core/src/memory.rs b/core/src/memory.rs index 10bb65bd74f..a86643128f9 100644 --- a/core/src/memory.rs +++ b/core/src/memory.rs @@ -29,7 +29,7 @@ use core::{ fmt, fmt::Debug, iter, - ops::{Deref, DerefMut}, + ops::{Deref, DerefMut, RangeInclusive}, }; use scale_info::{ scale::{self, Decode, Encode, EncodeLike, Input, Output}, @@ -270,6 +270,9 @@ pub enum AllocError { /// outside additionally allocated for this program. #[display(fmt = "Page {_0} cannot be freed by the current program")] InvalidFree(u32), + /// Invalid range for free_range + #[display(fmt = "Invalid range {_0}:{_1} for free_range")] + InvalidFreeRange(u32, u32), /// Gas charge error #[from] #[display(fmt = "{_0}")] @@ -376,15 +379,29 @@ impl AllocationsContext { Ok(start) } - /// Free specific page. - /// - /// Currently running program should own this page. + /// Free specific memory page. pub fn free(&mut self, page: WasmPage) -> Result<(), AllocError> { - if page < self.static_pages || page >= self.max_pages || !self.allocations.remove(&page) { - Err(AllocError::InvalidFree(page.0)) - } else { - Ok(()) + if page < self.static_pages || page >= self.max_pages { + return Err(AllocError::InvalidFree(page.0)); + } + + if !self.allocations.remove(&page) { + return Err(AllocError::InvalidFree(page.0)); + } + + Ok(()) + } + + /// Try to free pages in range. Will only return error if range is invalid. + /// + /// Currently running program should own this pages. + pub fn free_range(&mut self, range: RangeInclusive) -> Result<(), AllocError> { + if *range.start() < self.static_pages || *range.end() >= self.max_pages { + return Err(AllocError::InvalidFreeRange(range.start().0, range.end().0)); } + + self.allocations.retain(|p| !range.contains(p)); + Ok(()) } /// Decomposes this instance and returns allocations. @@ -458,6 +475,13 @@ mod tests { let mut ctx = AllocationsContext::new(BTreeSet::from([WasmPage(0)]), WasmPage(1), WasmPage(1)); assert_eq!(ctx.free(WasmPage(1)), Err(AllocError::InvalidFree(1))); + + let mut ctx = AllocationsContext::new( + BTreeSet::from([WasmPage(1), WasmPage(3)]), + WasmPage(1), + WasmPage(4), + ); + assert_eq!(ctx.free_range(WasmPage(1)..=WasmPage(3)), Ok(())); } #[test] @@ -540,13 +564,15 @@ mod tests { enum Action { Alloc { pages: WasmPage }, Free { page: WasmPage }, + FreeRange { page: WasmPage, size: u8 }, } fn actions() -> impl Strategy> { let action = wasm_page_number().prop_flat_map(|page| { prop_oneof![ Just(Action::Alloc { pages: page }), - Just(Action::Free { page }) + Just(Action::Free { page }), + any::().prop_map(move |size| Action::FreeRange { page, size }), ] }); proptest::collection::vec(action, 0..1024) @@ -579,6 +605,7 @@ mod tests { fn assert_free_error(err: AllocError) { match err { AllocError::InvalidFree(_) => {} + AllocError::InvalidFreeRange(_, _) => {} err => panic!("{err:?}"), } } @@ -610,6 +637,12 @@ mod tests { assert_free_error(err); } } + Action::FreeRange { page, size } => { + let end = WasmPage::from(page.0.saturating_add(size as u32) as u16); + if let Err(err) = ctx.free_range(page..=end) { + assert_free_error(err); + } + } } } } diff --git a/examples/constructor/src/builder.rs b/examples/constructor/src/builder.rs index bf871191605..a11b94f0640 100644 --- a/examples/constructor/src/builder.rs +++ b/examples/constructor/src/builder.rs @@ -1,5 +1,5 @@ use crate::{Arg, Call}; -use alloc::{boxed::Box, string::ToString, vec, vec::Vec}; +use alloc::{string::ToString, vec, vec::Vec}; use core::{fmt::Debug, ops::Deref}; use parity_scale_codec::{WrapperTypeDecode, WrapperTypeEncode}; @@ -297,20 +297,13 @@ impl Calls { pub fn if_else( self, bool_arg: impl Into>, - mut true_call: Self, - mut false_call: Self, + true_calls: Self, + false_calls: Self, ) -> Self { - if true_call.len() != 1 || false_call.len() != 1 { - unimplemented!() - }; - - let true_call = true_call.0.remove(0); - let false_call = false_call.0.remove(0); - self.add_call(Call::IfElse( bool_arg.into(), - Box::new(true_call), - Box::new(false_call), + true_calls.calls(), + false_calls.calls(), )) } diff --git a/examples/constructor/src/call.rs b/examples/constructor/src/call.rs index 2f14a20030c..2a82d24c5ca 100644 --- a/examples/constructor/src/call.rs +++ b/examples/constructor/src/call.rs @@ -1,5 +1,5 @@ use crate::Arg; -use alloc::{boxed::Box, string::String, vec::Vec}; +use alloc::{string::String, vec::Vec}; use parity_scale_codec::{Decode, Encode}; #[derive(Clone, Debug, Decode, Encode)] @@ -34,7 +34,7 @@ pub enum Call { Exit(Arg<[u8; 32]>), BytesEq(Arg>, Arg>), Noop, - IfElse(Arg, Box, Box), + IfElse(Arg, Vec, Vec), Load, LoadBytes, Wait, @@ -246,18 +246,20 @@ mod wasm { Some((left == right).encode()) } - fn if_else(self, previous: Option) -> Option> { - let Self::IfElse(flag, true_call, false_call) = self else { + fn if_else(self, mut previous: Option) -> Option> { + let Self::IfElse(flag, true_calls, false_calls) = self else { unreachable!() }; let flag = flag.value(); - let call = if flag { true_call } else { false_call }; + let calls = if flag { true_calls } else { false_calls }; - let (_call, value) = call.process(previous); + for call in calls { + previous = Some(call.process(previous)); + } - value + previous.and_then(|res| res.1) } fn value(self) -> Option> { diff --git a/examples/signal-wait/Cargo.toml b/examples/signal-wait/Cargo.toml index e81b1af57ca..e69de29bb2d 100644 --- a/examples/signal-wait/Cargo.toml +++ b/examples/signal-wait/Cargo.toml @@ -1,22 +0,0 @@ -[package] -name = "demo-signal-wait" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true - -[lib] -crate-type = ["lib", "cdylib"] - -[dependencies] -gstd.workspace = true - -[build-dependencies] -wasm-dep-builder.workspace = true - -[features] -debug = ["gstd/debug"] -default = ["std"] -std = [] diff --git a/examples/signal-wait/src/lib.rs b/examples/signal-wait/src/lib.rs index 8a7265b62e8..8b137891791 100644 --- a/examples/signal-wait/src/lib.rs +++ b/examples/signal-wait/src/lib.rs @@ -1,22 +1 @@ -// This file is part of Gear. -// Copyright (C) 2022-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(not(feature = "std"))] -mod wasm; diff --git a/examples/signal-wait/src/wasm.rs b/examples/signal-wait/src/wasm.rs deleted file mode 100644 index d00fb71420a..00000000000 --- a/examples/signal-wait/src/wasm.rs +++ /dev/null @@ -1,39 +0,0 @@ -// This file is part of Gear. - -// Copyright (C) 2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use gstd::{exec, prelude::*}; - -static mut FIRST_EXEC: bool = true; - -#[no_mangle] -extern "C" fn handle() { - if unsafe { FIRST_EXEC } { - unsafe { - FIRST_EXEC = false; - } - exec::system_reserve_gas(1_000_000_000).unwrap(); - exec::wait_for(1); - } else { - panic!(); - } -} - -#[no_mangle] -extern "C" fn handle_signal() { - exec::wait(); -} diff --git a/galloc/Cargo.toml b/galloc/Cargo.toml index fa5f19ddc84..f8fedb3528a 100644 --- a/galloc/Cargo.toml +++ b/galloc/Cargo.toml @@ -1,5 +1,7 @@ [package] name = "galloc" +description = "Gear Wasm allocator" +keywords = ["gear", "allocator", "wasm"] version.workspace = true authors.workspace = true edition.workspace = true diff --git a/gcli/Cargo.toml b/gcli/Cargo.toml index a562d8cefff..5ae78c79334 100644 --- a/gcli/Cargo.toml +++ b/gcli/Cargo.toml @@ -11,17 +11,15 @@ license.workspace = true homepage.workspace = true repository.workspace = true -[[bin]] -path = "bin/gcli.rs" -name = "gcli" - [dependencies] gsdk.workspace = true anyhow.workspace = true +async-trait.workspace = true base64.workspace = true color-eyre.workspace = true dirs.workspace = true env_logger.workspace = true +futures.workspace = true gmeta.workspace = true gear-core.workspace = true gear-core-errors.workspace = true @@ -36,7 +34,7 @@ scale-info.workspace = true schnorrkel.workspace = true serde.workspace = true serde_json.workspace = true -clap = { workspace = true, features = ["derive"] } +clap = { workspace = true, features = ["std", "derive"] } thiserror.workspace = true tokio = { workspace = true, features = [ "full" ] } whoami.workspace = true diff --git a/gcli/bin/gcli.rs b/gcli/examples/mycli.rs similarity index 52% rename from gcli/bin/gcli.rs rename to gcli/examples/mycli.rs index 178aa739dea..9b049342ae2 100644 --- a/gcli/bin/gcli.rs +++ b/gcli/examples/mycli.rs @@ -16,18 +16,39 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! gear command entry -use color_eyre::eyre::Result; +use gcli::{async_trait, App, Command, Parser}; -#[tokio::main] -async fn main() -> Result<()> { - color_eyre::install()?; +/// My customized sub commands. +#[derive(Debug, Parser)] +pub enum SubCommand { + /// GCli preset commands. + #[clap(flatten)] + GCliCommands(Command), + /// My customized ping command. + Ping, +} - sp_core::crypto::set_default_ss58_version(gcli::VARA_SS58_PREFIX.into()); +/// My customized gcli. +#[derive(Debug, Parser)] +pub struct MyGCli { + #[clap(subcommand)] + command: SubCommand, +} - if let Err(e) = gcli::cmd::Opt::run().await { - log::error!("{}", e); +#[async_trait] +impl App for MyGCli { + async fn exec(&self) -> anyhow::Result<()> { + match &self.command { + SubCommand::GCliCommands(command) => command.exec(self).await, + SubCommand::Ping => { + println!("pong"); + Ok(()) + } + } } +} - Ok(()) +#[tokio::main] +async fn main() -> color_eyre::Result<()> { + MyGCli::parse().run().await } diff --git a/gcli/src/app.rs b/gcli/src/app.rs new file mode 100644 index 00000000000..0946db8cff2 --- /dev/null +++ b/gcli/src/app.rs @@ -0,0 +1,135 @@ +// This file is part of Gear. +// +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +//! Command line application abstraction + +use crate::keystore; +use clap::Parser; +use color_eyre::{eyre::eyre, Result}; +use env_logger::{Builder, Env}; +use gsdk::{signer::Signer, Api}; + +/// Command line gear program application abstraction. +/// +/// ```ignore +/// use gcli::{async_trait, App, Command, Parser}; +/// +/// /// My customized sub commands. +/// #[derive(Debug, Parser)] +/// pub enum SubCommand { +/// /// GCli preset commands. +/// #[clap(flatten)] +/// GCliCommands(Command), +/// /// My customized ping command. +/// Ping, +/// } +/// +/// /// My customized gcli. +/// #[derive(Debug, Parser)] +/// pub struct MyGCli { +/// #[clap(subcommand)] +/// command: SubCommand, +/// } +/// +/// #[async_trait] +/// impl App for MyGCli { +/// async fn exec(&self) -> anyhow::Result<()> { +/// match &self.command { +/// SubCommand::GCliCommands(command) => command.exec(self).await, +/// SubCommand::Ping => { +/// println!("pong"); +/// Ok(()) +/// } +/// } +/// } +/// } +/// +/// #[tokio::main] +/// async fn main() -> color_eyre::Result<()> { +/// MyGCli::parse().run().await +/// } +/// ``` +#[async_trait::async_trait] +pub trait App: Parser + Sync { + /// Timeout of rpc requests. + fn timeout(&self) -> u64 { + 60000 + } + + /// The verbosity logging level. + fn verbose(&self) -> u16 { + 0 + } + + /// The endpoint of the gear node. + fn endpoint(&self) -> Option { + None + } + + /// Password of the signer account. + fn passwd(&self) -> Option { + None + } + + /// Exec program from the parsed arguments. + async fn exec(&self) -> anyhow::Result<()>; + + /// Get signer. + async fn signer(&self) -> anyhow::Result { + let endpoint = self.endpoint().clone(); + let timeout = self.timeout(); + let passwd = self.passwd(); + + let api = Api::new_with_timeout(endpoint.as_deref(), Some(timeout)).await?; + let pair = if let Ok(s) = keystore::cache(passwd.as_deref()) { + s + } else { + keystore::keyring(passwd.as_deref())? + }; + + Ok((api, pair).into()) + } + + /// Run application. + /// + /// This is a wrapper of [`Self::exec`] with preset retry + /// and verbose level. + async fn run(&self) -> Result<()> { + color_eyre::install()?; + sp_core::crypto::set_default_ss58_version(crate::VARA_SS58_PREFIX.into()); + + let name = Self::command().get_name().to_string(); + let filter = match self.verbose() { + 0 => format!("{name}=info,gsdk=info"), + 1 => format!("{name}=debug,gsdk=debug"), + 2 => "debug".into(), + _ => "trace".into(), + }; + + let mut builder = Builder::from_env(Env::default().default_filter_or(filter)); + builder + .format_target(false) + .format_module_path(false) + .format_timestamp(None); + builder.try_init()?; + + self.exec() + .await + .map_err(|e| eyre!("Failed to run app, {e}")) + } +} diff --git a/examples/signal-wait/build.rs b/gcli/src/bin/gcli.rs similarity index 85% rename from examples/signal-wait/build.rs rename to gcli/src/bin/gcli.rs index 56e81d1b0b2..1ed0e8eefb0 100644 --- a/examples/signal-wait/build.rs +++ b/gcli/src/bin/gcli.rs @@ -1,21 +1,24 @@ // This file is part of Gear. - +// // Copyright (C) 2021-2023 Gear Technologies Inc. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. - +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. - +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -fn main() { - wasm_dep_builder::demo(); +use gcli::{cmd::Opt, App, Parser}; + +#[tokio::main] +async fn main() -> color_eyre::Result<()> { + Opt::parse().run().await } diff --git a/gcli/src/cmd/info.rs b/gcli/src/cmd/info.rs index a9a1e18c741..59776d958ba 100644 --- a/gcli/src/cmd/info.rs +++ b/gcli/src/cmd/info.rs @@ -97,7 +97,8 @@ impl Info { } } -struct Mail { +/// Program mail for display +pub(crate) struct Mail { message: UserStoredMessage, interval: Interval, } diff --git a/gcli/src/cmd/key.rs b/gcli/src/cmd/key.rs index 1a5f85d0ac1..68c1bf3bc00 100644 --- a/gcli/src/cmd/key.rs +++ b/gcli/src/cmd/key.rs @@ -96,6 +96,9 @@ pub struct Key { /// Key actions #[command(subcommand)] action: Action, + /// Passphrase override + #[arg(short, long)] + passwd: Option, } macro_rules! match_scheme { @@ -121,15 +124,15 @@ impl Key { /// # NOTE /// /// Reserved the `passwd` for getting suri from cache. - pub fn exec(&self, passwd: Option<&str>) -> Result<()> { + pub fn exec(&self) -> Result<()> { match &self.action { - Action::Generate => self.generate(passwd)?, + Action::Generate => self.generate()?, #[cfg(feature = "node-key")] Action::GenerateNodeKey => Self::generate_node_key(), - Action::Inspect { suri } => self.inspect(suri, passwd)?, + Action::Inspect { suri } => self.inspect(suri)?, #[cfg(feature = "node-key")] Action::InspectNodeKey { secret } => Self::inspect_node_key(secret)?, - Action::Sign { suri, message } => self.sign(suri, message, passwd)?, + Action::Sign { suri, message } => self.sign(suri, message)?, Action::Verify { signature, message, @@ -140,7 +143,8 @@ impl Key { Ok(()) } - fn generate(&self, passwd: Option<&str>) -> Result<()> { + fn generate(&self) -> Result<()> { + let passwd = self.passwd.as_deref(); match_scheme!(self.scheme, generate_with_phrase(passwd), res, { let (pair, phrase, seed) = res; let signer = pair.signer(); @@ -181,9 +185,10 @@ impl Key { println!(" SS58 Address: {}", signer.public().into_account()); } - fn inspect(&self, suri: &str, passwd: Option<&str>) -> Result<()> { + fn inspect(&self, suri: &str) -> Result<()> { let key = KeyT::from_string(suri); let key_ref = &key; + let passwd = self.passwd.as_deref(); match_scheme!(self.scheme, pair(key_ref, passwd), pair, { Self::info(&format!("Secret Key URI `{suri}`"), pair.0.signer(), pair.1) }); @@ -209,9 +214,10 @@ impl Key { Ok(()) } - fn sign(&self, suri: &str, message: &str, passwd: Option<&str>) -> Result<()> { + fn sign(&self, suri: &str, message: &str) -> Result<()> { let key = KeyT::from_string(suri); let key_ref = &key; + let passwd = self.passwd.as_deref(); match_scheme!(self.scheme, pair(key_ref, passwd), pair, { let signer = pair.0.signer(); diff --git a/gcli/src/cmd/mod.rs b/gcli/src/cmd/mod.rs index 6f22dbb1588..29ea7ef4c41 100644 --- a/gcli/src/cmd/mod.rs +++ b/gcli/src/cmd/mod.rs @@ -17,11 +17,8 @@ // along with this program. If not, see . //! commands -use crate::{keystore, result::Result}; +use crate::App; use clap::Parser; -use env_logger::{Builder, Env}; -use gsdk::Api; -use log::LevelFilter; pub mod claim; pub mod create; @@ -36,7 +33,7 @@ pub mod transfer; pub mod update; pub mod upload; -/// Commands of cli `gear` +/// All SubCommands of gear command line interface. #[derive(Debug, Parser)] pub enum Command { Claim(claim::Claim), @@ -54,26 +51,42 @@ pub enum Command { Update(update::Update), } -/// gear command-line tools -/// ___ ___ _ ___ -/// / __| / __| | | |_ _| -/// | (_ | | (__ | |__ | | -/// \___| \___| |____| |___| -/// _|"""""|_|"""""|_|"""""|_|"""""| -/// "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-' +impl Command { + /// Execute the command. + pub async fn exec(&self, app: &impl App) -> anyhow::Result<()> { + match self { + Command::Key(key) => key.exec()?, + Command::Login(login) => login.exec()?, + Command::New(new) => new.exec().await?, + Command::Program(program) => program.exec(app).await?, + Command::Update(update) => update.exec().await?, + Command::Claim(claim) => claim.exec(app.signer().await?).await?, + Command::Create(create) => create.exec(app.signer().await?).await?, + Command::Info(info) => info.exec(app.signer().await?).await?, + Command::Send(send) => send.exec(app.signer().await?).await?, + Command::Upload(upload) => upload.exec(app.signer().await?).await?, + Command::Transfer(transfer) => transfer.exec(app.signer().await?).await?, + Command::Reply(reply) => reply.exec(app.signer().await?).await?, + } + + Ok(()) + } +} + +/// Gear command-line interface. #[derive(Debug, Parser)] -#[clap(author, version, verbatim_doc_comment)] +#[clap(author, version)] #[command(name = "gcli")] pub struct Opt { /// Commands. #[command(subcommand)] pub command: Command, - /// How many times we'll retry when RPC requests failed. - #[arg(short, long, default_value = "5")] - pub retry: u16, + /// Timeout for rpc requests. + #[arg(short, long, default_value = "60000")] + pub timeout: u64, /// Enable verbose logs. - #[arg(short, long)] - pub verbose: bool, + #[clap(short, long, action = clap::ArgAction::Count)] + pub verbose: u16, /// Gear node rpc endpoint. #[arg(short, long)] pub endpoint: Option, @@ -82,87 +95,33 @@ pub struct Opt { pub passwd: Option, } -impl Opt { - /// setup logs - fn setup_logs(&self) -> Result<()> { - let mut builder = if self.verbose { - Builder::from_env(Env::default().default_filter_or("gcli=debug")) - } else { - match &self.command { - Command::Claim(_) - | Command::Create(_) - | Command::Reply(_) - | Command::Send(_) - | Command::Upload(_) - | Command::Transfer(_) => { - let mut builder = Builder::from_env(Env::default().default_filter_or("info")); - builder - .format_target(false) - .format_module_path(false) - .format_timestamp(None) - .filter_level(LevelFilter::Info); - - builder - } - _ => Builder::from_default_env(), - } - }; +#[async_trait::async_trait] +impl App for Opt { + fn timeout(&self) -> u64 { + self.timeout + } - builder.try_init()?; - Ok(()) + fn verbose(&self) -> u16 { + self.verbose } - /// run program - pub async fn run() -> Result<()> { - let opt = Opt::parse(); + fn endpoint(&self) -> Option { + self.endpoint.clone() + } - opt.setup_logs()?; - opt.exec().await?; - Ok(()) + fn passwd(&self) -> Option { + self.passwd.clone() } - /// Create api client from endpoint - async fn api(&self) -> Result { - Api::new(self.endpoint.as_deref()).await.map_err(Into::into) + async fn exec(&self) -> anyhow::Result<()> { + self.command.exec(self).await } +} - /// Execute command sync +impl Opt { + /// Run command sync. pub fn exec_sync(&self) -> color_eyre::Result<()> { let rt = tokio::runtime::Runtime::new().unwrap(); - - rt.block_on(self.exec()).map_err(Into::into) - } - - /// Execute command. - pub async fn exec(&self) -> Result<()> { - match &self.command { - Command::Key(key) => key.exec(self.passwd.as_deref())?, - Command::Login(login) => login.exec()?, - Command::New(new) => new.exec().await?, - Command::Program(program) => program.exec(self.api().await?).await?, - Command::Update(update) => update.exec().await?, - sub => { - let api = self.api().await?; - let pair = if let Ok(s) = keystore::cache(self.passwd.as_deref()) { - s - } else { - keystore::keyring(self.passwd.as_deref())? - }; - let signer = (api, pair).into(); - - match sub { - Command::Claim(claim) => claim.exec(signer).await?, - Command::Create(create) => create.exec(signer).await?, - Command::Info(info) => info.exec(signer).await?, - Command::Send(send) => send.exec(signer).await?, - Command::Upload(upload) => upload.exec(signer).await?, - Command::Transfer(transfer) => transfer.exec(signer).await?, - Command::Reply(reply) => reply.exec(signer).await?, - _ => unreachable!("Already matched"), - } - } - } - - Ok(()) + rt.block_on(self.run()).map_err(Into::into) } } diff --git a/gcli/src/cmd/program.rs b/gcli/src/cmd/program.rs index 80db325eb2b..e6c7bdaba78 100644 --- a/gcli/src/cmd/program.rs +++ b/gcli/src/cmd/program.rs @@ -17,13 +17,13 @@ // along with this program. If not, see . //! Command `program`. -use crate::{meta::Meta, result::Result}; +use crate::{meta::Meta, result::Result, App}; use clap::Parser; use gsdk::{ext::sp_core::H256, Api}; use std::{fs, path::PathBuf}; /// Read program state, etc. -#[derive(Clone, Debug, Parser)] +#[derive(Debug, Parser)] pub enum Program { /// Display metadata of the program. /// @@ -61,7 +61,7 @@ pub enum Program { impl Program { /// Run command program. - pub async fn exec(&self, api: Api) -> Result<()> { + pub async fn exec(&self, app: &impl App) -> Result<()> { match self { Program::State { pid, @@ -70,6 +70,7 @@ impl Program { args, at, } => { + let api = app.signer().await?.api().clone(); if let (Some(wasm), Some(method)) = (wasm, method) { // read state from wasm. Self::wasm_state(api, *pid, wasm.to_vec(), method, args.clone(), *at).await?; diff --git a/gcli/src/cmd/send.rs b/gcli/src/cmd/send.rs index 77521884460..a72e3bb7375 100644 --- a/gcli/src/cmd/send.rs +++ b/gcli/src/cmd/send.rs @@ -19,7 +19,11 @@ //! Command `send` use crate::{result::Result, utils::Hex}; use clap::Parser; -use gsdk::signer::Signer; +use gsdk::{ + metadata::{gear, runtime_types::gear_common::event::MessageEntry}, + signer::Signer, + Event, +}; /// Sends a message to a program or to another account. /// @@ -55,7 +59,7 @@ pub struct Send { impl Send { pub async fn exec(&self, signer: Signer) -> Result<()> { - signer + let tx = signer .calls .send_message( self.destination.to_hash()?.into(), @@ -65,6 +69,19 @@ impl Send { ) .await?; + let api = signer.api(); + for event in api.events_of(&tx).await? { + if let Event::Gear(gear::Event::MessageQueued { + id, + entry: MessageEntry::Handle, + .. + }) = event + { + log::info!("Message ID: 0x{}", hex::encode(id.0)); + break; + } + } + Ok(()) } } diff --git a/gcli/src/cmd/upload.rs b/gcli/src/cmd/upload.rs index 34635284f92..27f8073e362 100644 --- a/gcli/src/cmd/upload.rs +++ b/gcli/src/cmd/upload.rs @@ -18,8 +18,13 @@ //! command `upload_program` use crate::{result::Result, utils::Hex}; +use anyhow::anyhow; use clap::Parser; -use gsdk::signer::Signer; +use gsdk::{ + metadata::{gear::Event as GearEvent, runtime_types::gear_common::event::MessageEntry}, + signer::Signer, + Event, +}; use std::{fs, path::PathBuf}; /// Deploy program to gear node or save program `code` in storage. @@ -47,7 +52,8 @@ pub struct Upload { impl Upload { /// Exec command submit pub async fn exec(&self, signer: Signer) -> Result<()> { - let code = fs::read(&self.code)?; + let code = + fs::read(&self.code).map_err(|e| anyhow!("program {:?} not found, {e}", &self.code))?; if self.code_only { signer.calls.upload_code(code).await?; return Ok(()); @@ -66,11 +72,29 @@ impl Upload { // Estimate gas and upload program. let gas_limit = signer.api().cmp_gas_limit(gas)?; - signer + let tx = signer .calls .upload_program(code, self.salt.to_vec()?, payload, gas_limit, self.value) .await?; + for event in signer.api().events_of(&tx).await? { + match event { + Event::Gear(GearEvent::MessageQueued { + id, + destination, + entry: MessageEntry::Init, + .. + }) => { + log::info!("Program ID: 0x{}", hex::encode(destination.0)); + log::info!("Init Message ID: 0x{}", hex::encode(id.0)); + } + Event::Gear(GearEvent::CodeChanged { id, .. }) => { + log::info!("Code ID: 0x{}", hex::encode(id.0)); + } + _ => {} + } + } + Ok(()) } } diff --git a/gcli/src/lib.rs b/gcli/src/lib.rs index 569987e692c..364fe1e00a8 100644 --- a/gcli/src/lib.rs +++ b/gcli/src/lib.rs @@ -122,6 +122,7 @@ //! //! GPL v3.0 +mod app; pub mod cmd; pub mod keystore; pub mod meta; @@ -129,5 +130,10 @@ pub mod result; pub mod template; pub mod utils; +pub use self::{app::App, cmd::Command}; +pub use async_trait::async_trait; +pub use clap::Parser; +pub use gsdk::signer::Signer; + /// SS58 prefix for vara network. pub const VARA_SS58_PREFIX: u8 = 137; diff --git a/gcli/src/meta/executor.rs b/gcli/src/meta/executor.rs index 42381ae2328..b15069d8dfa 100644 --- a/gcli/src/meta/executor.rs +++ b/gcli/src/meta/executor.rs @@ -131,6 +131,7 @@ mod env { "gr_size" => gr_size(store, memory), // methods may be used by programs but not required by metadata. "free" => func!(@result store, i32), + "free_range" => func!(@result store, i32, i32), "gr_block_height" => func!(store, u32), "gr_block_timestamp" => func!(store, u32), "gr_create_program_wgas" => func!(store, i32, i32, u32, i32, u32, u64, u32, i32), diff --git a/gcli/tests/cmd/claim.rs b/gcli/tests/cmd/claim.rs index 7d9e57b924d..208d5ba9831 100644 --- a/gcli/tests/cmd/claim.rs +++ b/gcli/tests/cmd/claim.rs @@ -18,7 +18,7 @@ //! Integration tests for command `send` -use crate::common::{self, logs, traits::NodeExec, Args, Result, ALICE_SS58_ADDRESS as ADDRESS}; +use crate::common::{self, node::NodeExec, Args, Result, ALICE_SS58_ADDRESS as ADDRESS}; use gsdk::Api; const REWARD_PER_BLOCK: u128 = 75_000; // 3_000 gas * 25 value per gas @@ -27,9 +27,7 @@ const REWARD_PER_BLOCK: u128 = 75_000; // 3_000 gas * 25 value per gas async fn test_command_claim_works() -> Result<()> { // hack to check initial alice balance let (initial_balance, initial_stash) = { - let mut node = common::dev()?; - - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS)?; + let node = common::dev()?; // Get balance of the testing address let signer = Api::new(Some(&node.ws())) @@ -68,9 +66,7 @@ async fn test_command_claim_works() -> Result<()> { let burned_after = signer.api().get_balance(&signer.address()).await? - initial_stash; let after = signer.api().get_balance(ADDRESS).await?; - assert_eq!(initial_balance - before - burned_before, REWARD_PER_BLOCK,); - + assert_eq!(initial_balance - before - burned_before, REWARD_PER_BLOCK); assert_eq!(initial_balance - burned_after, after); - Ok(()) } diff --git a/gcli/tests/cmd/info.rs b/gcli/tests/cmd/info.rs index 90360519a59..83a91a92b14 100644 --- a/gcli/tests/cmd/info.rs +++ b/gcli/tests/cmd/info.rs @@ -18,8 +18,8 @@ //! Integration tests for command `deploy` use crate::common::{ - self, logs, - traits::{Convert, NodeExec}, + self, + node::{Convert, NodeExec}, Args, Result, }; @@ -46,9 +46,7 @@ const EXPECTED_MAILBOX: &str = r#" #[tokio::test] async fn test_action_balance_works() -> Result<()> { - common::login_as_alice().expect("login failed"); - let mut node = common::dev()?; - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS)?; + let node = common::dev()?; let output = node.run(Args::new("info").address("//Alice").action("balance"))?; let stdout = output.stdout.convert(); diff --git a/gcli/tests/cmd/key.rs b/gcli/tests/cmd/key.rs index afad9b0e186..977d1a19a3a 100644 --- a/gcli/tests/cmd/key.rs +++ b/gcli/tests/cmd/key.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . //! Integration tests for command `key` -use crate::common::{self, traits::Convert, Result}; +use crate::common::{self, node::Convert, Result}; const SIGNATURE_PATT: &str = "Signature:"; const SEED_PATT: &str = "Seed:"; @@ -27,6 +27,10 @@ const PUBLIC_PATT: &str = "Public key:"; fn parse_from<'s>(log: &'s str, patt: &'s str) -> &'s str { let arr = log.split(patt).collect::>(); + if arr.len() != 2 { + panic!("Failed to parse {patt}, log: {log}"); + } + arr[1].split_whitespace().collect::>()[0] } diff --git a/gcli/tests/cmd/program.rs b/gcli/tests/cmd/program.rs index d1e1594afa1..048f1b5ea62 100644 --- a/gcli/tests/cmd/program.rs +++ b/gcli/tests/cmd/program.rs @@ -18,8 +18,8 @@ //! Integration tests for command `program` use crate::common::{ - self, env, logs, - traits::{Convert, NodeExec}, + self, env, + node::{Convert, NodeExec}, Args, Result, }; use demo_new_meta::{MessageInitIn, Wallet}; @@ -27,11 +27,7 @@ use scale_info::scale::Encode; #[tokio::test] async fn test_command_program_state_works() -> Result<()> { - common::login_as_alice().expect("login failed"); - - // Setup node. - let mut node = common::dev()?; - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS)?; + let node = common::dev()?; // Deploy demo_new_meta. let opt = env::wasm_bin("demo_new_meta.opt.wasm"); @@ -100,9 +96,8 @@ fn test_command_program_metadata_works() -> Result<()> { let node = common::dev()?; let meta = env::wasm_bin("demo_new_meta.meta.txt"); let args = Args::new("program").action("meta").meta(meta); - let result = node.run(args)?; + let stdout = node.stdout(args)?; - let stdout = result.stdout.convert(); assert_eq!( stdout.trim(), DEMO_NEW_META_METADATA.trim(), @@ -121,9 +116,7 @@ fn test_command_program_metadata_derive_works() -> Result<()> { .flag("--derive") .derive("Person"); - let result = node.run(args)?; - let stdout = result.stdout.convert(); - + let stdout = node.stdout(args)?; let expected = "Person { surname: String, name: String }"; assert_eq!( stdout.trim(), @@ -158,9 +151,8 @@ fn test_command_program_metawasm_works() -> Result<()> { let node = common::dev()?; let meta = env::wasm_bin("demo_meta_state_v1.meta.wasm"); let args = Args::new("program").action("meta").meta(meta); - let result = node.run(args)?; + let stdout = node.stdout(args)?; - let stdout = result.stdout.convert(); assert_eq!( stdout.trim(), META_WASM_V1_OUTPUT.trim(), @@ -179,8 +171,7 @@ fn test_command_program_metawasm_derive_works() -> Result<()> { .flag("--derive") .derive("Person"); - let result = node.run(args)?; - let stdout = result.stdout.convert(); + let stdout = node.stdout(args)?; let expected = "Person { surname: String, name: String }"; assert_eq!( diff --git a/gcli/tests/cmd/send.rs b/gcli/tests/cmd/send.rs index 83d8fb2020c..f7e3ac2c2da 100644 --- a/gcli/tests/cmd/send.rs +++ b/gcli/tests/cmd/send.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . //! Integration tests for command `send` -use crate::common::{self, traits::NodeExec, Args, Result}; +use crate::common::{self, node::NodeExec, Args, Result}; use gsdk::Api; use scale_info::scale::Encode; diff --git a/gcli/tests/cmd/transfer.rs b/gcli/tests/cmd/transfer.rs index 074da2ef944..b578fe4f3ec 100644 --- a/gcli/tests/cmd/transfer.rs +++ b/gcli/tests/cmd/transfer.rs @@ -18,7 +18,7 @@ //! Integration tests for command `deploy` -use crate::common::{self, logs, Args, NodeExec, Result}; +use crate::common::{self, Args, NodeExec, Result}; use gsdk::Api; // Testing account @@ -27,10 +27,7 @@ const ADDRESS: &str = "kGhmTEymraqSPa1NYjXzqbko2p4Ge1CmEfACtC1s4aC5hTPYk"; #[tokio::test] async fn test_command_transfer_works() -> Result<()> { - common::login_as_alice()?; - let mut node = common::dev()?; - - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS)?; + let node = common::dev()?; // Get balance of the testing address let signer = Api::new(Some(&node.ws())).await?.signer(SURI, None)?; diff --git a/gcli/tests/cmd/upload.rs b/gcli/tests/cmd/upload.rs index 3a28c7d20b8..280d0910166 100644 --- a/gcli/tests/cmd/upload.rs +++ b/gcli/tests/cmd/upload.rs @@ -18,41 +18,29 @@ //! Integration tests for command `upload` use crate::common::{ - self, env, logs, - traits::{Convert, NodeExec}, + self, env, + node::{Convert, NodeExec}, Args, Result, }; use gear_core::ids::CodeId; use gsdk::Api; #[tokio::test] -async fn test_command_upload_works() { - common::login_as_alice().expect("login failed"); - let mut node = common::dev().expect("failed to start node"); - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS) - .expect("node timeout"); - - let signer = Api::new(Some(&node.ws())) - .await - .expect("build api failed") - .signer("//Alice", None) - .expect("get signer failed"); - +async fn test_command_upload_works() -> Result<()> { + let node = common::dev()?; + let signer = Api::new(Some(&node.ws())).await?.signer("//Alice", None)?; let code_id = CodeId::generate(demo_new_meta::WASM_BINARY); assert!( signer.api().code_storage(code_id).await.is_err(), "code should not exist" ); - let output = node - .run(Args::new("upload").program(env::wasm_bin("demo_new_meta.opt.wasm"))) - .expect("run command upload failed"); - + let output = node.run(Args::new("upload").program(env::wasm_bin("demo_new_meta.opt.wasm")))?; assert!( output .stderr .convert() - .contains(logs::gear_program::EX_UPLOAD_PROGRAM), + .contains("Submitted Gear::upload_program"), "code should be uploaded, but got: {:?}", output.stderr ); @@ -60,14 +48,13 @@ async fn test_command_upload_works() { signer.api().code_storage(code_id).await.is_ok(), "code should exist" ); + + Ok(()) } #[tokio::test] -async fn test_command_upload_program_works() -> Result<()> { - common::login_as_alice().expect("login failed"); - let mut node = common::dev()?; - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS)?; - +async fn test_command_upload_code_works() -> Result<()> { + let node = common::dev()?; let output = node.run( Args::new("upload") .flag("--code-only") @@ -77,7 +64,7 @@ async fn test_command_upload_program_works() -> Result<()> { let stderr = output.stderr.convert(); assert!( - stderr.contains(logs::gear_program::EX_UPLOAD_CODE), + stderr.contains("Submitted Gear::upload_code"), "code should be uploaded, but got: {stderr:?}", ); Ok(()) diff --git a/gcli/tests/common/logs.rs b/gcli/tests/common/logs.rs deleted file mode 100644 index 7aa06b7541b..00000000000 --- a/gcli/tests/common/logs.rs +++ /dev/null @@ -1,29 +0,0 @@ -// This file is part of Gear. -// -// Copyright (C) 2021-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Logs from binaries - -pub mod gear_node { - // `#1` is enough here. - pub const IMPORTING_BLOCKS: &str = "Imported #1"; -} - -pub mod gear_program { - pub const EX_UPLOAD_PROGRAM: &str = "Successfully submitted call Gear::upload_program"; - pub const EX_UPLOAD_CODE: &str = "Successfully submitted call Gear::upload_code"; -} diff --git a/gcli/tests/common/mod.rs b/gcli/tests/common/mod.rs index 78494bb3d1b..f387ecb27de 100644 --- a/gcli/tests/common/mod.rs +++ b/gcli/tests/common/mod.rs @@ -19,14 +19,15 @@ //! Common utils for integration tests pub use self::{ args::Args, + node::{Convert, NodeExec}, result::{Error, Result}, - traits::{Convert, NodeExec}, }; use gear_core::ids::{CodeId, ProgramId}; use gsdk::{ ext::{sp_core::crypto::Ss58Codec, sp_runtime::AccountId32}, testing::Node, }; +pub use scale_info::scale::Encode; use std::{ iter::IntoIterator, process::{Command, Output}, @@ -34,18 +35,10 @@ use std::{ mod args; pub mod env; -pub mod logs; +pub mod node; mod result; -pub mod traits; -mod prelude { - pub use scale_info::scale::Encode; - - pub const ALICE_SS58_ADDRESS: &str = "kGkLEU3e3XXkJp2WK4eNpVmSab5xUNL9QtmLPh8QfCL2EgotW"; -} - -#[cfg(not(feature = "vara-testing"))] -pub use prelude::*; +pub const ALICE_SS58_ADDRESS: &str = "kGkLEU3e3XXkJp2WK4eNpVmSab5xUNL9QtmLPh8QfCL2EgotW"; impl NodeExec for Node { fn ws(&self) -> String { @@ -72,9 +65,16 @@ pub fn gcli(args: impl IntoIterator) -> Result { /// Run the dev node pub fn dev() -> Result { + login_as_alice()?; + let args = vec!["--tmp", "--dev"]; + let mut node = Node::try_from_path(env::bin("gear"), args)?; - Node::try_from_path(env::bin("gear"), args).map_err(Into::into) + // TODO: use [`Node::wait_while_initialized`] instead, + // it currently presents infinite loop even after capturing + // the specified log #3304. + node.wait_for_log_record("Imported #1")?; + Ok(node) } /// Init env logger @@ -103,12 +103,10 @@ pub fn alice_account_id() -> AccountId32 { /// Create program messager pub async fn create_messager() -> Result { - login_as_alice()?; - let mut node = dev()?; - node.wait_for_log_record(logs::gear_node::IMPORTING_BLOCKS)?; + let node = dev()?; let args = Args::new("upload").program(env::wasm_bin("demo_messager.opt.wasm")); - let _ = node.run(args)?; + Ok(node) } diff --git a/gcli/tests/common/traits.rs b/gcli/tests/common/node.rs similarity index 81% rename from gcli/tests/common/traits.rs rename to gcli/tests/common/node.rs index 797dc11569c..9ff5469b429 100644 --- a/gcli/tests/common/traits.rs +++ b/gcli/tests/common/node.rs @@ -16,9 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Shared traits. +//! Shared node. use crate::common::{Args, Output, Result}; +use anyhow::anyhow; /// Convert self into `String`. pub trait Convert { @@ -48,6 +49,18 @@ pub trait NodeExec { /// ``` fn run(&self, args: Args) -> Result; + /// Execute command gcli with Node instance + /// and return stdout. + fn stdout(&self, args: Args) -> Result { + let output = self.run(args)?; + + if output.stdout.is_empty() { + return Err(anyhow!("stdout is empty, stderr: {}", output.stderr.convert()).into()); + } + + Ok(output.stdout.convert()) + } + /// Formats websocket address to string. /// /// This interface is used for constructing the `endpoint` diff --git a/gcore/Cargo.toml b/gcore/Cargo.toml index dff1d9db8bf..f0e4ac0fdea 100644 --- a/gcore/Cargo.toml +++ b/gcore/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "gcore" +description = "Gear programs core library" version.workspace = true authors.workspace = true edition.workspace = true diff --git a/gsdk/Cargo.toml b/gsdk/Cargo.toml index 35b7fdb4c22..08f5540537a 100644 --- a/gsdk/Cargo.toml +++ b/gsdk/Cargo.toml @@ -13,6 +13,7 @@ repository.workspace = true [dependencies] anyhow.workspace = true base64.workspace = true +colored.workspace = true futures-util.workspace = true futures.workspace = true gear-core = { workspace = true, features = [ "std" ] } diff --git a/gsdk/api-gen/Cargo.toml b/gsdk/api-gen/Cargo.toml index 6ab0e2fc2ed..2ab9911b677 100644 --- a/gsdk/api-gen/Cargo.toml +++ b/gsdk/api-gen/Cargo.toml @@ -25,4 +25,4 @@ subxt-codegen.workspace = true # TODO: inherit from workspace # # use "2.0.15" because subxt-codegen-0.29.0 requires it. -syn = { version = "2.0.39", features = ["full", "parsing"] } +syn = { version = "2.0.40", features = ["full", "parsing"] } diff --git a/gsdk/src/api.rs b/gsdk/src/api.rs index 475b86a29a2..60f243c57d5 100644 --- a/gsdk/src/api.rs +++ b/gsdk/src/api.rs @@ -16,9 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{client::Rpc, config::GearConfig, signer::Signer, Blocks, Events, Result}; +use crate::{ + client::Rpc, config::GearConfig, metadata::Event, signer::Signer, Blocks, Events, Result, + TxInBlock, +}; use core::ops::{Deref, DerefMut}; -use subxt::OnlineClient; +use std::result::Result as StdResult; +use subxt::{Error, OnlineClient}; /// Gear api wrapper. #[derive(Clone)] @@ -96,6 +100,16 @@ impl Api { Ok(self.client.blocks().subscribe_all().await?.into()) } + /// Parse events of an extrinsic + pub async fn events_of(&self, tx: &TxInBlock) -> Result> { + tx.fetch_events() + .await? + .iter() + .map(|e| -> StdResult { e?.as_root_event::() }) + .collect::, Error>>() + .map_err(Into::into) + } + /// Subscribe finalized events /// /// Same as `events` but only finalized events. diff --git a/gsdk/src/client.rs b/gsdk/src/client.rs index 0a416da914b..71c2cd95128 100644 --- a/gsdk/src/client.rs +++ b/gsdk/src/client.rs @@ -71,6 +71,7 @@ impl RpcClient { timeout.unwrap_or(DEFAULT_TIMEOUT), ); + log::info!("Connecting to {url} ..."); if url.starts_with("ws") { Ok(Self::Ws( WsClientBuilder::default() diff --git a/gsdk/src/metadata/generated.rs b/gsdk/src/metadata/generated.rs index 2024928555f..007041e2882 100644 --- a/gsdk/src/metadata/generated.rs +++ b/gsdk/src/metadata/generated.rs @@ -2667,12 +2667,9 @@ pub mod runtime_types { #[doc = "Program with the specified id is not found."] ProgramNotFound, #[codec(index = 14)] - #[doc = "Voucher can't be redeemed"] - FailureRedeemingVoucher, - #[codec(index = 15)] #[doc = "Gear::run() already included in current block."] GearRunAlreadyInBlock, - #[codec(index = 16)] + #[codec(index = 15)] #[doc = "The program rent logic is disabled."] ProgramRentDisabled, } @@ -2778,6 +2775,8 @@ pub mod runtime_types { pub alloc: runtime_types::sp_weights::weight_v2::Weight, pub alloc_per_page: runtime_types::sp_weights::weight_v2::Weight, pub free: runtime_types::sp_weights::weight_v2::Weight, + pub free_range: runtime_types::sp_weights::weight_v2::Weight, + pub free_range_per_page: runtime_types::sp_weights::weight_v2::Weight, pub gr_reserve_gas: runtime_types::sp_weights::weight_v2::Weight, pub gr_unreserve_gas: runtime_types::sp_weights::weight_v2::Weight, pub gr_system_reserve_gas: runtime_types::sp_weights::weight_v2::Weight, @@ -3337,9 +3336,9 @@ pub mod runtime_types { #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] pub enum Error { #[codec(index = 0)] - FailureToCreateVoucher, + InsufficientBalance, #[codec(index = 1)] - FailureToRedeemVoucher, + InvalidVoucher, } #[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)] #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] diff --git a/gsdk/src/signer/utils.rs b/gsdk/src/signer/utils.rs index 84a568ef556..cc705bf9926 100644 --- a/gsdk/src/signer/utils.rs +++ b/gsdk/src/signer/utils.rs @@ -30,6 +30,7 @@ use crate::{ Error, TxInBlock, TxStatus, }; use anyhow::anyhow; +use colored::Colorize; use scale_value::Composite; use sp_core::H256; use std::sync::Arc; @@ -48,7 +49,7 @@ impl Inner { pub async fn log_balance_spent(&self, before: u128) -> Result<()> { let signer_rpc = SignerRpc(Arc::new(self.clone())); let after = before.saturating_sub(signer_rpc.get_balance().await?); - log::info!(" Balance spent: {after}"); + log::info!("\tBalance spent: {after}"); Ok(()) } @@ -56,22 +57,22 @@ impl Inner { /// Propagates log::info for given status. pub(crate) fn log_status(status: &TxStatus) { match status { - TxStatus::Validated => log::info!(" Status: Validated"), - TxStatus::Broadcasted { num_peers } => log::info!(" Status: Broadcast( {num_peers} )"), - TxStatus::NoLongerInBestBlock => log::info!(" Status: NoLongerInBestBlock"), + TxStatus::Validated => log::info!("\tStatus: Validated"), + TxStatus::Broadcasted { num_peers } => log::info!("\tStatus: Broadcast( {num_peers} )"), + TxStatus::NoLongerInBestBlock => log::info!("\tStatus: NoLongerInBestBlock"), TxStatus::InBestBlock(b) => log::info!( - " Status: InBestBlock( block hash: {}, extrinsic hash: {} )", + "\tStatus: InBestBlock( block hash: {}, extrinsic hash: {} )", b.block_hash(), b.extrinsic_hash() ), TxStatus::InFinalizedBlock(b) => log::info!( - " Status: Finalized( block hash: {}, extrinsic hash: {} )", + "\tStatus: Finalized( block hash: {}, extrinsic hash: {} )", b.block_hash(), b.extrinsic_hash() ), - TxStatus::Error { message: e } => log::error!(" Status: Error( {e} )"), - TxStatus::Dropped { message: e } => log::error!(" Status: Dropped( {e} )"), - TxStatus::Invalid { message: e } => log::error!(" Status: Invalid( {e} )"), + TxStatus::Error { message: e } => log::error!("\tStatus: Error( {e:?} )"), + TxStatus::Dropped { message: e } => log::error!("\tStatus: Dropped( {e:?} )"), + TxStatus::Invalid { message: e } => log::error!("\tStatus: Invalid( {e:?} )"), } } @@ -84,9 +85,9 @@ impl Inner { let mut process = self.sign_and_submit_then_watch(&tx).await?; let (pallet, name) = (tx.pallet_name(), tx.call_name()); + let extrinsic = format!("{pallet}::{name}").magenta().bold(); - log::info!("Submitted extrinsic {}::{}", pallet, name); - + log::info!("Pending {extrinsic} ..."); let mut queue: Vec = Default::default(); let mut hash: Option = None; @@ -115,13 +116,9 @@ impl Inner { ); } InFinalizedBlock(b) => { - log::info!( - "Successfully submitted call {}::{} {} at {}!", - pallet, - name, - b.extrinsic_hash(), - b.block_hash() - ); + log::info!("Submitted {extrinsic} !"); + log::info!("\tBlock Hash: {:?}", b.block_hash()); + log::info!("\tTransaction Hash: {:?}", b.extrinsic_hash()); self.log_balance_spent(before).await?; return Ok(b); } @@ -196,7 +193,6 @@ impl Inner { call: Call, fields: impl Into>, ) -> Result { - log::info!("Run tx: {}::{}", Call::PALLET, call.call_name()); let tx = subxt::dynamic::tx(Call::PALLET, call.call_name(), fields.into()); self.process(tx).await diff --git a/gsdk/src/testing/node.rs b/gsdk/src/testing/node.rs index 6dcade77aaf..77d8df44894 100644 --- a/gsdk/src/testing/node.rs +++ b/gsdk/src/testing/node.rs @@ -18,6 +18,7 @@ use crate::testing::{port, Error, Result}; use std::{ + env, ffi::OsStr, io::{BufRead, BufReader}, net::{Ipv4Addr, SocketAddrV4}, @@ -43,10 +44,13 @@ impl Node { let port_string = port.to_string(); let mut args = args; - args.push("--ws-port"); - args.push(&port_string); + args.extend_from_slice(&["--ws-port", &port_string]); let process = Command::new(path) + .env( + "RUST_LOG", + env::var("RUST_LOG").unwrap_or_else(|_| "".into()), + ) .args(args) .stderr(Stdio::piped()) .stdout(Stdio::piped()) @@ -62,15 +66,19 @@ impl Node { Ok(node) } - fn wait_while_initialized(&mut self) -> Result { + /// Wait until node is initialized. + pub fn wait_while_initialized(&mut self) -> Result { // `#1` here is enough to ensure that node is initialized. self.wait_for_log_record("Imported #1 ") } + /// Wait the provided log record is emitted. pub fn wait_for_log_record(&mut self, log: &str) -> Result { - let stderr = self.process.stderr.as_mut(); - let reader = BufReader::new(stderr.ok_or(Error::EmptyStderr)?); - for line in reader.lines().flatten() { + let Some(stderr) = self.process.stderr.as_mut() else { + return Err(Error::EmptyStderr); + }; + + for line in BufReader::new(stderr).lines().flatten() { if line.contains(log) { return Ok(line); } diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index ab8ddff724f..aa6c6ae6d5d 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -1,9 +1,14 @@ [package] name = "gstd" +description = "Gear programs standard library" +keywords = ["gear", "std", "no-std", "wasm", "smart-contracts"] +categories = ["api-bindings"] version.workspace = true -authors.workspace = true edition.workspace = true +authors.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [dependencies] document-features = { version = "0.2.7", optional = true } diff --git a/gstd/codegen/Cargo.toml b/gstd/codegen/Cargo.toml index 3f99d9d2985..5b790f762fb 100644 --- a/gstd/codegen/Cargo.toml +++ b/gstd/codegen/Cargo.toml @@ -1,15 +1,20 @@ [package] name = "gstd-codegen" -version = "0.1.0" -authors.workspace = true +description = "Code generation library for the Gear standard library" +keywords = ["gear", "codegen", "std"] +categories = ["api-bindings"] +version.workspace = true edition.workspace = true +authors.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lib] proc-macro = true [dependencies] -syn = { workspace = true, features = ["full"] } +syn = { workspace = true, features = ["default", "full"] } quote.workspace = true proc-macro2.workspace = true diff --git a/gsys/src/lib.rs b/gsys/src/lib.rs index 6cb4cdeb15c..daf6b517c75 100644 --- a/gsys/src/lib.rs +++ b/gsys/src/lib.rs @@ -474,7 +474,7 @@ extern "C" { err_mid_pid: *mut ErrorWithTwoHashes, ); - /// Fallible `gr_reply_deposit` syscall. + /// Fallible `gr_reply_deposit` control syscall. /// /// Arguments type: /// - `message_id`: `const ptr` for message id. diff --git a/lazy-pages/interface/src/lib.rs b/lazy-pages/interface/src/lib.rs index ef0d7d73f87..d9dc7232280 100644 --- a/lazy-pages/interface/src/lib.rs +++ b/lazy-pages/interface/src/lib.rs @@ -24,7 +24,6 @@ extern crate alloc; use byteorder::{ByteOrder, LittleEndian}; use core::fmt; -use gear_common::Origin; use gear_core::{ ids::ProgramId, memory::{HostPointer, Memory, MemoryInterval}, @@ -75,10 +74,9 @@ pub fn init_for_program( wasm_mem_size: mem.size().raw(), stack_end: stack_end.map(|p| p.raw()), program_key: { - let program_id = <[u8; 32]>::from(program_id.into_origin()); let memory_infix = memory_infix.inner().to_le_bytes(); - [&program_id[..], &memory_infix[..]].concat() + [program_id.as_ref(), memory_infix.as_ref()].concat() }, globals_config, weights, diff --git a/pallets/gas/src/tests.rs b/pallets/gas/src/tests.rs index e9edc9cdbc7..96aa29c6895 100644 --- a/pallets/gas/src/tests.rs +++ b/pallets/gas/src/tests.rs @@ -31,7 +31,7 @@ type Gas = as common::GasProvider>::GasTree; type GasTree = GasNodes; fn random_node_id() -> MessageId { - MessageId::from_origin(H256::random()) + H256::random().cast() } const MULTIPLIER: GasMultiplier = GasMultiplier::ValuePerGas(25); diff --git a/pallets/gear-debug/src/lib.rs b/pallets/gear-debug/src/lib.rs index 7e699474be1..adb4a05837d 100644 --- a/pallets/gear-debug/src/lib.rs +++ b/pallets/gear-debug/src/lib.rs @@ -37,7 +37,7 @@ pub mod pallet { use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; use frame_system::pallet_prelude::*; use gear_core::{ - ids::{CodeId, ProgramId}, + ids::ProgramId, memory::PageBuf, message::{StoredDispatch, StoredMessage}, pages::{GearPage, PageU32Size, WasmPage}, @@ -184,8 +184,8 @@ pub mod pallet { let message = StoredMessage::new( msg.id(), - ProgramId::from_origin(source), - ProgramId::from_origin(destination), + source.cast(), + destination.cast(), (*msg.payload_bytes()).to_vec().try_into().unwrap(), msg.value(), msg.details(), @@ -211,8 +211,7 @@ pub mod pallet { } } }; - let code_id = CodeId::from_origin(active.code_hash); - let static_pages = match T::CodeStorage::get_code(code_id) { + let static_pages = match T::CodeStorage::get_code(active.code_hash.cast()) { Some(code) => code.static_pages(), None => WasmPage::zero(), }; diff --git a/pallets/gear-debug/src/mock.rs b/pallets/gear-debug/src/mock.rs index 0306045e380..0cd9529c9e1 100644 --- a/pallets/gear-debug/src/mock.rs +++ b/pallets/gear-debug/src/mock.rs @@ -19,7 +19,9 @@ use crate as pallet_gear_debug; use common::storage::Limiter; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, + dispatch::DispatchClass, + parameter_types, traits::{FindAuthor, Get, OnFinalize, OnInitialize}, weights::Weight, }; @@ -148,6 +150,10 @@ pub fn run_to_block(n: u64, remaining_weight: Option) { ); } + // Spend the maximum weight of the block to account for the weight of Gear::run() in the current block. + let max_block_weight = + <::BlockWeights as Get>::get().max_block; + System::register_extra_weight_unchecked(max_block_weight, DispatchClass::Mandatory); Gear::run(frame_support::dispatch::RawOrigin::None.into(), None).unwrap(); Gear::on_finalize(System::block_number()); diff --git a/pallets/gear-debug/src/tests/mod.rs b/pallets/gear-debug/src/tests/mod.rs index 11865cff8f8..4a3c0d7360f 100644 --- a/pallets/gear-debug/src/tests/mod.rs +++ b/pallets/gear-debug/src/tests/mod.rs @@ -952,7 +952,7 @@ fn disabled_program_rent() { let block_count = 2_000u32; let rent = RentCostPerBlockOf::::get() * u128::from(block_count); - let pay_rent_account_id = AccountId::from_origin(pay_rent_id.into_origin()); + let pay_rent_account_id = pay_rent_id.cast::(); let balance_before = Balances::free_balance(pay_rent_account_id); assert_ok!(Gear::send_message( RuntimeOrigin::signed(1), diff --git a/pallets/gear-scheduler/src/mock.rs b/pallets/gear-scheduler/src/mock.rs index 65e97e9802d..f5fc7da8aa1 100644 --- a/pallets/gear-scheduler/src/mock.rs +++ b/pallets/gear-scheduler/src/mock.rs @@ -20,6 +20,7 @@ use crate as pallet_gear_scheduler; use common::storage::Limiter; use frame_support::{ construct_runtime, + dispatch::DispatchClass, pallet_prelude::*, parameter_types, traits::{ConstU64, FindAuthor}, @@ -145,6 +146,10 @@ pub fn run_to_block(n: u64, remaining_weight: Option) { ); } + // Spend the maximum weight of the block to account for the weight of Gear::run() in the current block. + let max_block_weight = + <::BlockWeights as Get>::get().max_block; + System::register_extra_weight_unchecked(max_block_weight, DispatchClass::Mandatory); Gear::run(frame_support::dispatch::RawOrigin::None.into(), None).unwrap(); Gear::on_finalize(System::block_number()); diff --git a/pallets/gear-scheduler/src/tests.rs b/pallets/gear-scheduler/src/tests.rs index 14f9143f61f..6b025001248 100644 --- a/pallets/gear-scheduler/src/tests.rs +++ b/pallets/gear-scheduler/src/tests.rs @@ -51,9 +51,9 @@ fn dispatch_from(src: impl Into) -> StoredDispatch { StoredDispatch::new( DispatchKind::Handle, StoredMessage::new( - MessageId::from_origin(H256::random().into_origin()), + H256::random().cast(), src.into(), - ProgramId::from_origin(H256::random().into_origin()), + H256::random().cast(), Default::default(), 0, None, @@ -111,7 +111,7 @@ fn out_of_rent_reply_exists( mid: impl Into, pid: impl Into, ) -> bool { - let src = ProgramId::from_origin(user_id.into_origin()); + let src = user_id.cast(); let mid = mid.into(); let pid = pid.into(); diff --git a/pallets/gear-voucher/src/benchmarking.rs b/pallets/gear-voucher/src/benchmarking.rs index 38aac81bf34..06216d854ff 100644 --- a/pallets/gear-voucher/src/benchmarking.rs +++ b/pallets/gear-voucher/src/benchmarking.rs @@ -41,16 +41,16 @@ benchmarks! { 100_000_000_000_000_u128.unique_saturated_into() ); let holder = benchmarking::account::("caller", 0, 1); - let program_id = ProgramId::from_origin( - benchmarking::account::("program", 0, 100).into_origin() - ); + let program_id = + benchmarking::account::("program", 0, 100).cast() + ; let holder_lookup = T::Lookup::unlookup(holder.clone()); }: _(RawOrigin::Signed(issuer), holder_lookup, program_id, 10_000_000_000_000_u128.unique_saturated_into()) verify { - let voucher_account_id = GearVoucher::::voucher_account_id(&holder, &program_id); + let voucher_id = GearVoucher::::voucher_id(&holder, &program_id); assert_eq!( - CurrencyOf::::free_balance(&voucher_account_id), + CurrencyOf::::free_balance(&voucher_id), 10_000_000_000_000_u128.unique_saturated_into(), ); } diff --git a/pallets/gear-voucher/src/lib.rs b/pallets/gear-voucher/src/lib.rs index c3257765888..e7e7d0a2980 100644 --- a/pallets/gear-voucher/src/lib.rs +++ b/pallets/gear-voucher/src/lib.rs @@ -57,7 +57,6 @@ mod mock; #[cfg(test)] mod tests; -use common::PaymentVoucher; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement, ReservableCurrency, StorageVersion}, @@ -82,7 +81,9 @@ const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[frame_support::pallet] pub mod pallet { use super::*; + use common::storage::Mailbox; use frame_system::pallet_prelude::*; + use gear_core::message::UserStoredMessage; #[pallet::config] pub trait Config: frame_system::Config { @@ -103,6 +104,8 @@ pub mod pallet { AccountId = Self::AccountId, Balance = BalanceOf, >; + + type Mailbox: Mailbox; } #[pallet::pallet] @@ -124,8 +127,8 @@ pub mod pallet { // Gas pallet error. #[pallet::error] pub enum Error { - FailureToCreateVoucher, - FailureToRedeemVoucher, + InsufficientBalance, + InvalidVoucher, } #[pallet::hooks] @@ -158,13 +161,13 @@ pub mod pallet { let to = T::Lookup::lookup(to)?; // Generate unique account id corresponding to the pair (user, program) - let voucher_id = Self::voucher_account_id(&to, &program); + let voucher_id = Self::voucher_id(&to, &program); // Transfer funds to the keyless account T::Currency::transfer(&who, &voucher_id, value, ExistenceRequirement::KeepAlive) .map_err(|e| { log::debug!("Failed to transfer funds to the voucher account: {:?}", e); - Error::::FailureToCreateVoucher + Error::::InsufficientBalance })?; Self::deposit_event(Event::VoucherIssued { @@ -185,27 +188,33 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; - T::CallsDispatcher::dispatch(origin, call) + let sponsor = Self::sponsor_of(&origin, &call).ok_or(Error::::InvalidVoucher)?; + + T::CallsDispatcher::dispatch(origin, sponsor, call) } } -} -impl Pallet { - /// Derive a synthesized account ID from an account ID and a program ID. - pub fn voucher_account_id(who: &T::AccountId, program_id: &ProgramId) -> T::AccountId { - let entropy = (b"modlpy/voucher__", who, program_id).using_encoded(blake2_256); - Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) - .expect("infinite length input; no invalid inputs for type; qed") - } -} - -impl PaymentVoucher> for Pallet { - type VoucherId = T::AccountId; - type Error = DispatchError; + impl Pallet { + /// Derive a synthesized account ID from an account ID and a program ID. + pub fn voucher_id(who: &T::AccountId, program_id: &ProgramId) -> T::AccountId { + let entropy = (b"modlpy/voucher__", who, program_id).using_encoded(blake2_256); + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") + } - #[inline] - fn voucher_id(who: T::AccountId, program: ProgramId) -> Self::VoucherId { - Self::voucher_account_id(&who, &program) + /// Return synthesized account ID based on call data. + pub fn sponsor_of( + who: &T::AccountId, + call: &PrepaidCall>, + ) -> Option { + match call { + PrepaidCall::SendMessage { destination, .. } => { + Some(Self::voucher_id(who, destination)) + } + PrepaidCall::SendReply { reply_to_id, .. } => T::Mailbox::peek(who, reply_to_id) + .map(|stored_message| Self::voucher_id(who, &stored_message.source())), + } + } } } @@ -235,6 +244,7 @@ pub trait PrepaidCallsDispatcher { fn dispatch( account_id: Self::AccountId, + sponsor_id: Self::AccountId, call: PrepaidCall, ) -> DispatchResultWithPostInfo; } diff --git a/pallets/gear-voucher/src/mock.rs b/pallets/gear-voucher/src/mock.rs index 418dedc28bc..8224c66199d 100644 --- a/pallets/gear-voucher/src/mock.rs +++ b/pallets/gear-voucher/src/mock.rs @@ -17,10 +17,12 @@ // along with this program. If not, see . use crate as pallet_gear_voucher; +use common::storage::{Interval, Mailbox}; use frame_support::{ construct_runtime, parameter_types, weights::constants::RocksDbWeight, PalletId, }; use frame_system as system; +use gear_core::{ids::MessageId, message::UserStoredMessage}; use primitive_types::H256; use sp_runtime::{ generic, @@ -71,18 +73,50 @@ impl crate::PrepaidCallsDispatcher for () { } fn dispatch( _account_id: Self::AccountId, + _sponsor_id: Self::AccountId, _call: pallet_gear_voucher::PrepaidCall, ) -> frame_support::pallet_prelude::DispatchResultWithPostInfo { unimplemented!() } } +pub struct MailboxMock; + +impl Mailbox for MailboxMock { + type BlockNumber = (); + type Error = (); + type Key1 = AccountId; + type Key2 = MessageId; + type Value = UserStoredMessage; + type OutputError = (); + + fn clear() { + unimplemented!() + } + fn contains(_key1: &Self::Key1, _key2: &Self::Key2) -> bool { + unimplemented!() + } + fn insert(_value: Self::Value, _bn: Self::BlockNumber) -> Result<(), Self::OutputError> { + unimplemented!() + } + fn peek(_key1: &Self::Key1, _key2: &Self::Key2) -> Option { + unimplemented!() + } + fn remove( + _key1: Self::Key1, + _key2: Self::Key2, + ) -> Result<(Self::Value, Interval), Self::OutputError> { + unimplemented!() + } +} + impl pallet_gear_voucher::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type PalletId = VoucherPalletId; type WeightInfo = (); type CallsDispatcher = (); + type Mailbox = MailboxMock; } // Build genesis storage according to the mock runtime. diff --git a/pallets/gear-voucher/src/tests.rs b/pallets/gear-voucher/src/tests.rs index a46cfe97ac4..5d16c90ab5e 100644 --- a/pallets/gear-voucher/src/tests.rs +++ b/pallets/gear-voucher/src/tests.rs @@ -25,8 +25,8 @@ use primitive_types::H256; #[test] fn voucher_issue_works() { new_test_ext().execute_with(|| { - let program_id = ProgramId::from_origin(H256::from(b"some//quasy//random//program//id")); - let synthesized = Voucher::voucher_account_id(&BOB, &program_id); + let program_id = H256::from(b"some//quasy//random//program//id").cast(); + let synthesized = Voucher::voucher_id(&BOB, &program_id); assert_ok!(Voucher::issue( RuntimeOrigin::signed(ALICE), @@ -47,7 +47,7 @@ fn voucher_issue_works() { // Insufficient funds assert_noop!( Voucher::issue(RuntimeOrigin::signed(ALICE), BOB, program_id, 100_000_000,), - Error::::FailureToCreateVoucher + Error::::InsufficientBalance ); }); } @@ -55,8 +55,8 @@ fn voucher_issue_works() { #[test] fn voucher_redemption_works() { new_test_ext().execute_with(|| { - let program_id = ProgramId::from_origin(H256::from(b"some//quasy//random//program//id")); - let synthesized = Voucher::voucher_account_id(&BOB, &program_id); + let program_id = H256::from(b"some//quasy//random//program//id").cast(); + let synthesized = Voucher::voucher_id(&BOB, &program_id); assert_ok!(Voucher::issue( RuntimeOrigin::signed(ALICE), @@ -69,13 +69,13 @@ fn voucher_redemption_works() { // Redemption ok assert_ok!(Balances::reserve( - &Voucher::voucher_id(BOB, program_id), + &Voucher::voucher_id(&BOB, &program_id), 2_000 )); // Redemption fails assert_noop!( - Balances::reserve(&Voucher::voucher_id(BOB, program_id), 100_000_000), + Balances::reserve(&Voucher::voucher_id(&BOB, &program_id), 100_000_000), pallet_balances::Error::::InsufficientBalance ); }); diff --git a/pallets/gear/Cargo.toml b/pallets/gear/Cargo.toml index 749f2cb115b..b2b9c5a4c3a 100644 --- a/pallets/gear/Cargo.toml +++ b/pallets/gear/Cargo.toml @@ -110,7 +110,6 @@ demo-rwlock.workspace = true demo-reservation-manager.workspace = true demo-send-from-reservation.workspace = true demo-signal-entry.workspace = true -demo-signal-wait.workspace = true demo-state-rollback.workspace = true demo-async-signal-entry.workspace = true demo-async-custom-entry.workspace = true diff --git a/pallets/gear/rpc/src/lib.rs b/pallets/gear/rpc/src/lib.rs index 3f7b72c4bdb..7e85786071f 100644 --- a/pallets/gear/rpc/src/lib.rs +++ b/pallets/gear/rpc/src/lib.rs @@ -24,7 +24,6 @@ #![doc(html_favicon_url = "https://gear-tech.io/favicons/favicon.ico")] use gear_common::Origin; -use gear_core::ids::{CodeId, MessageId, ProgramId}; use gear_core_errors::*; use jsonrpsee::{ core::{async_trait, Error as JsonRpseeError, RpcResult}, @@ -272,7 +271,7 @@ where let GasInfo { min_limit, .. } = self.calculate_gas_info( at_hash, source, - HandleKind::InitByHash(CodeId::from_origin(code_id)), + HandleKind::InitByHash(code_id.cast()), payload.to_vec(), value, allow_other_panics, @@ -282,7 +281,7 @@ where self.calculate_gas_info( at_hash, source, - HandleKind::InitByHash(CodeId::from_origin(code_id)), + HandleKind::InitByHash(code_id.cast()), payload.to_vec(), value, allow_other_panics, @@ -336,7 +335,7 @@ where let GasInfo { min_limit, .. } = self.calculate_gas_info( at_hash, source, - HandleKind::Handle(ProgramId::from_origin(dest)), + HandleKind::Handle(dest.cast()), payload.to_vec(), value, allow_other_panics, @@ -346,7 +345,7 @@ where self.calculate_gas_info( at_hash, source, - HandleKind::Handle(ProgramId::from_origin(dest)), + HandleKind::Handle(dest.cast()), payload.to_vec(), value, allow_other_panics, @@ -369,7 +368,7 @@ where at_hash, source, HandleKind::Reply( - MessageId::from_origin(message_id), + message_id.cast(), ReplyCode::Success(SuccessReplyReason::Manual), ), payload.to_vec(), @@ -382,7 +381,7 @@ where at_hash, source, HandleKind::Reply( - MessageId::from_origin(message_id), + message_id.cast(), ReplyCode::Success(SuccessReplyReason::Manual), ), payload.to_vec(), diff --git a/pallets/gear/src/benchmarking/code.rs b/pallets/gear/src/benchmarking/code.rs index 90821ae1a37..9d4384e6377 100644 --- a/pallets/gear/src/benchmarking/code.rs +++ b/pallets/gear/src/benchmarking/code.rs @@ -236,10 +236,13 @@ where // Import supervisor functions. They start with idx 0. for name in def.imported_functions { let sign = name.signature(); - let sig = builder::signature() - .with_params(sign.params.into_iter().map(Into::into)) - .with_results(sign.results.into_iter()) - .build_sig(); + let sig_builder = + builder::signature().with_params(sign.params().iter().copied().map(Into::into)); + let results = sign + .results() + .map(|results| results.to_vec()) + .unwrap_or_default(); + let sig = sig_builder.with_results(results.into_iter()).build_sig(); let sig = program.push_signature(sig); program = program .import() diff --git a/pallets/gear/src/benchmarking/mod.rs b/pallets/gear/src/benchmarking/mod.rs index 9404a10fb28..b6d702d47bd 100644 --- a/pallets/gear/src/benchmarking/mod.rs +++ b/pallets/gear/src/benchmarking/mod.rs @@ -284,7 +284,7 @@ where RawOrigin::Signed(caller).into(), program_id, program.allocations, - CodeId::from_origin(program.code_hash), + program.code_hash.cast(), ) .expect("failed to start resume session"); @@ -470,8 +470,8 @@ benchmarks! { let program_id = benchmarking::account::("program", 0, 100); CurrencyOf::::deposit_creating(&program_id, 100_000_000_000_000_u128.unique_saturated_into()); let code = benchmarking::generate_wasm2(16.into()).unwrap(); - benchmarking::set_program::, _>(ProgramId::from_origin(program_id.clone().into_origin()), code, 1.into()); - let original_message_id = MessageId::from_origin(benchmarking::account::("message", 0, 100).into_origin()); + benchmarking::set_program::, _>(program_id.clone().cast(), code, 1.into()); + let original_message_id = benchmarking::account::("message", 0, 100).cast(); let gas_limit = 50000; let value = 10000u32.into(); let multiplier = ::GasMultiplier::get(); @@ -480,8 +480,8 @@ benchmarks! { GearBank::::deposit_value(&program_id, value, true).unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); MailboxOf::::insert(gear_core::message::StoredMessage::new( original_message_id, - ProgramId::from_origin(program_id.into_origin()), - ProgramId::from_origin(caller.clone().into_origin()), + program_id.cast(), + caller.clone().cast(), Default::default(), value.unique_saturated_into(), None, @@ -532,7 +532,7 @@ benchmarks! { .try_into() .expect("program should be active"); ProgramStorageOf::::pause_program(program_id, 100u32.into()).unwrap(); - }: _(RawOrigin::Signed(caller.clone()), program_id, program.allocations, CodeId::from_origin(program.code_hash)) + }: _(RawOrigin::Signed(caller.clone()), program_id, program.allocations, program.code_hash.cast()) verify { assert!(ProgramStorageOf::::paused_program_exists(&program_id)); assert!( @@ -696,7 +696,7 @@ benchmarks! { let caller = benchmarking::account("caller", 0, 0); CurrencyOf::::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); let minimum_balance = CurrencyOf::::minimum_balance(); - let program_id = ProgramId::from_origin(benchmarking::account::("program", 0, 100).into_origin()); + let program_id = benchmarking::account::("program", 0, 100).cast(); let code = benchmarking::generate_wasm2(16.into()).unwrap(); benchmarking::set_program::, _>(program_id, code, 1.into()); let payload = vec![0_u8; p as usize]; @@ -715,8 +715,8 @@ benchmarks! { let program_id = benchmarking::account::("program", 0, 100); CurrencyOf::::deposit_creating(&program_id, 100_000_000_000_000_u128.unique_saturated_into()); let code = benchmarking::generate_wasm2(16.into()).unwrap(); - benchmarking::set_program::, _>(ProgramId::from_origin(program_id.clone().into_origin()), code, 1.into()); - let original_message_id = MessageId::from_origin(benchmarking::account::("message", 0, 100).into_origin()); + benchmarking::set_program::, _>(program_id.clone().cast(), code, 1.into()); + let original_message_id = benchmarking::account::("message", 0, 100).cast(); let gas_limit = 50000; let value = (p % 2).into(); let multiplier = ::GasMultiplier::get(); @@ -725,8 +725,8 @@ benchmarks! { GearBank::::deposit_value(&program_id, value, true).unwrap_or_else(|e| unreachable!("Gear bank error: {e:?}")); MailboxOf::::insert(gear_core::message::StoredMessage::new( original_message_id, - ProgramId::from_origin(program_id.into_origin()), - ProgramId::from_origin(caller.clone().into_origin()), + program_id.cast(), + caller.clone().cast(), Default::default(), value.unique_saturated_into(), None, @@ -827,6 +827,28 @@ benchmarks! { verify_process(res.unwrap()); } + free_range { + let r in 0 .. API_BENCHMARK_BATCHES; + let mut res = None; + let exec = Benches::::free_range(r, 1)?; + }: { + res.replace(run_process(exec)); + } + verify { + verify_process(res.unwrap()); + } + + free_range_per_page { + let p in 1 .. API_BENCHMARK_BATCHES; + let mut res = None; + let exec = Benches::::free_range(1, p)?; + }: { + res.replace(run_process(exec)); + } + verify { + verify_process(res.unwrap()); + } + gr_reserve_gas { let r in 0 .. T::ReservationsLimit::get() as u32; let mut res = None; @@ -2830,7 +2852,7 @@ benchmarks! { let (user, message_id) = tasks::remove_from_mailbox::(); let mut ext_manager = ExtManager::::default(); }: { - ext_manager.remove_from_mailbox(T::AccountId::from_origin(user.into_origin()), message_id); + ext_manager.remove_from_mailbox(user.cast(), message_id); } tasks_pause_program { diff --git a/pallets/gear/src/benchmarking/syscalls.rs b/pallets/gear/src/benchmarking/syscalls.rs index 4e0b6484fa9..ce7e46bb90c 100644 --- a/pallets/gear/src/benchmarking/syscalls.rs +++ b/pallets/gear/src/benchmarking/syscalls.rs @@ -107,7 +107,7 @@ where let instance = Program::::new(module.into(), vec![])?; utils::prepare_exec::( instance.caller.into_origin(), - HandleKind::Handle(ProgramId::from_origin(instance.addr)), + HandleKind::Handle(instance.addr.cast()), vec![], PrepareConfig { value: value.into(), @@ -159,7 +159,7 @@ where let instance = Program::::new(module.into(), vec![])?; utils::prepare_exec::( instance.caller.into_origin(), - HandleKind::Handle(ProgramId::from_origin(instance.addr)), + HandleKind::Handle(instance.addr.cast()), vec![], PrepareConfig { value: value.into(), @@ -176,7 +176,7 @@ where let instance = Program::::new(module.into(), vec![])?; // insert gas reservation slots - let program_id = ProgramId::from_origin(instance.addr); + let program_id = instance.addr.cast(); ProgramStorageOf::::update_active_program(program_id, |program| { for x in 0..repetitions { program.gas_reservation_map.insert( @@ -205,7 +205,7 @@ where let instance = Program::::new(module.into(), vec![])?; utils::prepare_exec::( instance.caller.into_origin(), - HandleKind::Handle(ProgramId::from_origin(instance.addr)), + HandleKind::Handle(instance.addr.cast()), vec![0xff; MAX_PAYLOAD_LEN as usize], Default::default(), ) @@ -262,6 +262,43 @@ where Self::prepare_handle(module, 0) } + pub fn free_range(repetitions: u32, pages_per_call: u32) -> Result, &'static str> { + use Instruction::*; + + let n_pages = repetitions.checked_mul(pages_per_call).unwrap(); + assert!(n_pages <= max_pages::() as u32); + + let mut instructions = vec![]; + for _ in 0..API_BENCHMARK_BATCH_SIZE { + instructions.extend([I32Const(n_pages as i32), Call(0), I32Const(-1)]); + unreachable_condition(&mut instructions, I32Eq); // if alloc returns -1 then it's error + + for i in 0..repetitions { + let start = i.checked_mul(pages_per_call).unwrap(); + let end = pages_per_call + .checked_sub(1) + .and_then(|x| start.checked_add(x)) + .unwrap(); + instructions.extend([ + I32Const(start as i32), + I32Const(end as i32), + Call(1), + I32Const(0), + ]); + unreachable_condition(&mut instructions, I32Ne); + } + } + + let module = ModuleDefinition { + memory: Some(ImportedMemory::new(0)), + imported_functions: vec![SyscallName::Alloc, SyscallName::FreeRange], + handle_body: Some(body::from_instructions(instructions)), + ..Default::default() + }; + + Self::prepare_handle(module, 0) + } + pub fn gr_reserve_gas(r: u32) -> Result, &'static str> { let repetitions = r; let res_offset = COMMON_OFFSET; @@ -1348,10 +1385,10 @@ where assert!(repetitions <= 1); let params = if let Some(c) = param { - assert!(name.signature().params.len() == 1); + assert!(name.signature().params().len() == 1); vec![InstrI32Const(c)] } else { - assert!(name.signature().params.is_empty()); + assert!(name.signature().params().is_empty()); vec![] }; diff --git a/pallets/gear/src/benchmarking/tests/lazy_pages.rs b/pallets/gear/src/benchmarking/tests/lazy_pages.rs index be56fe5ad50..b324e6628ef 100644 --- a/pallets/gear/src/benchmarking/tests/lazy_pages.rs +++ b/pallets/gear/src/benchmarking/tests/lazy_pages.rs @@ -270,7 +270,7 @@ where }; let instance = Program::::new(module.into(), vec![]).unwrap(); let source = instance.caller.into_origin(); - let program_id = ProgramId::from_origin(instance.addr); + let program_id = instance.addr.cast(); // Append data in storage for some pages. for page in (0..rng.gen_range(0..MAX_PAGES_WITH_DATA)) @@ -369,7 +369,7 @@ where let instance = instance.clone(); let mut exec = common_utils::prepare_exec::( instance.caller.into_origin(), - HandleKind::Handle(ProgramId::from_origin(instance.addr)), + HandleKind::Handle(instance.addr.cast()), vec![], Default::default(), ) @@ -529,7 +529,7 @@ where let gas_burned = { let mut exec = common_utils::prepare_exec::( source, - HandleKind::Handle(ProgramId::from_origin(origin)), + HandleKind::Handle(origin.cast()), vec![], Default::default(), ) @@ -563,7 +563,7 @@ where { let mut exec = common_utils::prepare_exec::( source, - HandleKind::Handle(ProgramId::from_origin(origin)), + HandleKind::Handle(origin.cast()), vec![], PrepareConfig { gas_limit: gas_burned, @@ -601,7 +601,7 @@ where { let mut exec = common_utils::prepare_exec::( source, - HandleKind::Handle(ProgramId::from_origin(origin)), + HandleKind::Handle(origin.cast()), vec![], PrepareConfig { gas_allowance: gas_burned, diff --git a/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs b/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs index ddfb9baea37..d1895d00f92 100644 --- a/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs +++ b/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs @@ -179,8 +179,11 @@ where | SyscallName::Debug | SyscallName::Panic | SyscallName::OomPanic => {/* tests here aren't required, read module docs for more info */}, - SyscallName::Alloc => check_mem::(false), - SyscallName::Free => check_mem::(true), + + SyscallName::Alloc + | SyscallName::Free + | SyscallName::FreeRange => check_mem::(), + SyscallName::OutOfGas => { /*no need for tests */} SyscallName::Random => check_gr_random::(), SyscallName::ReserveGas => check_gr_reserve_gas::(), @@ -362,7 +365,7 @@ where let expected_mid = MessageId::generate_reply(next_user_mid); let post_test = move || { - let source = ProgramId::from_origin(default_sender.into_origin()); + let source = default_sender.cast(); assert!(SystemPallet::::events().into_iter().any(|e| { let bytes = e.event.encode(); let Ok(gear_event): Result, _> = Event::decode(&mut bytes[1..].as_ref()) else { return false }; @@ -381,7 +384,7 @@ where }); } -fn check_mem(check_free: bool) +fn check_mem() where T: Config, T::AccountId: Origin, @@ -413,23 +416,25 @@ where utils::run_to_next_block::(None); // no errors occurred + assert!(Gear::::is_initialized(pid)); + assert!(Gear::::is_active(pid)); assert!(MailboxOf::::is_empty(&default_account)); - if check_free { - Gear::::send_message( - RawOrigin::Signed(default_account.clone()).into(), - pid, - b"".to_vec(), - 50_000_000_000, - 0u128.unique_saturated_into(), - false, - ) - .expect("failed to send message to test program"); - utils::run_to_next_block::(None); + Gear::::send_message( + RawOrigin::Signed(default_account.clone()).into(), + pid, + b"".to_vec(), + 50_000_000_000, + 0u128.unique_saturated_into(), + false, + ) + .expect("failed to send message to test program"); + utils::run_to_next_block::(None); - // no errors occurred - assert!(MailboxOf::::is_empty(&default_account)); - } + // no errors occurred + assert!(Gear::::is_initialized(pid)); + assert!(Gear::::is_active(pid)); + assert!(MailboxOf::::is_empty(&default_account)); Gear::::reset(); } @@ -690,7 +695,7 @@ where let expected_mid = MessageId::generate_reply(next_user_mid); let post_test = move || { - let source = ProgramId::from_origin(default_sender.into_origin()); + let source = default_sender.cast(); assert!(SystemPallet::::events().into_iter().any(|e| { let bytes = e.event.encode(); let Ok(gear_event): Result, _> = Event::decode(&mut bytes[1..].as_ref()) else { return false }; @@ -721,7 +726,7 @@ where let message = payload.clone().into(); let post_test = move || { - let source = ProgramId::from_origin(default_sender.into_origin()); + let source = default_sender.cast(); assert!(SystemPallet::::events().into_iter().any(|e| { let bytes = e.event.encode(); let Ok(gear_event): Result, _> = Event::decode(&mut bytes[1..].as_ref()) else { return false }; @@ -748,7 +753,7 @@ where let message = payload.clone().into(); let post_test = move || { - let source = ProgramId::from_origin(default_sender.into_origin()); + let source = default_sender.cast(); assert!(SystemPallet::::events().into_iter().any(|e| { let bytes = e.event.encode(); let Ok(gear_event): Result, _> = Event::decode(&mut bytes[1..].as_ref()) else { return false }; @@ -1086,8 +1091,8 @@ where // Manually reset the storage Gear::::reset(); CurrencyOf::::slash( - &Id::from_origin(tester_pid.into_origin()), - CurrencyOf::::free_balance(&Id::from_origin(tester_pid.into_origin())), + &tester_pid.cast(), + CurrencyOf::::free_balance(&tester_pid.cast()), ); } @@ -1210,70 +1215,6 @@ where .into() } -// (module -// (import "env" "memory" (memory 1)) -// (import "env" "alloc" (func $alloc (param i32) (result i32))) -// (import "env" "free" (func $free (param i32))) -// (export "init" (func $init)) -// (export "handle" (func $handle)) -// (func $init -// ;; allocate 2 more pages with expected starting index 1 -// (block -// i32.const 0x2 -// call $alloc -// i32.const 0x1 -// i32.eq -// br_if 0 -// unreachable -// ) -// ;; put to page with index 2 (the third) some value -// (block -// i32.const 0x20001 -// i32.const 0x63 -// i32.store -// ) -// ;; put to page with index 1 (the second) some value -// (block -// i32.const 0x10001 -// i32.const 0x64 -// i32.store -// ) -// ;; check it has the value -// (block -// i32.const 0x10001 -// i32.load -// i32.const 0x65 -// i32.eq -// br_if 0 -// unreachable -// ) -// ;; remove page with index 1 (the second page) -// (block -// i32.const 0x1 -// call $free -// ) -// ) -// (func $handle -// ;; check that the second page is empty -// (block -// i32.const 0x10001 -// i32.load -// i32.const 0x0 -// i32.eq -// br_if 0 -// unreachable -// ) -// ;; check that the third page has data -// (block -// i32.const 0x20001 -// i32.load -// i32.const 0x63 -// i32.eq -// br_if 0 -// unreachable -// ) -// ) -// ) fn alloc_free_test_wasm() -> WasmModule where T::AccountId: Origin, @@ -1282,53 +1223,67 @@ where ModuleDefinition { memory: Some(ImportedMemory::new(1)), - imported_functions: vec![SyscallName::Alloc, SyscallName::Free], + imported_functions: vec![ + SyscallName::Alloc, + SyscallName::Free, + SyscallName::FreeRange, + ], init_body: Some(FuncBody::new( vec![], Instructions::new(vec![ - // ;; allocate 2 more pages with expected starting index 1 + // allocate 5 pages Instruction::Block(BlockType::NoResult), - Instruction::I32Const(0x2), + Instruction::I32Const(0x5), Instruction::Call(0), Instruction::I32Const(0x1), Instruction::I32Eq, Instruction::BrIf(0), Instruction::Unreachable, Instruction::End, - // ;; put to page with index 2 (the third) some value + // put some values in pages 2-5 Instruction::Block(BlockType::NoResult), + Instruction::I32Const(0x10001), + Instruction::I32Const(0x61), + Instruction::I32Store(2, 0), Instruction::I32Const(0x20001), + Instruction::I32Const(0x62), + Instruction::I32Store(2, 0), + Instruction::I32Const(0x30001), Instruction::I32Const(0x63), Instruction::I32Store(2, 0), - Instruction::End, - // ;; put to page with index 1 (the second) some value - Instruction::Block(BlockType::NoResult), - Instruction::I32Const(0x10001), + Instruction::I32Const(0x40001), Instruction::I32Const(0x64), Instruction::I32Store(2, 0), Instruction::End, - // ;; check it has the value + // check it has the value Instruction::Block(BlockType::NoResult), Instruction::I32Const(0x10001), Instruction::I32Load(2, 0), - Instruction::I32Const(0x64), + Instruction::I32Const(0x61), Instruction::I32Eq, Instruction::BrIf(0), Instruction::Unreachable, Instruction::End, - // ;; remove page with index 1 (the second page) + // free second page Instruction::Block(BlockType::NoResult), Instruction::I32Const(0x1), Instruction::Call(1), Instruction::Drop, Instruction::End, + // free_range pages 2-4 + Instruction::Block(BlockType::NoResult), + Instruction::I32Const(0x1), + Instruction::I32Const(0x3), + Instruction::Call(2), + Instruction::Drop, + Instruction::End, Instruction::End, ]), )), handle_body: Some(FuncBody::new( vec![], Instructions::new(vec![ - // ;; check that the second page is empty + // check that the second page is empty Instruction::Block(BlockType::NoResult), Instruction::I32Const(0x10001), Instruction::I32Load(2, 0), @@ -1337,11 +1292,20 @@ where Instruction::BrIf(0), Instruction::Unreachable, Instruction::End, - // ;; check that the third page has data + // check that the 3rd page is empty Instruction::Block(BlockType::NoResult), Instruction::I32Const(0x20001), Instruction::I32Load(2, 0), - Instruction::I32Const(0x63), + Instruction::I32Const(0x0), + Instruction::I32Eq, + Instruction::BrIf(0), + Instruction::Unreachable, + Instruction::End, + // check that the 5th page still has data + Instruction::Block(BlockType::NoResult), + Instruction::I32Const(0x40001), + Instruction::I32Load(2, 0), + Instruction::I32Const(0x64), Instruction::I32Eq, Instruction::BrIf(0), Instruction::Unreachable, diff --git a/pallets/gear/src/benchmarking/utils.rs b/pallets/gear/src/benchmarking/utils.rs index 7bf78a1fa5c..e17a4e5c9f1 100644 --- a/pallets/gear/src/benchmarking/utils.rs +++ b/pallets/gear/src/benchmarking/utils.rs @@ -157,7 +157,7 @@ where DispatchKind::Init, Message::new( root_message_id, - ProgramId::from_origin(source), + source.cast(), program_id, payload.try_into()?, Some(u64::MAX), @@ -183,7 +183,7 @@ where DispatchKind::Init, Message::new( root_message_id, - ProgramId::from_origin(source), + source.cast(), program_id, payload.try_into()?, Some(u64::MAX), @@ -196,7 +196,7 @@ where DispatchKind::Handle, Message::new( root_message_id, - ProgramId::from_origin(source), + source.cast(), dest, payload.try_into()?, Some(u64::MAX), @@ -205,14 +205,13 @@ where ), ), HandleKind::Reply(msg_id, exit_code) => { - let (msg, _bn) = - MailboxOf::::remove(::from_origin(source), msg_id) - .map_err(|_| "Internal error: unable to find message in mailbox")?; + let (msg, _bn) = MailboxOf::::remove(source.cast(), msg_id) + .map_err(|_| "Internal error: unable to find message in mailbox")?; Dispatch::new( DispatchKind::Reply, Message::new( root_message_id, - ProgramId::from_origin(source), + source.cast(), msg.source(), payload.try_into()?, Some(u64::MAX), @@ -222,14 +221,13 @@ where ) } HandleKind::Signal(msg_id, status_code) => { - let (msg, _bn) = - MailboxOf::::remove(::from_origin(source), msg_id) - .map_err(|_| "Internal error: unable to find message in mailbox")?; + let (msg, _bn) = MailboxOf::::remove(source.cast(), msg_id) + .map_err(|_| "Internal error: unable to find message in mailbox")?; Dispatch::new( DispatchKind::Signal, Message::new( root_message_id, - ProgramId::from_origin(source), + source.cast(), msg.source(), payload.try_into()?, Some(u64::MAX), diff --git a/pallets/gear/src/internal.rs b/pallets/gear/src/internal.rs index 7a25243946f..af4cc41d665 100644 --- a/pallets/gear/src/internal.rs +++ b/pallets/gear/src/internal.rs @@ -466,8 +466,8 @@ where Self::consume_and_retrieve(mailboxed.id()); // Taking data for funds transfer. - let user_id = ::from_origin(mailboxed.destination().into_origin()); - let from = ::from_origin(mailboxed.source().into_origin()); + let user_id = mailboxed.destination().cast(); + let from = mailboxed.source().cast(); // Transferring reserved funds, associated with the message. GearBank::::transfer_value(&from, &user_id, mailboxed.value().unique_saturated_into()) @@ -528,7 +528,7 @@ where .unwrap_or_else(|| origin_msg.into()); // Taking data for funds manipulations. - let from = ::from_origin(dispatch.source().into_origin()); + let from = dispatch.source().cast(); let value = dispatch.value().unique_saturated_into(); // `HoldBound` builder. @@ -731,8 +731,8 @@ where .unwrap_or_else(|_| unreachable!("Signal message sent to user")); // Taking data for funds manipulations. - let from = ::from_origin(message.source().into_origin()); - let to = ::from_origin(message.destination().into_origin()); + let from = message.source().cast(); + let to = message.destination().cast(); let value = message.value().unique_saturated_into(); // If gas limit can cover threshold, message will be added to mailbox, @@ -842,8 +842,8 @@ where }; // Taking data for funds manipulations. - let from = ::from_origin(message.source().into_origin()); - let to = ::from_origin(message.destination().into_origin()); + let from = message.source().cast(); + let to = message.destination().cast(); let value = message.value().unique_saturated_into(); // If gas limit can cover threshold, message will be added to mailbox, diff --git a/pallets/gear/src/lib.rs b/pallets/gear/src/lib.rs index cc45e3009b5..df588801d72 100644 --- a/pallets/gear/src/lib.rs +++ b/pallets/gear/src/lib.rs @@ -59,7 +59,7 @@ use alloc::{format, string::String}; use common::{ self, event::*, gas_provider::GasNodeId, paused_program_storage::SessionId, scheduler::*, storage::*, BlockLimiter, CodeMetadata, CodeStorage, GasProvider, GasTree, Origin, - PausedProgramStorage, PaymentVoucher, Program, ProgramState, ProgramStorage, QueueRunner, + PausedProgramStorage, Program, ProgramState, ProgramStorage, QueueRunner, }; use core::marker::PhantomData; use core_processor::{ @@ -124,7 +124,6 @@ pub type RentFreePeriodOf = ::ProgramRentFreePeriod; pub type RentCostPerBlockOf = ::ProgramRentCostPerBlock; pub type ResumeMinimalPeriodOf = ::ProgramResumeMinimalRentPeriod; pub type ResumeSessionDurationOf = ::ProgramResumeSessionDuration; -pub(crate) type VoucherOf = ::Voucher; pub(crate) type GearBank = pallet_gear_bank::Pallet; /// The current storage version. @@ -245,14 +244,6 @@ pub mod pallet { /// Message Queue processing routing provider. type QueueRunner: QueueRunner>; - /// Type that allows to check caller's eligibility for using voucher for payment. - type Voucher: PaymentVoucher< - Self::AccountId, - ProgramId, - BalanceOf, - VoucherId = Self::AccountId, - >; - /// The free of charge period of rent. #[pallet::constant] type ProgramRentFreePeriod: Get>; @@ -455,8 +446,6 @@ pub mod pallet { ResumePeriodLessThanMinimal, /// Program with the specified id is not found. ProgramNotFound, - /// Voucher can't be redeemed - FailureRedeemingVoucher, /// Gear::run() already included in current block. GearRunAlreadyInBlock, /// The program rent logic is disabled. @@ -637,9 +626,7 @@ pub mod pallet { ); let message = InitMessage::from_packet(message_id, packet); - let dispatch = message - .into_dispatch(ProgramId::from_origin(origin)) - .into_stored(); + let dispatch = message.into_dispatch(origin.cast()).into_stored(); QueueOf::::queue(dispatch) .unwrap_or_else(|e| unreachable!("Messages storage corrupted: {e:?}")); @@ -686,13 +673,11 @@ pub mod pallet { argument: Option>, gas_allowance: Option, ) -> Result, Vec> { - let program_id = ProgramId::from_origin(program_id.into_origin()); - let fn_name = String::from_utf8(fn_name) .map_err(|_| "Non-utf8 function name".as_bytes().to_vec())?; Self::read_state_using_wasm_impl( - program_id, + program_id.cast(), payload, fn_name, wasm, @@ -707,18 +692,15 @@ pub mod pallet { payload: Vec, gas_allowance: Option, ) -> Result, Vec> { - let program_id = ProgramId::from_origin(program_id.into_origin()); - - Self::read_state_impl(program_id, payload, gas_allowance).map_err(String::into_bytes) + Self::read_state_impl(program_id.cast(), payload, gas_allowance) + .map_err(String::into_bytes) } pub fn read_metahash( program_id: H256, gas_allowance: Option, ) -> Result> { - let program_id = ProgramId::from_origin(program_id.into_origin()); - - Self::read_metahash_impl(program_id, gas_allowance).map_err(String::into_bytes) + Self::read_metahash_impl(program_id.cast(), gas_allowance).map_err(String::into_bytes) } #[cfg(not(test))] @@ -900,9 +882,8 @@ pub mod pallet { let nonce = SentOf::::get(); SentOf::::increase(); let block_number = >::block_number().unique_saturated_into(); - let user_id = ProgramId::from_origin(user_id); - MessageId::generate_from_user(block_number, user_id, nonce.into()) + MessageId::generate_from_user(block_number, user_id.cast(), nonce.into()) } /// Delayed tasks processing. @@ -1245,9 +1226,7 @@ pub mod pallet { ); let message = InitMessage::from_packet(message_id, packet); - let dispatch = message - .into_dispatch(ProgramId::from_origin(origin)) - .into_stored(); + let dispatch = message.into_dispatch(origin.cast()).into_stored(); let event = Event::MessageQueued { id: dispatch.id(), @@ -1495,8 +1474,8 @@ pub mod pallet { payload, gas_limit, value, - false, keep_alive, + None, ) } @@ -1532,8 +1511,8 @@ pub mod pallet { payload, gas_limit, value, - false, keep_alive, + None, ) } @@ -1568,11 +1547,8 @@ pub mod pallet { Self::create(origin.clone(), message.id(), 0, true); // Converting reply message into appropriate type for queueing. - let dispatch = message.into_stored_dispatch( - ProgramId::from_origin(origin.into_origin()), - mailboxed.source(), - mailboxed.id(), - ); + let dispatch = + message.into_stored_dispatch(origin.cast(), mailboxed.source(), mailboxed.id()); // Queueing dispatch. QueueOf::::queue(dispatch) @@ -1584,7 +1560,7 @@ pub mod pallet { /// Process message queue #[pallet::call_index(6)] - #[pallet::weight((Weight::zero(), DispatchClass::Mandatory))] + #[pallet::weight((::BlockWeights::get().max_block, DispatchClass::Mandatory))] pub fn run( origin: OriginFor, max_gas: Option>, @@ -1605,9 +1581,13 @@ pub mod pallet { // overlay and never be committed to storage. GearRunInBlock::::set(Some(())); - let weight_used = >::block_weight(); let max_weight = ::BlockWeights::get().max_block; - let remaining_weight = max_weight.saturating_sub(weight_used.total()); + + // Subtract extrinsic weight from the current block weight to get used weight in the current block. + let weight_used = >::block_weight() + .total() + .saturating_sub(max_weight); + let remaining_weight = max_weight.saturating_sub(weight_used); // Remaining weight may exceed the minimum block gas limit set by the Limiter trait. let mut adjusted_gas = GasAllowanceOf::::get().max(remaining_weight.ref_time()); @@ -1832,8 +1812,8 @@ pub mod pallet { payload: Vec, gas_limit: u64, value: BalanceOf, - prepaid: bool, keep_alive: bool, + gas_sponsor: Option>, ) -> DispatchResultWithPostInfo { let payload = payload .try_into() @@ -1864,29 +1844,13 @@ pub mod pallet { // a voucher exists. The latter can only be used to pay for gas or transaction fee. GearBank::::deposit_value(&who, value, keep_alive)?; - let external_node = if prepaid { - // If voucher is used, we attempt to reserve funds on the respective account. - // If no such voucher exists, the call is invalidated. - let voucher_id = VoucherOf::::voucher_id(who.clone(), destination); + // If voucher or any other prepaid mechanism is not used, + // gas limit is taken from user's account. + let gas_sponsor = gas_sponsor.unwrap_or_else(|| who.clone()); + GearBank::::deposit_gas(&gas_sponsor, gas_limit, keep_alive)?; + Self::create(gas_sponsor, message.id(), gas_limit, false); - GearBank::::deposit_gas(&voucher_id, gas_limit, keep_alive).map_err(|e| { - log::debug!( - "Failed to redeem voucher for user {who:?} and program {destination:?}: {e:?}" - ); - Error::::FailureRedeemingVoucher - })?; - - voucher_id - } else { - // If voucher is not used, we reserve gas limit on the user's account. - GearBank::::deposit_gas(&who, gas_limit, keep_alive)?; - - who.clone() - }; - - Self::create(external_node, message.id(), gas_limit, false); - - let message = message.into_stored_dispatch(ProgramId::from_origin(origin)); + let message = message.into_stored_dispatch(origin.cast()); Self::deposit_event(Event::MessageQueued { id: message.id(), @@ -1898,7 +1862,7 @@ pub mod pallet { QueueOf::::queue(message) .unwrap_or_else(|e| unreachable!("Messages storage corrupted: {e:?}")); } else { - let message = message.into_stored(ProgramId::from_origin(origin)); + let message = message.into_stored(origin.cast()); let message: UserMessage = message .try_into() .unwrap_or_else(|_| unreachable!("Signal message sent to user")); @@ -1911,9 +1875,7 @@ pub mod pallet { CurrencyOf::::transfer( &who, - &::AccountId::from_origin( - message.destination().into_origin(), - ), + &message.destination().cast(), value.unique_saturated_into(), existence_requirement, )?; @@ -1934,8 +1896,8 @@ pub mod pallet { payload: Vec, gas_limit: u64, value: BalanceOf, - prepaid: bool, keep_alive: bool, + gas_sponsor: Option>, ) -> DispatchResultWithPostInfo { let payload = payload .try_into() @@ -1966,28 +1928,11 @@ pub mod pallet { GearBank::::deposit_value(&origin, value, keep_alive)?; - let external_node = if prepaid { - // If voucher is used, we attempt to reserve funds on the respective account. - // If no such voucher exists, the call is invalidated. - let voucher_id = VoucherOf::::voucher_id(origin.clone(), destination); - - GearBank::::deposit_gas(&voucher_id, gas_limit, keep_alive).map_err(|e| { - log::debug!( - "Failed to redeem voucher for user {origin:?} and program {destination:?}: {e:?}" - ); - Error::::FailureRedeemingVoucher - })?; - - voucher_id - } else { - // If voucher is not used, we reserve gas limit on the user's account. - GearBank::::deposit_gas(&origin, gas_limit, keep_alive)?; - - origin.clone() - }; - - // Following up with a gas node creation. - Self::create(external_node, reply_id, gas_limit, true); + // If voucher or any other prepaid mechanism is not used, + // gas limit is taken from user's account. + let gas_sponsor = gas_sponsor.unwrap_or_else(|| origin.clone()); + GearBank::::deposit_gas(&gas_sponsor, gas_limit, keep_alive)?; + Self::create(gas_sponsor, reply_id, gas_limit, true); // Creating reply message. let message = ReplyMessage::from_packet( @@ -1996,11 +1941,8 @@ pub mod pallet { ); // Converting reply message into appropriate type for queueing. - let dispatch = message.into_stored_dispatch( - ProgramId::from_origin(origin.clone().into_origin()), - destination, - mailboxed.id(), - ); + let dispatch = + message.into_stored_dispatch(origin.clone().cast(), destination, mailboxed.id()); // Pre-generating appropriate event to avoid dispatch cloning. let event = Event::MessageQueued { @@ -2041,6 +1983,7 @@ pub mod pallet { fn dispatch( account_id: Self::AccountId, + sponsor_id: Self::AccountId, call: PrepaidCall, ) -> DispatchResultWithPostInfo { match call { @@ -2056,8 +1999,8 @@ pub mod pallet { payload, gas_limit, value, - true, keep_alive, + Some(sponsor_id), ), PrepaidCall::SendReply { reply_to_id, @@ -2071,8 +2014,8 @@ pub mod pallet { payload, gas_limit, value, - true, keep_alive, + Some(sponsor_id), ), } } diff --git a/pallets/gear/src/manager/journal.rs b/pallets/gear/src/manager/journal.rs index 79a60a0f110..6bbd2c5f566 100644 --- a/pallets/gear/src/manager/journal.rs +++ b/pallets/gear/src/manager/journal.rs @@ -230,7 +230,7 @@ where if dispatch.value() != 0 { GearBank::::deposit_value( - &::from_origin(dispatch.source().into_origin()), + &dispatch.source().cast(), dispatch.value().unique_saturated_into(), false, ) @@ -375,9 +375,8 @@ where } fn send_value(&mut self, from: ProgramId, to: Option, value: u128) { - let to = Pallet::::inheritor_for(to.unwrap_or(from)); - let to = ::from_origin(to.into_origin()); - let from = ::from_origin(from.into_origin()); + let to = Pallet::::inheritor_for(to.unwrap_or(from)).cast(); + let from = from.cast(); let value = value.unique_saturated_into(); GearBank::::transfer_value(&from, &to, value) @@ -539,7 +538,7 @@ where } fn pay_program_rent(&mut self, payer: ProgramId, program_id: ProgramId, block_count: u32) { - let from = ::from_origin(payer.into_origin()); + let from = payer.cast(); let block_count = block_count.unique_saturated_into(); ProgramStorageOf::::update_active_program(program_id, |program| { diff --git a/pallets/gear/src/manager/mod.rs b/pallets/gear/src/manager/mod.rs index 4973d70a7f6..b18ce498ce3 100644 --- a/pallets/gear/src/manager/mod.rs +++ b/pallets/gear/src/manager/mod.rs @@ -223,11 +223,9 @@ where /// program with `id` doesn't exist or it's terminated pub fn get_actor(&self, id: ProgramId) -> Option { let active: ActiveProgram<_> = ProgramStorageOf::::get_program(id)?.try_into().ok()?; - let code_id = CodeId::from_origin(active.code_hash); + let code_id = active.code_hash.cast(); - let balance = - CurrencyOf::::free_balance(&::from_origin(id.into_origin())) - .unique_saturated_into(); + let balance = CurrencyOf::::free_balance(&id.cast()).unique_saturated_into(); Some(Actor { balance, @@ -257,7 +255,7 @@ where // // Code can exist without program, but the latter can't exist without code. debug_assert!( - T::CodeStorage::exists(CodeId::from_origin(code_info.id)), + T::CodeStorage::exists(code_info.id.cast()), "Program set must be called only when code exists", ); @@ -377,14 +375,13 @@ where ) { ProgramStorageOf::::remove_program_pages(program_id, memory_infix); - let program_account = &::from_origin(program_id.into_origin()); - let balance = CurrencyOf::::free_balance(program_account); + let program_account = program_id.cast(); + let balance = CurrencyOf::::free_balance(&program_account); if !balance.is_zero() { - let destination = Pallet::::inheritor_for(value_destination); - let destination = ::from_origin(destination.into_origin()); + let destination = Pallet::::inheritor_for(value_destination).cast(); CurrencyOf::::transfer( - program_account, + &program_account, &destination, balance, ExistenceRequirement::AllowDeath, diff --git a/pallets/gear/src/mock.rs b/pallets/gear/src/mock.rs index 84d3a630975..107358b2c0c 100644 --- a/pallets/gear/src/mock.rs +++ b/pallets/gear/src/mock.rs @@ -93,7 +93,7 @@ pallet_gear_program::impl_config!(Test); pallet_gear_messenger::impl_config!(Test, CurrentBlockNumber = Gear); pallet_gear_scheduler::impl_config!(Test); pallet_gear_bank::impl_config!(Test); -pallet_gear::impl_config!(Test, Schedule = DynamicSchedule, Voucher = GearVoucher); +pallet_gear::impl_config!(Test, Schedule = DynamicSchedule); pallet_gear_gas::impl_config!(Test); common::impl_pallet_balances!(Test); common::impl_pallet_authorship!(Test); @@ -174,6 +174,7 @@ impl pallet_gear_voucher::Config for Test { type PalletId = VoucherPalletId; type WeightInfo = (); type CallsDispatcher = Gear; + type Mailbox = MailboxOf; } // Build genesis storage according to the mock runtime. @@ -259,6 +260,10 @@ pub fn run_to_block_maybe_with_queue( QueueProcessingOf::::deny(); } + // Spend the maximum weight of the block to account for the weight of Gear::run() in the current block. + let max_block_weight = as Get>::get().max_block; + System::register_extra_weight_unchecked(max_block_weight, DispatchClass::Mandatory); + Gear::run(frame_support::dispatch::RawOrigin::None.into(), None).unwrap(); } diff --git a/pallets/gear/src/pallet_tests.rs b/pallets/gear/src/pallet_tests.rs index 7cd98cb72c7..ccc6d78ece6 100644 --- a/pallets/gear/src/pallet_tests.rs +++ b/pallets/gear/src/pallet_tests.rs @@ -56,7 +56,6 @@ macro_rules! impl_config_inner { type BlockLimiter = GearGas; type Scheduler = GearScheduler; type QueueRunner = Gear; - type Voucher = GearConfigVoucher; type ProgramRentFreePeriod = RentFreePeriod; type ProgramResumeMinimalRentPeriod = ResumeMinimalPeriod; type ProgramRentCostPerBlock = RentCostPerBlock; @@ -72,12 +71,6 @@ macro_rules! impl_config_inner { $crate::impl_config_inner!($runtime, $($( $rest )*)?); }; - ($runtime:ty, Voucher = $voucher:ty $(, $( $rest:tt )*)?) => { - type GearConfigVoucher = $voucher; - - $crate::impl_config_inner!($runtime, $($( $rest )*)?); - }; - ($runtime:ty, DebugInfo = $debug_info:ty $(, $( $rest:tt )*)?) => { type GearConfigDebugInfo = $debug_info; diff --git a/pallets/gear/src/queue.rs b/pallets/gear/src/queue.rs index 5cb06f554c7..9f23ea851ad 100644 --- a/pallets/gear/src/queue.rs +++ b/pallets/gear/src/queue.rs @@ -202,9 +202,7 @@ where let dispatch_id = dispatch.id(); let dispatch_reply = dispatch.reply_details().is_some(); - let balance = CurrencyOf::::free_balance(&::from_origin( - program_id.into_origin(), - )); + let balance = CurrencyOf::::free_balance(&program_id.cast()); let get_actor_data = |precharged_dispatch: PrechargedDispatch| { // At this point gas counters should be changed accordingly so fetch the program data. @@ -296,7 +294,7 @@ where ActorResult::Data(Some(ExecutableActorData { allocations: program.allocations, - code_id: CodeId::from_origin(program.code_hash), + code_id: program.code_hash.cast(), code_exports: program.code_exports, static_pages: program.static_pages, initialized: matches!(program.state, ProgramState::Initialized), diff --git a/pallets/gear/src/runtime_api.rs b/pallets/gear/src/runtime_api.rs index 8885c6d44ff..e92627c7845 100644 --- a/pallets/gear/src/runtime_api.rs +++ b/pallets/gear/src/runtime_api.rs @@ -56,7 +56,7 @@ where ) -> Result> { Self::enable_lazy_pages(); - let account = ::from_origin(source); + let account = source.cast(); let balance = CurrencyOf::::free_balance(&account); let max_balance: BalanceOf = ::GasMultiplier::get() @@ -150,9 +150,7 @@ where let dispatch_id = queued_dispatch.id(); let dispatch_reply = queued_dispatch.reply_details().is_some(); - let balance = CurrencyOf::::free_balance(&::from_origin( - actor_id.into_origin(), - )); + let balance = CurrencyOf::::free_balance(&actor_id.cast()); let get_actor_data = |precharged_dispatch: PrechargedDispatch| { // At this point gas counters should be changed accordingly so fetch the program data. @@ -219,8 +217,8 @@ where match note { JournalNote::SendDispatch { dispatch, .. } => { - let destination = - T::AccountId::from_origin(dispatch.destination().into_origin()); + let destination = dispatch.destination().cast(); + if MailboxOf::::contains(&destination, &dispatch.id()) && from_main_chain(dispatch.id())? { @@ -275,8 +273,7 @@ where let program = ActiveProgram::try_from(program) .map_err(|e| format!("Get active program error: {e:?}"))?; - let code_id = CodeId::from_origin(program.code_hash); - let instrumented_code = T::CodeStorage::get_code(code_id) + let instrumented_code = T::CodeStorage::get_code(program.code_hash.cast()) .ok_or_else(|| String::from("Failed to get code for given program id"))?; Ok(CodeWithMemoryData { diff --git a/pallets/gear/src/schedule.rs b/pallets/gear/src/schedule.rs index 5e86704f868..737251e29d2 100644 --- a/pallets/gear/src/schedule.rs +++ b/pallets/gear/src/schedule.rs @@ -344,6 +344,12 @@ pub struct HostFnWeights { /// Weight of calling `free`. pub free: Weight, + /// Weight of calling `free_range`. + pub free_range: Weight, + + /// Weight of calling `free_range` per page. + pub free_range_per_page: Weight, + /// Weight of calling `gr_reserve_gas`. pub gr_reserve_gas: Weight, @@ -857,6 +863,8 @@ impl HostFnWeights { alloc: self.alloc.ref_time(), alloc_per_page: self.alloc_per_page.ref_time(), free: self.free.ref_time(), + free_range: self.free_range.ref_time(), + free_range_per_page: self.free_range_per_page.ref_time(), gr_reserve_gas: self.gr_reserve_gas.ref_time(), gr_unreserve_gas: self.gr_unreserve_gas.ref_time(), gr_system_reserve_gas: self.gr_system_reserve_gas.ref_time(), @@ -979,6 +987,8 @@ impl Default for HostFnWeights { .saturating_sub(to_weight!(cost_batched!(mem_grow))), alloc_per_page: to_weight!(cost_batched!(alloc_per_page)), free: to_weight!(cost_batched!(free)), + free_range: to_weight!(cost_batched!(free_range)), + free_range_per_page: to_weight!(cost_batched!(free_range_per_page)), gr_reserve_gas: to_weight!(cost!(gr_reserve_gas)), gr_system_reserve_gas: to_weight!(cost_batched!(gr_system_reserve_gas)), gr_unreserve_gas: to_weight!(cost!(gr_unreserve_gas)), diff --git a/pallets/gear/src/tests.rs b/pallets/gear/src/tests.rs index b407aecaec4..dbb959bd840 100644 --- a/pallets/gear/src/tests.rs +++ b/pallets/gear/src/tests.rs @@ -2637,11 +2637,8 @@ fn mailbox_rent_out_of_rent() { let user_2_balance = Balances::free_balance(USER_2); assert_eq!(GearBank::::account_total(&USER_2), 0); - let prog_balance = Balances::free_balance(AccountId::from_origin(sender.into_origin())); - assert_eq!( - GearBank::::account_total(&AccountId::from_origin(sender.into_origin())), - 0 - ); + let prog_balance = Balances::free_balance(sender.cast::()); + assert_eq!(GearBank::::account_total(&sender.cast()), 0); let (_, gas_info) = utils::calculate_handle_and_send_with_extra( USER_1, @@ -2731,16 +2728,12 @@ fn mailbox_rent_claimed() { let user_2_balance = Balances::free_balance(USER_2); assert_eq!(GearBank::::account_total(&USER_2), 0); - - let prog_balance = Balances::free_balance(AccountId::from_origin(sender.into_origin())); - assert_eq!( - GearBank::::account_total(&AccountId::from_origin(sender.into_origin())), - 0 - ); + let prog_balance = Balances::free_balance(sender.cast::()); + assert_eq!(GearBank::::account_total(&sender.cast()), 0); let (_, gas_info) = utils::calculate_handle_and_send_with_extra( USER_1, - sender, + sender.cast(), data.request(USER_2.into_origin()).encode(), Some(data.extra_gas), 0, @@ -2821,11 +2814,8 @@ fn mailbox_sending_instant_transfer() { let user_2_balance = Balances::free_balance(USER_2); assert_eq!(GearBank::::account_total(&USER_2), 0); - let prog_balance = Balances::free_balance(AccountId::from_origin(sender.into_origin())); - assert_eq!( - GearBank::::account_total(&AccountId::from_origin(sender.into_origin())), - 0 - ); + let prog_balance = Balances::free_balance(sender.cast::()); + assert_eq!(GearBank::::account_total(&sender.cast()), 0); let payload = if let Some(gas_limit) = gas_limit { TestData::gasful(gas_limit, value) @@ -3020,7 +3010,7 @@ fn mailbox_threshold_works() { let check_result = |sufficient: bool| -> MessageId { run_to_next_block(None); - let mailbox_key = AccountId::from_origin(USER_1.into_origin()); + let mailbox_key = USER_1.cast(); let message_id = get_last_message_id(); if sufficient { @@ -4385,7 +4375,7 @@ fn send_reply_works() { // Top up program's account balance by 2000 to allow user claim 1000 from mailbox assert_ok!(>::transfer( &USER_1, - &AccountId::from_origin(prog_id.into_origin()), + &prog_id.cast(), 2000, frame_support::traits::ExistenceRequirement::AllowDeath )); @@ -4428,7 +4418,7 @@ fn send_reply_failure_to_claim_from_mailbox() { assert_noop!( Gear::send_reply( RuntimeOrigin::signed(USER_1), - MessageId::from_origin(5.into_origin()), // non existent `reply_to_id` + 5.cast(), // non existent `reply_to_id` EMPTY_PAYLOAD.to_vec(), DEFAULT_GAS_LIMIT, 0, @@ -4476,7 +4466,7 @@ fn send_reply_value_claiming_works() { let send_to_program_amount = locked_value * 2; assert_ok!(>::transfer( &USER_1, - &AccountId::from_origin(prog_id.into_origin()), + &prog_id.cast(), send_to_program_amount, frame_support::traits::ExistenceRequirement::AllowDeath )); @@ -4762,8 +4752,7 @@ fn test_code_submission_pass() { init_logger(); new_test_ext().execute_with(|| { let code = ProgramCodeKind::Default.to_bytes(); - let code_hash = generate_code_hash(&code).into(); - let code_id = CodeId::from_origin(code_hash); + let code_id = CodeId::generate(&code); assert_ok!(Gear::upload_code( RuntimeOrigin::signed(USER_1), @@ -4827,7 +4816,7 @@ fn test_code_is_not_submitted_twice_after_program_submission() { init_logger(); new_test_ext().execute_with(|| { let code = ProgramCodeKind::Default.to_bytes(); - let code_id = generate_code_hash(&code).into(); + let code_id = CodeId::generate(&code); // First submit program, which will set code and metadata assert_ok!(Gear::upload_program( @@ -4865,8 +4854,7 @@ fn test_code_is_not_reset_within_program_submission() { init_logger(); new_test_ext().execute_with(|| { let code = ProgramCodeKind::Default.to_bytes(); - let code_hash = generate_code_hash(&code).into(); - let code_id = CodeId::from_origin(code_hash); + let code_id = CodeId::generate(&code); // First submit code assert_ok!(Gear::upload_code( @@ -6992,7 +6980,7 @@ fn resume_program_works() { RuntimeOrigin::signed(USER_1), program_id, program.allocations.clone(), - CodeId::from_origin(program.code_hash), + program.code_hash.cast(), )); assert_ne!( old_nonce, @@ -7003,7 +6991,7 @@ fn resume_program_works() { RuntimeOrigin::signed(USER_3), program_id, program.allocations.clone(), - CodeId::from_origin(program.code_hash), + program.code_hash.cast(), )); let (session_id, session_end_block, ..) = get_last_session(); @@ -7013,7 +7001,7 @@ fn resume_program_works() { RuntimeOrigin::signed(USER_2), program_id, program.allocations, - CodeId::from_origin(program.code_hash), + program.code_hash.cast(), )); let (session_id_2, session_end_block_2, ..) = get_last_session(); @@ -7386,7 +7374,7 @@ fn pay_program_rent_syscall_works() { ); // attempt to pay rent for not existing program - let pay_rent_account_id = AccountId::from_origin(pay_rent_id.into_origin()); + let pay_rent_account_id = pay_rent_id.cast::(); let balance_before = Balances::free_balance(pay_rent_account_id); assert_ok!(Gear::send_message( @@ -8319,12 +8307,12 @@ fn gas_spent_precalculated() { run_to_block(2, None); let get_program_code = |pid| { - let code_id = CodeId::from_origin( - ProgramStorageOf::::get_program(pid) - .and_then(|program| common::ActiveProgram::try_from(program).ok()) - .expect("program must exist") - .code_hash, - ); + let code_id = ProgramStorageOf::::get_program(pid) + .and_then(|program| common::ActiveProgram::try_from(program).ok()) + .expect("program must exist") + .code_hash + .cast(); + ::CodeStorage::get_code(code_id).unwrap() }; @@ -8570,8 +8558,7 @@ fn test_create_program_with_value_lt_ed() { // programs deployed by user and by program assert_init_success(2); - let origin_msg_id = - MessageId::generate_from_user(1, ProgramId::from_origin(USER_1.into_origin()), 0); + let origin_msg_id = MessageId::generate_from_user(1, USER_1.cast(), 0); let msg1_mailbox = MessageId::generate_outgoing(origin_msg_id, 0); let msg2_mailbox = MessageId::generate_outgoing(origin_msg_id, 1); assert!(MailboxOf::::contains(&msg_receiver_1, &msg1_mailbox)); @@ -9173,11 +9160,8 @@ fn free_storage_hold_on_scheduler_overwhelm() { let user_2_balance = Balances::free_balance(USER_2); assert_eq!(GearBank::::account_total(&USER_2), 0); - let prog_balance = Balances::free_balance(AccountId::from_origin(sender.into_origin())); - assert_eq!( - GearBank::::account_total(&AccountId::from_origin(sender.into_origin())), - 0 - ); + let prog_balance = Balances::free_balance(sender.cast::()); + assert_eq!(GearBank::::account_total(&sender.cast()), 0); let (_, gas_info) = utils::calculate_handle_and_send_with_extra( USER_1, @@ -10469,7 +10453,7 @@ fn missing_functions_are_not_executed() { let locked_value = 1_000; assert_ok!(>::transfer( &USER_1, - &AccountId::from_origin(program_id.into_origin()), + &program_id.cast(), locked_value, frame_support::traits::ExistenceRequirement::AllowDeath )); @@ -13978,6 +13962,160 @@ fn free_usage_error() { }); } +#[test] +fn free_range_oob_error() { + const WAT: &str = r#" +(module + (import "env" "memory" (memory 1)) + (import "env" "free_range" (func $free_range (param i32) (param i32) (result i32))) + (export "init" (func $init)) + (func $init + ;; free impossible and non-existing range + i32.const 0x0 + i32.const 0xffffff + call $free_range + i32.const 0x0 + i32.ne + if + unreachable + end + ) +) + "#; + + init_logger(); + new_test_ext().execute_with(|| { + let pid = Gear::upload_program( + RuntimeOrigin::signed(USER_1), + ProgramCodeKind::Custom(WAT).to_bytes(), + DEFAULT_SALT.to_vec(), + EMPTY_PAYLOAD.to_vec(), + 10_000_000_000_u64, + 0, + false, + ) + .map(|_| get_last_program_id()) + .unwrap(); + let mid = get_last_message_id(); + + run_to_next_block(None); + + assert!(Gear::is_terminated(pid)); + assert_failed( + mid, + ActorExecutionErrorReplyReason::Trap(TrapExplanation::Unknown), + ); + }); +} + +#[test] +fn free_range_invalid_range_error() { + const WAT: &str = r#" +(module + (import "env" "memory" (memory 1)) + (import "env" "free_range" (func $free_range (param i32) (param i32) (result i32))) + (export "init" (func $init)) + (func $init + ;; free invalid range (start > end) + i32.const 0x55 + i32.const 0x2 + call $free_range + i32.const 0x1 ;; we expect an error + i32.ne + if + unreachable + end + ) +) + "#; + + init_logger(); + new_test_ext().execute_with(|| { + let pid = Gear::upload_program( + RuntimeOrigin::signed(USER_1), + ProgramCodeKind::Custom(WAT).to_bytes(), + DEFAULT_SALT.to_vec(), + EMPTY_PAYLOAD.to_vec(), + 500_000_000_u64, + 0, + false, + ) + .map(|_| get_last_program_id()) + .unwrap(); + let mid = get_last_message_id(); + + run_to_next_block(None); + assert!(!Gear::is_terminated(pid)); + assert_succeed(mid); + }); +} + +#[test] +fn free_range_success() { + const WAT: &str = r#" +(module + (import "env" "memory" (memory 1)) + (import "env" "alloc" (func $alloc (param i32) (result i32))) + (import "env" "free" (func $free (param i32) (result i32))) + (import "env" "free_range" (func $free_range (param i32) (param i32) (result i32))) + (export "init" (func $init)) + (func $init + ;; allocate 4 pages + i32.const 0x4 + call $alloc + + i32.const 1 + i32.ne + if + unreachable + end + + ;; free one page in range + i32.const 0x2 + call $free + + i32.const 0 + i32.ne + if + unreachable + end + + ;; free range with one missing page + i32.const 0x1 + i32.const 0x4 + call $free_range + i32.const 0x0 + i32.ne + if + unreachable + end + ) +) + "#; + + init_logger(); + new_test_ext().execute_with(|| { + let pid = Gear::upload_program( + RuntimeOrigin::signed(USER_1), + ProgramCodeKind::Custom(WAT).to_bytes(), + DEFAULT_SALT.to_vec(), + EMPTY_PAYLOAD.to_vec(), + 500_000_000_u64, + 0, + false, + ) + .map(|_| get_last_program_id()) + .unwrap(); + let mid = get_last_message_id(); + + run_to_next_block(None); + + assert_succeed(mid); + assert!(Gear::is_initialized(pid)); + assert!(Gear::is_active(pid)); + }); +} + #[test] fn reject_incorrect_stack_pointer() { let wat = format!( @@ -14233,7 +14371,7 @@ fn send_gasless_message_works() { keep_alive: false, } ), - Error::::FailureRedeemingVoucher + pallet_gear_bank::Error::::InsufficientBalance ); // USER_1 as the program owner issues a voucher for USER_2 enough to send a message @@ -14257,7 +14395,7 @@ fn send_gasless_message_works() { // Balance check // Voucher has been issued, but not used yet, so funds should be still in the respective account - let voucher_id = GearVoucher::voucher_account_id(&USER_2, &program_id); + let voucher_id = GearVoucher::voucher_id(&USER_2, &program_id); assert_eq!( Balances::free_balance(voucher_id), gas_price(DEFAULT_GAS_LIMIT) @@ -14328,7 +14466,7 @@ fn send_gasless_reply_works() { // Top up program's account balance with some funds CurrencyOf::::resolve_creating( - &AccountId::from_origin(prog_id.into_origin()), + &prog_id.cast(), CurrencyOf::::issue(2_000_u128), ); @@ -14339,7 +14477,7 @@ fn send_gasless_reply_works() { prog_id, gas_price(DEFAULT_GAS_LIMIT), )); - let voucher_id = GearVoucher::voucher_account_id(&USER_1, &prog_id); + let voucher_id = GearVoucher::voucher_id(&USER_1, &prog_id); run_to_block(3, None); @@ -14636,7 +14774,7 @@ fn test_send_to_terminated_from_program() { init_logger(); new_test_ext().execute_with(|| { - let user_1_bytes = ProgramId::from_origin(USER_1.into_origin()).into_bytes(); + let user_1_bytes = USER_1.into_origin().to_fixed_bytes(); // Dies in init let init = Calls::builder().panic("Die in init"); @@ -14996,15 +15134,29 @@ fn test_gas_info_of_terminated_program() { #[test] fn test_handle_signal_wait() { - use binaries::demo_signal_wait::WASM_BINARY_OPT; + use binaries::demo_constructor::WASM_BINARY_OPT; + use demo_constructor::{Arg, Calls, Scheme}; init_logger(); new_test_ext().execute_with(|| { + let init = Calls::builder().bool("first", true); + let handle = Calls::builder().if_else( + Arg::get("first"), + Calls::builder() + .bool("first", false) + .system_reserve_gas(10_000_000_000) + .wait_for(1), + Calls::builder().panic(None), + ); + let handle_signal = Calls::builder().wait(); + + let scheme = Scheme::predefined(init, handle, Default::default(), handle_signal); + assert_ok!(Gear::upload_program( RuntimeOrigin::signed(USER_1), WASM_BINARY_OPT.to_vec(), DEFAULT_SALT.to_vec(), - EMPTY_PAYLOAD.to_vec(), + scheme.encode(), 100_000_000_000, 0, false, @@ -15021,7 +15173,7 @@ fn test_handle_signal_wait() { RuntimeOrigin::signed(USER_1), pid, EMPTY_PAYLOAD.to_vec(), - 50_000_000_000, + 100_000_000_000, 0, false, )); @@ -15052,6 +15204,73 @@ fn test_handle_signal_wait() { }); } +#[test] +fn test_constructor_if_else() { + use binaries::demo_constructor::WASM_BINARY_OPT; + use demo_constructor::{Arg, Call, Calls, Scheme}; + + init_logger(); + new_test_ext().execute_with(|| { + let init = Calls::builder().bool("switch", false); + let handle = Calls::builder() + .if_else( + Arg::get("switch"), + Calls::builder().add_call(Call::Bool(false)), + Calls::builder().add_call(Call::Bool(true)), + ) + .store("switch") + .if_else( + Arg::get("switch"), + Calls::builder().wait_for(1), + Calls::builder().exit(<[u8; 32]>::from(USER_1.into_origin())), + ); + + let scheme = Scheme::predefined(init, handle, Default::default(), Default::default()); + + assert_ok!(Gear::upload_program( + RuntimeOrigin::signed(USER_1), + WASM_BINARY_OPT.to_vec(), + DEFAULT_SALT.to_vec(), + scheme.encode(), + 100_000_000_000, + 0, + false, + )); + + let pid = get_last_program_id(); + + run_to_next_block(None); + + assert!(Gear::is_active(pid)); + assert!(Gear::is_initialized(pid)); + + assert_ok!(Gear::send_message( + RuntimeOrigin::signed(USER_1), + pid, + EMPTY_PAYLOAD.to_vec(), + 100_000_000_000, + 0, + false, + )); + + let mid = get_last_message_id(); + + run_to_next_block(None); + + let task = ScheduledTask::WakeMessage(pid, mid); + + assert!(WaitlistOf::::contains(&pid, &mid)); + assert!(TaskPoolOf::::contains( + &(Gear::block_number() + 1), + &task + )); + + run_to_next_block(None); + + assert!(!WaitlistOf::::contains(&pid, &mid)); + }); +} + mod utils { #![allow(unused)] @@ -15166,7 +15385,7 @@ mod utils { free: impl Into>, reserved: impl Into>, ) { - let account_id = AccountId::from_origin(origin.into_origin()); + let account_id = origin.cast(); assert_eq!(Balances::free_balance(account_id), free.into()); assert_eq!( GearBank::::account_total(&account_id), @@ -15341,7 +15560,7 @@ mod utils { // If value can't be reserved, message is skipped. assert_ok!(>::transfer( &sender, - &AccountId::from_origin(program_id.into_origin()), + &program_id.cast(), locked_value, frame_support::traits::ExistenceRequirement::AllowDeath )); diff --git a/pallets/gear/src/weights.rs b/pallets/gear/src/weights.rs index a71ad0a9798..b0695a26165 100644 --- a/pallets/gear/src/weights.rs +++ b/pallets/gear/src/weights.rs @@ -69,6 +69,8 @@ pub trait WeightInfo { fn alloc(r: u32, ) -> Weight; fn alloc_per_page(p: u32, ) -> Weight; fn free(r: u32, ) -> Weight; + fn free_range(r: u32, ) -> Weight; + fn free_range_per_page(p: u32, ) -> Weight; fn gr_reserve_gas(r: u32, ) -> Weight; fn gr_unreserve_gas(r: u32, ) -> Weight; fn gr_system_reserve_gas(r: u32, ) -> Weight; @@ -594,6 +596,26 @@ impl WeightInfo for SubstrateWeight { // Standard Error: 269_511 .saturating_add(Weight::from_parts(63_993_415, 0).saturating_mul(r.into())) } + /// The range of component `r` is `[0, 20]`. + fn free_range(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 229_654_000 picoseconds. + Weight::from_parts(251_181_937, 0) + // Standard Error: 228_273 + .saturating_add(Weight::from_parts(76_272_378, 0).saturating_mul(r.into())) + } + /// The range of component `p` is `[1, 20]`. + fn free_range_per_page(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 305_902_000 picoseconds. + Weight::from_parts(302_932_691, 0) + // Standard Error: 60_684 + .saturating_add(Weight::from_parts(5_306_653, 0).saturating_mul(p.into())) + } /// The range of component `r` is `[0, 256]`. fn gr_reserve_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: @@ -2565,6 +2587,26 @@ impl WeightInfo for () { // Standard Error: 269_511 .saturating_add(Weight::from_parts(63_993_415, 0).saturating_mul(r.into())) } + /// The range of component `r` is `[0, 20]`. + fn free_range(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 229_654_000 picoseconds. + Weight::from_parts(251_181_937, 0) + // Standard Error: 228_273 + .saturating_add(Weight::from_parts(76_272_378, 0).saturating_mul(r.into())) + } + /// The range of component `p` is `[1, 20]`. + fn free_range_per_page(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 305_902_000 picoseconds. + Weight::from_parts(302_932_691, 0) + // Standard Error: 60_684 + .saturating_add(Weight::from_parts(5_306_653, 0).saturating_mul(p.into())) + } /// The range of component `r` is `[0, 256]`. fn gr_reserve_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: diff --git a/pallets/payment/src/mock.rs b/pallets/payment/src/mock.rs index b989c655a8d..7cf4809e880 100644 --- a/pallets/payment/src/mock.rs +++ b/pallets/payment/src/mock.rs @@ -164,11 +164,9 @@ impl DelegateFee for DelegateFeeAccountBuilder { RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { call: pallet_gear_voucher::PrepaidCall::SendMessage { .. }, }) => Some(FEE_PAYER), - RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { - call: pallet_gear_voucher::PrepaidCall::SendReply { reply_to_id, .. }, - }) => as common::storage::Mailbox>::peek(who, reply_to_id).map( - |stored_message| GearVoucher::voucher_account_id(who, &stored_message.source()), - ), + RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { call }) => { + GearVoucher::sponsor_of(who, call) + } _ => None, } } @@ -190,6 +188,7 @@ impl pallet_gear_voucher::Config for Test { type PalletId = VoucherPalletId; type WeightInfo = (); type CallsDispatcher = Gear; + type Mailbox = MailboxOf; } // Build genesis storage according to the mock runtime. diff --git a/pallets/payment/src/tests.rs b/pallets/payment/src/tests.rs index 067c4db71a4..af5e36d8335 100644 --- a/pallets/payment/src/tests.rs +++ b/pallets/payment/src/tests.rs @@ -26,10 +26,7 @@ use frame_support::{ dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}, weights::{Weight, WeightToFee}, }; -use gear_core::{ - ids::{MessageId, ProgramId}, - message::{Dispatch, DispatchKind, Message, StoredDispatch, UserStoredMessage}, -}; +use gear_core::message::{Dispatch, DispatchKind, Message, StoredDispatch, UserStoredMessage}; use pallet_transaction_payment::{FeeDetails, InclusionFee, Multiplier, RuntimeDispatchInfo}; use primitive_types::H256; use sp_runtime::{testing::TestXt, traits::SignedExtension, FixedPointNumber}; @@ -169,7 +166,7 @@ fn fee_rounding_error_bounded_by_multiplier() { // rounding error only arises for calls that do not affect MQ let call: &::RuntimeCall = &RuntimeCall::Gear(pallet_gear::Call::claim_value { - message_id: MessageId::from_origin(H256::from_low_u64_le(1)), + message_id: H256::from_low_u64_le(1).cast(), }); let weights = vec![ @@ -210,7 +207,7 @@ fn mq_size_affecting_fee_works() { let alice_initial_balance = Balances::free_balance(ALICE); let author_initial_balance = Balances::free_balance(BLOCK_AUTHOR); - let program_id = ProgramId::from_origin(H256::random()); + let program_id = H256::random().cast(); let call: &::RuntimeCall = &RuntimeCall::Gear(pallet_gear::Call::send_message { @@ -308,7 +305,7 @@ fn mq_size_not_affecting_fee_works() { let call: &::RuntimeCall = &RuntimeCall::Gear(pallet_gear::Call::claim_value { - message_id: MessageId::from_origin(H256::from_low_u64_le(1)), + message_id: H256::from_low_u64_le(1).cast(), }); let len = 100usize; @@ -393,7 +390,7 @@ fn mq_size_not_affecting_fee_works() { #[test] #[allow(clippy::let_unit_value)] fn query_info_and_fee_details_work() { - let program_id = ProgramId::from_origin(H256::random()); + let program_id = H256::random().cast(); let call_affecting_mq = RuntimeCall::Gear(pallet_gear::Call::send_message { destination: program_id, payload: Default::default(), @@ -568,7 +565,7 @@ fn fee_payer_replacement_works() { let author_initial_balance = Balances::free_balance(BLOCK_AUTHOR); let synthesized_initial_balance = Balances::free_balance(FEE_PAYER); - let program_id = ProgramId::from_origin(H256::random()); + let program_id = H256::random().cast(); let call: &::RuntimeCall = &RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { @@ -627,14 +624,14 @@ fn reply_with_voucher_pays_fee_from_voucher_ok() { let author_initial_balance = Balances::free_balance(BLOCK_AUTHOR); let bob_initial_balance = Balances::free_balance(BOB); - let msg_id = MessageId::from_origin(H256::random()); - let program_id = ProgramId::from_origin(H256::random()); + let msg_id = H256::random().cast(); + let program_id = H256::random().cast(); // Put message in BOB's mailbox assert_ok!(MailboxOf::::insert( UserStoredMessage::new( msg_id, program_id, - ProgramId::from_origin(BOB.into_origin()), + BOB.cast(), Default::default(), Default::default(), ), @@ -648,7 +645,7 @@ fn reply_with_voucher_pays_fee_from_voucher_ok() { program_id, 200_000_000, )); - let voucher_id = GearVoucher::voucher_account_id(&BOB, &program_id); + let voucher_id = GearVoucher::voucher_id(&BOB, &program_id); run_to_block(2); diff --git a/runtime/vara/src/lib.rs b/runtime/vara/src/lib.rs index 784f3a7b435..8b01682a855 100644 --- a/runtime/vara/src/lib.rs +++ b/runtime/vara/src/lib.rs @@ -24,7 +24,7 @@ #[cfg(all(feature = "std", not(feature = "fuzz")))] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use common::storage::{Mailbox, Messenger}; +use common::storage::Messenger; use frame_election_provider_support::{ onchain, ElectionDataProvider, NposSolution, SequentialPhragmen, VoteWeight, }; @@ -994,7 +994,6 @@ impl pallet_gear::Config for Runtime { type BlockLimiter = GearGas; type Scheduler = GearScheduler; type QueueRunner = Gear; - type Voucher = GearVoucher; type ProgramRentFreePeriod = ConstU32<{ MONTHS * RENT_FREE_PERIOD_MONTH_FACTOR }>; type ProgramResumeMinimalRentPeriod = ConstU32<{ WEEKS * RENT_RESUME_WEEK_FACTOR }>; type ProgramRentCostPerBlock = ConstU128; @@ -1058,14 +1057,9 @@ pub struct DelegateFeeAccountBuilder; impl DelegateFee for DelegateFeeAccountBuilder { fn delegate_fee(call: &RuntimeCall, who: &AccountId) -> Option { match call { - RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { - call: pallet_gear_voucher::PrepaidCall::SendMessage { destination, .. }, - }) => Some(GearVoucher::voucher_account_id(who, destination)), - RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { - call: pallet_gear_voucher::PrepaidCall::SendReply { reply_to_id, .. }, - }) => <::Mailbox as Mailbox>::peek(who, reply_to_id).map( - |stored_message| GearVoucher::voucher_account_id(who, &stored_message.source()), - ), + RuntimeCall::GearVoucher(pallet_gear_voucher::Call::call { call }) => { + GearVoucher::sponsor_of(who, call) + } _ => None, } } @@ -1087,6 +1081,7 @@ impl pallet_gear_voucher::Config for Runtime { type PalletId = VoucherPalletId; type WeightInfo = weights::pallet_gear_voucher::SubstrateWeight; type CallsDispatcher = Gear; + type Mailbox = ::Mailbox; } impl frame_system::offchain::SendTransactionTypes for Runtime diff --git a/runtime/vara/src/weights/pallet_gear.rs b/runtime/vara/src/weights/pallet_gear.rs index b0219137a90..76d4cbfb0af 100644 --- a/runtime/vara/src/weights/pallet_gear.rs +++ b/runtime/vara/src/weights/pallet_gear.rs @@ -19,13 +19,13 @@ //! Autogenerated weights for pallet_gear //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("vara-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/gear benchmark pallet --chain=vara-dev --steps=50 --repeat=20 --pallet=pallet_gear --extrinsic=alloc,alloc_in_handle,alloc_per_page,claim_value,create_program,db_read_per_kb,db_write_per_kb,free,gr_block_height,gr_block_timestamp,gr_create_program,gr_create_program_per_kb,gr_create_program_wgas,gr_create_program_wgas_per_kb,gr_debug,gr_debug_per_kb,gr_gas_available,gr_message_id,gr_pay_program_rent,gr_program_id,gr_random,gr_read,gr_read_per_kb,gr_reply_code,gr_reply_deposit,gr_reply_per_kb,gr_reply_push,gr_reply_push_input,gr_reply_push_input_per_kb,gr_reply_push_per_kb,gr_reply_to,gr_reply_wgas_per_kb,gr_reservation_reply_commit_per_kb,gr_reservation_reply_per_kb,gr_reservation_send,gr_reservation_send_commit,gr_reservation_send_per_kb,gr_reserve_gas,gr_send,gr_send_commit,gr_send_commit_wgas,gr_send_init,gr_send_input,gr_send_input_wgas,gr_send_per_kb,gr_send_push,gr_send_push_input,gr_send_push_input_per_kb,gr_send_push_per_kb,gr_send_wgas,gr_send_wgas_per_kb,gr_signal_code,gr_signal_from,gr_size,gr_source,gr_system_reserve_gas,gr_unreserve_gas,gr_value,gr_value_available,gr_wake,initial_allocation,instantiate_module_per_kb,instr_br,instr_br_if,instr_br_table,instr_br_table_per_entry,instr_call,instr_call_const,instr_call_indirect,instr_call_indirect_per_param,instr_call_per_local,instr_global_get,instr_global_set,instr_i32add,instr_i32and,instr_i32clz,instr_i32ctz,instr_i32divs,instr_i32divu,instr_i32eq,instr_i32eqz,instr_i32extend16s,instr_i32extend8s,instr_i32ges,instr_i32geu,instr_i32gts,instr_i32gtu,instr_i32les,instr_i32leu,instr_i32load,instr_i32lts,instr_i32ltu,instr_i32mul,instr_i32ne,instr_i32or,instr_i32popcnt,instr_i32rems,instr_i32remu,instr_i32rotl,instr_i32rotr,instr_i32shl,instr_i32shrs,instr_i32shru,instr_i32store,instr_i32sub,instr_i32wrapi64,instr_i32xor,instr_i64add,instr_i64and,instr_i64clz,instr_i64ctz,instr_i64divs,instr_i64divu,instr_i64eq,instr_i64eqz,instr_i64extend16s,instr_i64extend32s,instr_i64extend8s,instr_i64extendsi32,instr_i64extendui32,instr_i64ges,instr_i64geu,instr_i64gts,instr_i64gtu,instr_i64les,instr_i64leu,instr_i64load,instr_i64lts,instr_i64ltu,instr_i64mul,instr_i64ne,instr_i64or,instr_i64popcnt,instr_i64rems,instr_i64remu,instr_i64rotl,instr_i64rotr,instr_i64shl,instr_i64shrs,instr_i64shru,instr_i64store,instr_i64sub,instr_i64xor,instr_if,instr_local_get,instr_local_set,instr_local_tee,instr_memory_current,instr_select,lazy_pages_host_func_read,lazy_pages_host_func_write,lazy_pages_host_func_write_after_read,lazy_pages_load_page_storage_data,lazy_pages_signal_read,lazy_pages_signal_write,lazy_pages_signal_write_after_read,mem_grow,pay_program_rent,reinstrument_per_kb,resume_session_commit,resume_session_init,resume_session_push,send_message,send_reply,tasks_pause_program,tasks_pause_program_uninited,tasks_remove_from_mailbox,tasks_remove_from_waitlist,tasks_remove_gas_reservation,tasks_remove_resume_session,tasks_send_dispatch,tasks_send_user_message,tasks_send_user_message_to_mailbox,tasks_wake_message,tasks_wake_message_no_wake,upload_code,upload_program,gr_env_vars --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./scripts/benchmarking/weights-output/pallet_gear.rs --template=.maintain/frame-weight-template.hbs +// ./target/production/gear benchmark pallet --chain=vara-dev --steps=50 --repeat=20 --pallet=pallet_gear --extrinsic=alloc,alloc_in_handle,alloc_per_page,claim_value,create_program,db_read_per_kb,db_write_per_kb,free,free_range,free_range_per_page,gr_block_height,gr_block_timestamp,gr_create_program,gr_create_program_per_kb,gr_create_program_wgas,gr_create_program_wgas_per_kb,gr_debug,gr_debug_per_kb,gr_env_vars,gr_gas_available,gr_message_id,gr_pay_program_rent,gr_program_id,gr_random,gr_read,gr_read_per_kb,gr_reply_code,gr_reply_deposit,gr_reply_per_kb,gr_reply_push,gr_reply_push_input,gr_reply_push_input_per_kb,gr_reply_push_per_kb,gr_reply_to,gr_reply_wgas_per_kb,gr_reservation_reply_commit_per_kb,gr_reservation_reply_per_kb,gr_reservation_send,gr_reservation_send_commit,gr_reservation_send_per_kb,gr_reserve_gas,gr_send,gr_send_commit,gr_send_commit_wgas,gr_send_init,gr_send_input,gr_send_input_wgas,gr_send_per_kb,gr_send_push,gr_send_push_input,gr_send_push_input_per_kb,gr_send_push_per_kb,gr_send_wgas,gr_send_wgas_per_kb,gr_signal_code,gr_signal_from,gr_size,gr_source,gr_system_reserve_gas,gr_unreserve_gas,gr_value,gr_value_available,gr_wake,initial_allocation,instantiate_module_per_kb,instr_br,instr_br_if,instr_br_table,instr_br_table_per_entry,instr_call,instr_call_const,instr_call_indirect,instr_call_indirect_per_param,instr_call_per_local,instr_global_get,instr_global_set,instr_i32add,instr_i32and,instr_i32clz,instr_i32ctz,instr_i32divs,instr_i32divu,instr_i32eq,instr_i32eqz,instr_i32extend16s,instr_i32extend8s,instr_i32ges,instr_i32geu,instr_i32gts,instr_i32gtu,instr_i32les,instr_i32leu,instr_i32load,instr_i32lts,instr_i32ltu,instr_i32mul,instr_i32ne,instr_i32or,instr_i32popcnt,instr_i32rems,instr_i32remu,instr_i32rotl,instr_i32rotr,instr_i32shl,instr_i32shrs,instr_i32shru,instr_i32store,instr_i32sub,instr_i32wrapi64,instr_i32xor,instr_i64add,instr_i64and,instr_i64clz,instr_i64ctz,instr_i64divs,instr_i64divu,instr_i64eq,instr_i64eqz,instr_i64extend16s,instr_i64extend32s,instr_i64extend8s,instr_i64extendsi32,instr_i64extendui32,instr_i64ges,instr_i64geu,instr_i64gts,instr_i64gtu,instr_i64les,instr_i64leu,instr_i64load,instr_i64lts,instr_i64ltu,instr_i64mul,instr_i64ne,instr_i64or,instr_i64popcnt,instr_i64rems,instr_i64remu,instr_i64rotl,instr_i64rotr,instr_i64shl,instr_i64shrs,instr_i64shru,instr_i64store,instr_i64sub,instr_i64xor,instr_if,instr_local_get,instr_local_set,instr_local_tee,instr_memory_current,instr_select,lazy_pages_host_func_read,lazy_pages_host_func_write,lazy_pages_host_func_write_after_read,lazy_pages_load_page_storage_data,lazy_pages_signal_read,lazy_pages_signal_write,lazy_pages_signal_write_after_read,mem_grow,pay_program_rent,reinstrument_per_kb,resume_session_commit,resume_session_init,resume_session_push,send_message,send_reply,tasks_pause_program,tasks_pause_program_uninited,tasks_remove_from_mailbox,tasks_remove_from_waitlist,tasks_remove_gas_reservation,tasks_remove_resume_session,tasks_send_dispatch,tasks_send_user_message,tasks_send_user_message_to_mailbox,tasks_wake_message,tasks_wake_message_no_wake,upload_code,upload_program --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./scripts/benchmarking/weights-output/pallet_gear.rs --template=.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -69,6 +69,8 @@ pub trait WeightInfo { fn alloc(r: u32, ) -> Weight; fn alloc_per_page(p: u32, ) -> Weight; fn free(r: u32, ) -> Weight; + fn free_range(r: u32, ) -> Weight; + fn free_range_per_page(p: u32, ) -> Weight; fn gr_reserve_gas(r: u32, ) -> Weight; fn gr_unreserve_gas(r: u32, ) -> Weight; fn gr_system_reserve_gas(r: u32, ) -> Weight; @@ -594,6 +596,26 @@ impl pallet_gear::WeightInfo for SubstrateWeight { // Standard Error: 269_511 .saturating_add(Weight::from_parts(63_993_415, 0).saturating_mul(r.into())) } + /// The range of component `r` is `[0, 20]`. + fn free_range(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 229_654_000 picoseconds. + Weight::from_parts(251_181_937, 0) + // Standard Error: 228_273 + .saturating_add(Weight::from_parts(76_272_378, 0).saturating_mul(r.into())) + } + /// The range of component `p` is `[1, 20]`. + fn free_range_per_page(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 305_902_000 picoseconds. + Weight::from_parts(302_932_691, 0) + // Standard Error: 60_684 + .saturating_add(Weight::from_parts(5_306_653, 0).saturating_mul(p.into())) + } /// The range of component `r` is `[0, 256]`. fn gr_reserve_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: @@ -2565,6 +2587,26 @@ impl WeightInfo for () { // Standard Error: 269_511 .saturating_add(Weight::from_parts(63_993_415, 0).saturating_mul(r.into())) } + /// The range of component `r` is `[0, 20]`. + fn free_range(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 229_654_000 picoseconds. + Weight::from_parts(251_181_937, 0) + // Standard Error: 228_273 + .saturating_add(Weight::from_parts(76_272_378, 0).saturating_mul(r.into())) + } + /// The range of component `p` is `[1, 20]`. + fn free_range_per_page(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 305_902_000 picoseconds. + Weight::from_parts(302_932_691, 0) + // Standard Error: 60_684 + .saturating_add(Weight::from_parts(5_306_653, 0).saturating_mul(p.into())) + } /// The range of component `r` is `[0, 256]`. fn gr_reserve_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: diff --git a/stack-buffer/Cargo.toml b/stack-buffer/Cargo.toml index df253031675..550d2df76cb 100644 --- a/stack-buffer/Cargo.toml +++ b/stack-buffer/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "gear-stack-buffer" +description = "Gear stack buffer implementation" version.workspace = true authors.workspace = true edition.workspace = true diff --git a/utils/crates-io/Cargo.toml b/utils/crates-io/Cargo.toml index 834d1e80a86..6f5c850fce7 100644 --- a/utils/crates-io/Cargo.toml +++ b/utils/crates-io/Cargo.toml @@ -1,16 +1,12 @@ [package] -name = "crates-io-manager" +name = "crates-io" version.workspace = true edition.workspace = true -[[bin]] -name = "publish" -path = "publish.rs" - [dependencies] anyhow.workspace = true cargo_metadata.workspace = true -cargo_toml.workspace = true -crates-io.workspace = true -curl.workspace = true -toml.workspace = true +clap = { workspace = true, features = ["derive"] } +serde = { workspace = true, features = ["derive"] } +reqwest = { workspace = true, features = ["blocking", "json", "default-tls"] } +toml_edit.workspace = true diff --git a/utils/crates-io/publish.rs b/utils/crates-io/publish.rs deleted file mode 100644 index f8e121abd08..00000000000 --- a/utils/crates-io/publish.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! mini-program for publishing packages to crates.io. -use anyhow::Result; -use cargo_metadata::MetadataCommand; -use cargo_toml::{Dependency, Manifest, Value}; -use crates_io::Registry; -use curl::easy::Easy; -use std::{ - collections::{BTreeMap, HashMap}, - env, fs, - path::PathBuf, - process::{Command, ExitStatus}, - thread, - time::Duration, -}; - -/// Packages need to be published. -const PACKAGES: [&str; 14] = [ - // Packages without local dependencies. - "actor-system-error", - "gear-common-codegen", - "gear-core-errors", - "gear-wasm-instrument", - "gmeta-codegen", - "gsdk-codegen", - "gsys", - // The packages below have local dependencies, - // and should be published in order. - "gmeta", - "gear-core", - "gear-utils", - "gear-common", - "gsdk", - "gcli", - "gclient", -]; - -/// Packages need to be patched in dependencies. -const PATCHED_PACKAGES: [&str; 1] = ["sp-arithmetic"]; - -struct CratesIo { - registry: Registry, -} - -impl CratesIo { - /// Create a new instance of `CratesIo`. - pub fn new() -> Result { - let mut handle = Easy::new(); - handle.useragent("gear-crates-io-manager")?; - - Ok(Self { - registry: Registry::new_handle("https://crates.io".into(), None, handle, false), - }) - } - - /// Verify if the package is published to crates.io. - pub fn verify(&mut self, package: &str, version: &str) -> Result { - // Here using limit = 1 since we are searching explicit - // packages here. - let (crates, _total) = self.registry.search(package, 1)?; - if crates.len() != 1 { - return Ok(false); - } - - Ok(crates[0].max_version == version) - } -} - -fn main() -> Result<()> { - let mut validator = CratesIo::new()?; - let metadata = MetadataCommand::new().no_deps().exec()?; - let mut graph = BTreeMap::new(); - let index = HashMap::::from_iter( - PACKAGES.into_iter().enumerate().map(|(i, p)| (p.into(), i)), - ); - - let workspace_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../../Cargo.toml") - .canonicalize()?; - let workspace = Manifest::from_path(&workspace_path)?; - - for p in metadata.packages.into_iter() { - if !index.contains_key(&p.name) { - continue; - } - - let version = p.version.to_string(); - if validator.verify(&p.name, &version)? { - println!("Package {}@{} already published.", &p.name, &version); - continue; - } - - let path = p.manifest_path.into_std_path_buf(); - let mut manifest = Manifest::::from_slice_with_metadata(&fs::read(&path)?)?; - manifest.complete_from_path_and_workspace(&path, Some((&workspace, &workspace_path)))?; - - // NOTE: This is a bug inside of crate cargo_toml, it should - // not append crate-type = ["rlib"] to proc-macro crates, fixing - // it by hacking it now. - if p.name.ends_with("-codegen") { - if let Some(mut product) = manifest.lib { - product.crate_type = vec![]; - manifest.lib = Some(product); - } - } - - for (name, dep) in manifest.dependencies.iter_mut() { - // No need to update dependencies for packages without - // local dependencies. - if !index.contains_key(name) && !PATCHED_PACKAGES.contains(&name.as_str()) { - continue; - } - - let mut detail = if let Dependency::Detailed(detail) = &dep { - detail.clone() - } else { - continue; - }; - - match name.as_ref() { - // NOTE: the required version of sp-arithmetic is 6.0.0 in - // git repo, but 7.0.0 in crates.io, so we need to fix it. - "sp-arithmetic" => { - detail.version = Some("7.0.0".into()); - detail.branch = None; - detail.git = None; - } - _ => detail.version = Some(version.to_string()), - } - - *dep = Dependency::Detailed(detail); - } - - graph.insert(index.get(&p.name), (path, manifest)); - } - - for (path, manifest) in graph.values() { - println!("Publishing {:?}", path); - fs::write(path, toml::to_string_pretty(manifest)?)?; - - let path = path.to_string_lossy(); - let status = publish(&path)?; - if !status.success() { - println!( - "Failed to publish package {}...\nRetry after 11 mins...", - &path - ); - // The most likely reason for failure is that - // we have reached the rate limit of crates.io. - // - // Need to wait for 10 mins and try again. here - // we use 11 mins to be safe. - // - // Only retry for once, if it still fails, we - // will just give up. - thread::sleep(Duration::from_secs(660)); - publish(&path)?; - } - } - - Ok(()) -} - -fn publish(manifest: &str) -> Result { - Command::new("cargo") - .arg("publish") - .arg("--manifest-path") - .arg(manifest) - .arg("--allow-dirty") - .status() - .map_err(Into::into) -} diff --git a/utils/crates-io/src/lib.rs b/utils/crates-io/src/lib.rs new file mode 100644 index 00000000000..454b60615c0 --- /dev/null +++ b/utils/crates-io/src/lib.rs @@ -0,0 +1,70 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! crates-io-manager library +#![deny(missing_docs)] + +mod manifest; +mod publisher; +mod version; + +pub use self::{manifest::Manifest, publisher::Publisher, version::verify}; +use anyhow::Result; +use std::process::{Command, ExitStatus}; + +/// Required Packages without local dependencies. +pub const SAFE_DEPENDENCIES: [&str; 10] = [ + "actor-system-error", + "galloc", + "gear-stack-buffer", + "gear-core-errors", + "gear-common-codegen", + "gear-wasm-instrument", + "gmeta-codegen", + "gsdk-codegen", + "gstd-codegen", + "gsys", +]; + +/// Required packages with local dependencies. +pub const STACKED_DEPENDENCIES: [&str; 5] = + ["gcore", "gmeta", "gear-core", "gear-utils", "gear-common"]; + +/// Packages need to be published. +pub const PACKAGES: [&str; 5] = ["gear-wasm-builder", "gstd", "gsdk", "gclient", "gcli"]; + +/// Check the input package +pub fn check(manifest: &str) -> Result { + Command::new("cargo") + .arg("check") + .arg("--manifest-path") + .arg(manifest) + .status() + .map_err(Into::into) +} + +/// Publish the input package +pub fn publish(manifest: &str) -> Result { + Command::new("cargo") + .arg("publish") + .arg("--manifest-path") + .arg(manifest) + .arg("--allow-dirty") + .status() + .map_err(Into::into) +} diff --git a/utils/crates-io/src/main.rs b/utils/crates-io/src/main.rs new file mode 100644 index 00000000000..15fc0b0fe85 --- /dev/null +++ b/utils/crates-io/src/main.rs @@ -0,0 +1,62 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! mini-program for publishing packages to crates.io. + +use anyhow::Result; +use clap::Parser; +use crates_io::Publisher; + +/// The command to run. +#[derive(Clone, Debug, Parser)] +enum Command { + /// Build manifests for packages that to be published. + Build, + /// Check packages that to be published. + Check, + /// Publish packages. + Publish { + /// The version to publish. + #[clap(long, short)] + version: Option, + }, +} + +/// Gear crates-io manager command line interface +/// +/// NOTE: this binary should not be used locally +/// but run in CI. +#[derive(Debug, Parser)] +pub struct Opt { + #[clap(subcommand)] + command: Command, +} + +fn main() -> Result<()> { + let Opt { command } = Opt::parse(); + + let publisher = Publisher::new()?; + match command { + Command::Check => publisher.build(None)?.check(), + Command::Publish { version } => publisher.build(version)?.publish(), + Command::Build => { + publisher.build(None)?; + Ok(()) + } + } +} diff --git a/utils/crates-io/src/manifest.rs b/utils/crates-io/src/manifest.rs new file mode 100644 index 00000000000..942a43118cc --- /dev/null +++ b/utils/crates-io/src/manifest.rs @@ -0,0 +1,188 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Manifest utils for crates-io-manager + +use anyhow::{anyhow, Result}; +use cargo_metadata::Package; +use std::{fs, path::PathBuf}; +use toml_edit::Document; + +use crate::version; + +const WORKSPACE_NAME: &str = "__gear_workspace"; + +/// Cargo manifest with path +pub struct Manifest { + /// Crate name + pub name: String, + /// Cargo manifest + pub manifest: Document, + /// Path of the manifest + pub path: PathBuf, +} + +impl Manifest { + /// Get the workspace manifest + pub fn workspace() -> Result { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(2) + .map(|workspace_dir| workspace_dir.join("Cargo.toml")) + .ok_or_else(|| anyhow::anyhow!("Could not find workspace manifest"))? + .canonicalize()?; + + Ok(Self { + name: WORKSPACE_NAME.to_string(), + manifest: fs::read_to_string(&path)?.parse()?, + path, + }) + } + + /// Complete the manifest of the specified crate from + /// the workspace manifest + pub fn manifest(&self, pkg: &Package) -> Result { + self.ensure_workspace()?; + + // Complete documentation as from + let mut manifest: Document = fs::read_to_string(&pkg.manifest_path)?.parse()?; + let name = pkg.name.clone(); + manifest["package"]["documentation"] = toml_edit::value(format!("https://docs.rs/{name}")); + + Ok(Self { + name, + manifest, + path: pkg.manifest_path.clone().into(), + }) + } + + /// complete the versions of the specified crates + pub fn complete_versions(&mut self, index: &[&str]) -> Result<()> { + self.ensure_workspace()?; + + let version = self.manifest["workspace"]["package"]["version"] + .clone() + .as_str() + .ok_or_else(|| anyhow!("Could not find version in workspace manifest"))? + .to_string(); + + let Some(deps) = self.manifest["workspace"]["dependencies"].as_table_mut() else { + return Err(anyhow!( + "Failed to parse dependencies from workspace {}", + self.path.display() + )); + }; + + for (key, dep) in deps.iter_mut() { + let name = key.get(); + if !index.contains(&name) { + continue; + } + + dep["version"] = toml_edit::value(version.clone()); + } + + self.rename_deps()?; + Ok(()) + } + + /// Set version for the workspace. + pub fn with_version(mut self, version: Option) -> Result { + self.ensure_workspace()?; + + let version = if let Some(version) = version { + version + } else { + self.version()? + "-" + &version::hash()? + }; + + self.manifest["workspace"]["package"]["version"] = toml_edit::value(version); + + Ok(self) + } + + /// Get version from the current manifest. + pub fn version(&self) -> Result { + self.ensure_workspace()?; + + Ok(self.manifest["workspace"]["package"]["version"] + .as_str() + .ok_or_else(|| { + anyhow!( + "Could not find version in workspace manifest: {}", + self.path.display() + ) + })? + .to_string()) + } + + /// Write manifest to disk. + pub fn write(&self) -> Result<()> { + fs::write(&self.path, self.manifest.to_string()).map_err(Into::into) + } + + /// Rename dependencies + fn rename_deps(&mut self) -> Result<()> { + self.ensure_workspace()?; + + let Some(deps) = self.manifest["workspace"]["dependencies"].as_table_like_mut() else { + return Ok(()); + }; + + for (name, dep) in deps.iter_mut() { + let name = name.get(); + if !name.starts_with("sp-") { + continue; + } + + // Format dotted values into inline table. + if let Some(table) = dep.as_table_mut() { + table.remove("branch"); + table.remove("git"); + table.remove("workspace"); + + if name == "sp-arithmetic" { + // NOTE: the required version of sp-arithmetic is 6.0.0 in + // git repo, but 7.0.0 in crates.io, so we need to fix it. + table.insert("version", toml_edit::value("7.0.0")); + } + + // Force the dep to be inline table in case of losing + // documentation. + let mut inline = table.clone().into_inline_table(); + inline.fmt(); + *dep = toml_edit::value(inline); + }; + } + + Ok(()) + } + + /// Ensure the current function is called on the workspace manifest + /// + /// TODO: remove this interface after #3565 + fn ensure_workspace(&self) -> Result<()> { + if self.name != WORKSPACE_NAME { + return Err(anyhow!( + "This method can only be called on the workspace manifest" + )); + } + + Ok(()) + } +} diff --git a/utils/crates-io/src/publisher.rs b/utils/crates-io/src/publisher.rs new file mode 100644 index 00000000000..0155eea94c8 --- /dev/null +++ b/utils/crates-io/src/publisher.rs @@ -0,0 +1,130 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Packages publisher + +use crate::{Manifest, PACKAGES, SAFE_DEPENDENCIES, STACKED_DEPENDENCIES}; +use anyhow::Result; +use cargo_metadata::{Metadata, MetadataCommand, Package}; +use std::collections::{BTreeMap, HashMap}; + +/// crates-io packages publisher. +pub struct Publisher { + metadata: Metadata, + graph: BTreeMap, Manifest>, + index: HashMap, +} + +impl Publisher { + /// Create a new publisher. + pub fn new() -> Result { + let metadata = MetadataCommand::new().no_deps().exec()?; + let graph = BTreeMap::new(); + let index = HashMap::::from_iter( + [ + SAFE_DEPENDENCIES.to_vec(), + STACKED_DEPENDENCIES.into(), + PACKAGES.into(), + ] + .concat() + .into_iter() + .enumerate() + .map(|(i, p)| (p.into(), i)), + ); + + Ok(Self { + metadata, + graph, + index, + }) + } + + /// Build package graphs + /// + /// 1. Replace git dependencies to crates-io dependencies. + /// 2. Rename version of all local packages + /// 3. Patch dependencies if needed + pub fn build(mut self, version: Option) -> Result { + let index = self.index.keys().map(|s| s.as_ref()).collect::>(); + let mut workspace = Manifest::workspace()?.with_version(version)?; + let version = workspace.version()?; + + for pkg @ Package { name, .. } in &self.metadata.packages { + if !index.contains(&name.as_ref()) { + continue; + } + + println!("Verifying {}@{} ...", &name, &version); + if crate::verify(name, &version)? { + println!("Package {}@{} already published .", &name, &version); + continue; + } + + self.graph + .insert(self.index.get(name).cloned(), workspace.manifest(pkg)?); + } + + // Flush new manifests to disk + workspace.complete_versions(&index)?; + let mut manifests = self.graph.values().collect::>(); + manifests.push(&workspace); + manifests + .iter() + .map(|m| m.write()) + .collect::>>()?; + + Ok(self) + } + + /// Check the to-be-published packages + /// + /// TODO: Complete the check process (#3565) + pub fn check(&self) -> Result<()> { + let mut failed = Vec::new(); + for Manifest { path, name, .. } in self.graph.values() { + if !PACKAGES.contains(&name.as_str()) { + continue; + } + + println!("Checking {path:?}"); + let status = crate::check(&path.to_string_lossy())?; + if !status.success() { + failed.push(path); + } + } + + if !failed.is_empty() { + panic!("Packages {failed:?} failed to pass the check ..."); + } + + Ok(()) + } + + /// Publish packages + pub fn publish(&self) -> Result<()> { + for Manifest { path, .. } in self.graph.values() { + println!("Publishing {path:?}"); + let status = crate::publish(&path.to_string_lossy())?; + if !status.success() { + panic!("Failed to publish package {path:?} ..."); + } + } + + Ok(()) + } +} diff --git a/utils/crates-io/src/version.rs b/utils/crates-io/src/version.rs new file mode 100644 index 00000000000..4986ef927fc --- /dev/null +++ b/utils/crates-io/src/version.rs @@ -0,0 +1,59 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Crate verifier + +use anyhow::{anyhow, Result}; +use serde::Deserialize; +use std::process::Command; + +#[derive(Debug, Deserialize)] +struct Resp { + pub versions: Vec, +} + +#[derive(Debug, Deserialize)] +struct Version { + pub num: String, +} + +/// Verify if the package has already been published. +pub fn verify(name: &str, version: &str) -> Result { + let client = reqwest::blocking::Client::builder() + .user_agent("gear-crates-io-manager") + .build()?; + + let resp = client + .get(format!("https://crates.io/api/v1/crates/{name}/versions")) + .send()? + .json::()?; + + Ok(resp.versions.into_iter().any(|v| v.num == version)) +} + +/// Get the short hash of the current commit. +pub fn hash() -> Result { + Ok(Command::new("git") + .args(["rev-parse", "--short", "HEAD"]) + .output() + .map_err(|e| anyhow!("failed to execute command git, {e}"))? + .stdout + .iter() + .filter_map(|&c| (!c.is_ascii_whitespace()).then_some(c as char)) + .collect()) +} diff --git a/utils/node-loader/src/utils.rs b/utils/node-loader/src/utils.rs index c155c61a1b4..3cf66ccdeaa 100644 --- a/utils/node-loader/src/utils.rs +++ b/utils/node-loader/src/utils.rs @@ -7,8 +7,8 @@ use gear_core::ids::{MessageId, ProgramId}; use gear_core_errors::ReplyCode; use gear_utils::NonEmpty; use gear_wasm_gen::{ - EntryPointsSet, InvocableSyscall, ParamType, StandardGearWasmConfigsBundle, SyscallName, - SyscallsInjectionTypes, SyscallsParamsConfig, + EntryPointsSet, InvocableSyscall, ParamType, RegularParamType, StandardGearWasmConfigsBundle, + SyscallName, SyscallsInjectionTypes, SyscallsParamsConfig, }; use gsdk::metadata::runtime_types::{ gear_common::event::DispatchStatus as GenDispatchStatus, @@ -230,8 +230,11 @@ pub fn get_wasm_gen_config( ); let mut params_config = SyscallsParamsConfig::default(); - params_config.add_rule(ParamType::Alloc, (1..=10).into()); - params_config.add_rule(ParamType::Free, (initial_pages..=initial_pages + 50).into()); + params_config.add_rule(ParamType::Regular(RegularParamType::Alloc), (1..=10).into()); + params_config.add_rule( + ParamType::Regular(RegularParamType::Free), + (initial_pages..=initial_pages + 50).into(), + ); StandardGearWasmConfigsBundle { log_info: Some(format!("Gear program seed = '{seed}'")), diff --git a/utils/regression-analysis/src/main.rs b/utils/regression-analysis/src/main.rs index 94a7903bacf..1d72cac6ece 100644 --- a/utils/regression-analysis/src/main.rs +++ b/utils/regression-analysis/src/main.rs @@ -309,6 +309,8 @@ fn weights(kind: WeightsKind, input_file: PathBuf, output_file: PathBuf) { alloc, alloc_per_page, free, + free_range, + free_range_per_page, gr_gas_available, gr_message_id, gr_pay_program_rent, diff --git a/utils/runtime-fuzzer/src/gear_calls.rs b/utils/runtime-fuzzer/src/gear_calls.rs index cf241af7040..1e57f8d81a4 100644 --- a/utils/runtime-fuzzer/src/gear_calls.rs +++ b/utils/runtime-fuzzer/src/gear_calls.rs @@ -35,8 +35,8 @@ use gear_call_gen::{ClaimValueArgs, SendReplyArgs}; use gear_core::ids::{CodeId, MessageId, ProgramId}; use gear_utils::NonEmpty; use gear_wasm_gen::{ - EntryPointsSet, InvocableSyscall, ParamType, StandardGearWasmConfigsBundle, SyscallName, - SyscallsInjectionTypes, SyscallsParamsConfig, + EntryPointsSet, InvocableSyscall, ParamType, RegularParamType, StandardGearWasmConfigsBundle, + SyscallName, SyscallsInjectionTypes, SyscallsParamsConfig, }; use std::mem; @@ -425,8 +425,14 @@ fn config( ); let mut params_config = SyscallsParamsConfig::default(); - params_config.add_rule(ParamType::Alloc, (10..=20).into()); - params_config.add_rule(ParamType::Free, (initial_pages..=initial_pages + 35).into()); + params_config.add_rule( + ParamType::Regular(RegularParamType::Alloc), + (10..=20).into(), + ); + params_config.add_rule( + ParamType::Regular(RegularParamType::Free), + (initial_pages..=initial_pages + 35).into(), + ); let existing_addresses = NonEmpty::collect( programs diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 79bad58298c..d9952c4dfd1 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "gear-wasm-builder" -version = "0.1.2" +version.workspace = true edition.workspace = true -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +license.workspace = true +repository.workspace = true description = "Utility for building Gear programs" -include = ["src/**/*", "Cargo.toml", "README.md"] -repository = "https://github.com/gear-tech/gear" +include = ["build.rs", "src/**/*", "Cargo.toml", "README.md"] readme = "README.md" [dependencies] diff --git a/utils/wasm-builder/src/crate_info.rs b/utils/wasm-builder/src/crate_info.rs index e94342744d3..6afa55a7287 100644 --- a/utils/wasm-builder/src/crate_info.rs +++ b/utils/wasm-builder/src/crate_info.rs @@ -18,7 +18,7 @@ use anyhow::{Context, Result}; use cargo_metadata::{Metadata, MetadataCommand, Package}; -use std::{collections::HashMap, path::Path}; +use std::{collections::BTreeMap, path::Path}; use crate::builder_error::BuilderError; @@ -32,7 +32,7 @@ pub struct CrateInfo { /// Crate version. pub version: String, /// Crate features. - pub features: HashMap>, + pub features: BTreeMap>, } impl CrateInfo { diff --git a/utils/wasm-builder/src/optimize.rs b/utils/wasm-builder/src/optimize.rs index dcff479eb3f..376636dd64d 100644 --- a/utils/wasm-builder/src/optimize.rs +++ b/utils/wasm-builder/src/optimize.rs @@ -78,7 +78,7 @@ impl Optimizer { } pub fn flush_to_file(self, path: &PathBuf) { - fs::write(path, self.module.to_bytes().unwrap()).unwrap(); + fs::write(path, self.module.into_bytes().unwrap()).unwrap(); } /// Process optimization. diff --git a/utils/wasm-builder/src/stack_end.rs b/utils/wasm-builder/src/stack_end.rs index 529ec48fd52..e98986587a6 100644 --- a/utils/wasm-builder/src/stack_end.rs +++ b/utils/wasm-builder/src/stack_end.rs @@ -37,7 +37,7 @@ use pwasm_utils::parity_wasm::{ pub fn insert_stack_end_export(module: &mut Module) -> Result<(), &'static str> { let module_bytes = module .clone() - .to_bytes() + .into_bytes() .map_err(|_| "cannot get code from module")?; let stack_pointer_index = @@ -141,7 +141,7 @@ pub fn insert_start_call_in_export_funcs(module: &mut Module) -> Result<(), &'st pub fn move_mut_globals_to_static(module: &mut Module) -> Result<(), &'static str> { let module_bytes = module .clone() - .to_bytes() + .into_bytes() .map_err(|_| "cannot get code from module")?; // Identify stack pointer and data end globals @@ -477,7 +477,7 @@ mod test { // Insert `_start` call in `handle` code and check that it works as expected. let mut module = parity_wasm::deserialize_buffer(binary.as_ref()).unwrap(); insert_start_call_in_export_funcs(&mut module).unwrap(); - check(&module.to_bytes().unwrap(), 12); + check(&module.into_bytes().unwrap(), 12); } #[test] @@ -556,6 +556,6 @@ mod test { // their values after first execution, and second execution will return another result. let mut module = parity_wasm::deserialize_buffer(binary.as_ref()).unwrap(); move_mut_globals_to_static(&mut module).unwrap(); - check(&module.to_bytes().unwrap(), 111, 113); + check(&module.into_bytes().unwrap(), 111, 113); } } diff --git a/utils/wasm-dep-builder/src/lib.rs b/utils/wasm-dep-builder/src/lib.rs index 1472a10142a..b09ad66210a 100644 --- a/utils/wasm-dep-builder/src/lib.rs +++ b/utils/wasm-dep-builder/src/lib.rs @@ -221,7 +221,8 @@ pub mod {dep_name} {{ !lock_exists, content == DEMO_OCCURRED ); - if !lock_exists || content == DEMO_OCCURRED { + #[allow(clippy::overly_complex_bool_expr)] + if true || !lock_exists || content == DEMO_OCCURRED { println!("cargo:warning=rebuilding..."); packages_to_build.insert(pkg.name.clone(), features); diff --git a/utils/wasm-gen/src/config/syscalls.rs b/utils/wasm-gen/src/config/syscalls.rs index ede17d5def5..531a0889cec 100644 --- a/utils/wasm-gen/src/config/syscalls.rs +++ b/utils/wasm-gen/src/config/syscalls.rs @@ -22,15 +22,16 @@ mod injection; mod param; mod precise; +mod process_errors; use gear_utils::NonEmpty; use gear_wasm_instrument::syscalls::SyscallName; use gsys::{Hash, HashWithValue}; -use std::collections::HashSet; pub use injection::*; pub use param::*; pub use precise::*; +pub use process_errors::*; use crate::InvocableSyscall; @@ -117,30 +118,6 @@ impl SyscallsConfigBuilder { } } -#[derive(Debug, Clone, Default)] -pub enum ErrorProcessingConfig { - /// Process errors on all the fallible syscalls. - All, - /// Process only errors on provided syscalls. - Whitelist(HashSet), - /// Process errors on all the syscalls excluding provided. - Blacklist(HashSet), - /// Don't process syscall errors at all. - #[default] - None, -} - -impl ErrorProcessingConfig { - pub fn error_should_be_processed(&self, syscall: &InvocableSyscall) -> bool { - match self { - Self::All => true, - Self::Whitelist(wl) => wl.contains(syscall), - Self::Blacklist(bl) => !bl.contains(syscall), - Self::None => false, - } - } -} - /// United config for all entities in syscalls generator module. #[derive(Debug, Clone, Default)] pub struct SyscallsConfig { diff --git a/utils/wasm-gen/src/config/syscalls/injection.rs b/utils/wasm-gen/src/config/syscalls/injection.rs index 681c77496d2..52b08befb1b 100644 --- a/utils/wasm-gen/src/config/syscalls/injection.rs +++ b/utils/wasm-gen/src/config/syscalls/injection.rs @@ -109,7 +109,7 @@ impl SyscallsInjectionTypes { } } - /// Imports the given syscall, if necessary. + /// Imports the given syscall, if possible. pub(crate) fn enable_syscall_import(&mut self, name: InvocableSyscall) { if let Some(injection_type @ SyscallInjectionType::None) = self.0.get_mut(&name) { *injection_type = SyscallInjectionType::Import; diff --git a/utils/wasm-gen/src/config/syscalls/param.rs b/utils/wasm-gen/src/config/syscalls/param.rs index f1bf90f1955..8b0815530ff 100644 --- a/utils/wasm-gen/src/config/syscalls/param.rs +++ b/utils/wasm-gen/src/config/syscalls/param.rs @@ -24,7 +24,7 @@ use crate::DEFAULT_INITIAL_SIZE; use arbitrary::{Result, Unstructured}; use std::{collections::HashMap, ops::RangeInclusive}; -pub use gear_wasm_instrument::syscalls::ParamType; +pub use gear_wasm_instrument::syscalls::{ParamType, RegularParamType}; /// Syscalls params config. /// @@ -50,17 +50,21 @@ impl SyscallsParamsConfig { /// New [`SyscallsParamsConfig`] with all rules set to produce one constant value. pub fn all_constant_value(value: i64) -> Self { + use ParamType::*; + use RegularParamType::*; + let allowed_values: SyscallParamAllowedValues = (value..=value).into(); Self( [ - ParamType::Length, - ParamType::Gas, - ParamType::Offset, - ParamType::DurationBlockNumber, - ParamType::DelayBlockNumber, - ParamType::Handler, - ParamType::Free, - ParamType::Version, + Regular(Length), + Regular(Gas), + Regular(Offset), + Regular(DurationBlockNumber), + Regular(DelayBlockNumber), + Regular(Handler), + Regular(Free), + Regular(FreeUpperBound), + Regular(Version), ] .into_iter() .map(|param_type| (param_type, allowed_values.clone())) @@ -75,7 +79,7 @@ impl SyscallsParamsConfig { /// Set allowed values for the `param`. pub fn add_rule(&mut self, param: ParamType, allowed_values: SyscallParamAllowedValues) { - matches!(param, ParamType::Ptr(..)) + matches!(param, ParamType::Regular(RegularParamType::Pointer(_))) .then(|| panic!("ParamType::Ptr(..) isn't supported in SyscallsParamsConfig")); self.0.insert(param, allowed_values); @@ -84,20 +88,24 @@ impl SyscallsParamsConfig { impl Default for SyscallsParamsConfig { fn default() -> Self { + use ParamType::*; + use RegularParamType::*; + let free_start = DEFAULT_INITIAL_SIZE as i64; let free_end = free_start + 5; Self( [ - (ParamType::Length, (0..=0x10000).into()), + (Regular(Length), (0..=0x10000).into()), // There are no rules for memory arrays and pointers as they are chosen // in accordance to memory pages config. - (ParamType::Gas, (0..=250_000_000_000).into()), - (ParamType::Offset, (0..=10).into()), - (ParamType::DurationBlockNumber, (1..=8).into()), - (ParamType::DelayBlockNumber, (0..=4).into()), - (ParamType::Handler, (0..=100).into()), - (ParamType::Free, (free_start..=free_end).into()), - (ParamType::Version, (1..=1).into()), + (Regular(Gas), (0..=250_000_000_000).into()), + (Regular(Offset), (0..=10).into()), + (Regular(DurationBlockNumber), (1..=8).into()), + (Regular(DelayBlockNumber), (0..=4).into()), + (Regular(Handler), (0..=100).into()), + (Regular(Free), (free_start..=free_end).into()), + (Regular(Version), (1..=1).into()), + (Regular(FreeUpperBound), (0..=10).into()), ] .into_iter() .collect(), diff --git a/utils/wasm-gen/src/config/syscalls/process_errors.rs b/utils/wasm-gen/src/config/syscalls/process_errors.rs new file mode 100644 index 00000000000..5ad2d8c83f2 --- /dev/null +++ b/utils/wasm-gen/src/config/syscalls/process_errors.rs @@ -0,0 +1,84 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Processing syscalls errors config. + +use std::collections::HashSet; + +use crate::InvocableSyscall; + +#[derive(Debug, Clone, Default)] +pub enum ErrorProcessingConfig { + /// Process errors on all the fallible syscalls. + All, + /// Process only errors on provided syscalls. + Whitelist(ErrorProneSyscalls), + /// Process errors on all the syscalls excluding provided. + Blacklist(ErrorProneSyscalls), + /// Don't process syscall errors at all. + #[default] + None, +} + +impl ErrorProcessingConfig { + pub fn error_should_be_processed(&self, syscall: InvocableSyscall) -> bool { + match self { + Self::All => true, + Self::Whitelist(wl) => wl.contains(syscall), + Self::Blacklist(bl) => { + if syscall.returns_error() { + !bl.contains(syscall) + } else { + false + } + } + Self::None => false, + } + } +} + +/// Set of syscalls that return an error. +/// +/// Basically, it's a wrapper over a hash set of [`InvocableSysCall`], +/// that controls types of inserted syscalls. +#[derive(Debug, Clone, Default)] +pub struct ErrorProneSyscalls(HashSet); + +impl ErrorProneSyscalls { + /// Create an empty set of returning error syscalls. + pub fn new() -> Self { + Self(HashSet::new()) + } + + /// Insert an error-prone syscall into the set. + pub fn insert(&mut self, syscall: InvocableSyscall) { + if syscall.returns_error() { + self.0.insert(syscall); + } else { + panic!( + "{syscall_str} is neither fallible, nor returns error value.", + syscall_str = syscall.to_str() + ); + } + } + + /// Check if the `syscall` is in the set. + pub fn contains(&self, syscall: InvocableSyscall) -> bool { + self.0.contains(&syscall) + } +} diff --git a/utils/wasm-gen/src/generator/syscalls.rs b/utils/wasm-gen/src/generator/syscalls.rs index d6cf7979352..8a29acd61cc 100644 --- a/utils/wasm-gen/src/generator/syscalls.rs +++ b/utils/wasm-gen/src/generator/syscalls.rs @@ -43,7 +43,7 @@ pub use imports::*; pub use invocator::*; use gear_wasm_instrument::syscalls::{ - HashType, ParamType, PtrInfo, PtrType, SyscallName, SyscallSignature, + ErrPtr, HashType, Ptr, RegularParamType, SyscallName, SyscallSignature, }; /// Type of invocable syscall. @@ -81,95 +81,94 @@ impl InvocableSyscall { match self { InvocableSyscall::Loose(name) => name.signature(), InvocableSyscall::Precise(name) => match name { - SyscallName::ReservationSend => SyscallSignature::gr([ - // Address of recipient and value (HashWithValue struct) - ParamType::Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - // Pointer to payload - ParamType::Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - // Length of the payload - ParamType::Length, - // Number of blocks to delay the sending for - ParamType::DelayBlockNumber, - // Amount of gas to reserve - ParamType::Gas, - // Duration of the reservation - ParamType::DurationBlockNumber, + SyscallName::ReservationSend => SyscallSignature::gr_fallible(( + [ + // Address of recipient and value (HashWithValue struct) + Ptr::HashWithValue(HashType::ActorId).into(), + // Pointer to payload + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + // Length of the payload + RegularParamType::Length, + // Number of blocks to delay the sending for + RegularParamType::DelayBlockNumber, + // Amount of gas to reserve + RegularParamType::Gas, + // Duration of the reservation + RegularParamType::DurationBlockNumber, + ], // Address of error returned - ParamType::Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - SyscallName::ReservationReply => SyscallSignature::gr([ - // Address of value - ParamType::Ptr(PtrInfo::new_immutable(PtrType::Value)), - // Pointer to payload - ParamType::Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - // Length of the payload - ParamType::Length, - // Amount of gas to reserve - ParamType::Gas, - // Duration of the reservation - ParamType::DurationBlockNumber, + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + SyscallName::ReservationReply => SyscallSignature::gr_fallible(( + [ + // Address of value + Ptr::Value.into(), + // Pointer to payload + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + // Length of the payload + RegularParamType::Length, + // Amount of gas to reserve + RegularParamType::Gas, + // Duration of the reservation + RegularParamType::DurationBlockNumber, + ], // Address of error returned - ParamType::Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - SyscallName::SendCommit => SyscallSignature::gr([ - // Address of recipient and value (HashWithValue struct) - ParamType::Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - // Pointer to payload - ParamType::Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - // Length of the payload - ParamType::Length, - // Number of blocks to delay the sending for - ParamType::DelayBlockNumber, + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + SyscallName::SendCommit => SyscallSignature::gr_fallible(( + [ + // Address of recipient and value (HashWithValue struct) + Ptr::HashWithValue(HashType::ActorId).into(), + // Pointer to payload + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + // Length of the payload + RegularParamType::Length, + // Number of blocks to delay the sending for + RegularParamType::DelayBlockNumber, + ], // Address of error returned, `ErrorCode` here because underlying syscalls have different error types - ParamType::Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - SyscallName::SendCommitWGas => SyscallSignature::gr([ - // Address of recipient and value (HashWithValue struct) - ParamType::Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - // Number of blocks to delay the sending for - ParamType::DelayBlockNumber, - // Amount of gas to reserve - ParamType::Gas, + ErrPtr::ErrorCode, + )), + SyscallName::SendCommitWGas => SyscallSignature::gr_fallible(( + [ + // Address of recipient and value (HashWithValue struct) + Ptr::HashWithValue(HashType::ActorId).into(), + // Number of blocks to delay the sending for + RegularParamType::DelayBlockNumber, + // Amount of gas to reserve + RegularParamType::Gas, + ], // Address of error returned, `ErrorCode` here because underlying syscalls have different error types - ParamType::Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - SyscallName::ReplyDeposit => SyscallSignature::gr([ - // Address of recipient and value (HashWithValue struct). That's needed - // because first `gr_send_input` is invoked and resulting message id is - // used as an input to `gr_reply_deposit`. - ParamType::Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - // An offset defining starting index in the received payload (related to `gr_send_input`). - ParamType::Offset, - // Length of the slice of the received message payload (related to `gr_send_input`). - ParamType::Length, - // Delay (related to `gr_send_input`). - ParamType::DelayBlockNumber, - // Amount of gas deposited for a message id got from `gr_send_input`. - // That's an actual input for `gr_reply_deposit` - ParamType::Gas, + ErrPtr::ErrorCode, + )), + SyscallName::ReplyDeposit => SyscallSignature::gr_fallible(( + [ + // Address of recipient and value (HashWithValue struct). That's needed + // because first `gr_send_input` is invoked and resulting message id is + // used as an input to `gr_reply_deposit`. + Ptr::HashWithValue(HashType::ActorId).into(), + // An offset defining starting index in the received payload (related to `gr_send_input`). + RegularParamType::Offset, + // Length of the slice of the received message payload (related to `gr_send_input`). + RegularParamType::Length, + // Delay (related to `gr_send_input`). + RegularParamType::DelayBlockNumber, + // Amount of gas deposited for a message id got from `gr_send_input`. + // That's an actual input for `gr_reply_deposit` + RegularParamType::Gas, + ], // Error pointer - ParamType::Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), + ErrPtr::ErrorWithHash(HashType::MessageId), + )), _ => unimplemented!(), }, } @@ -236,8 +235,21 @@ impl InvocableSyscall { && !matches!(self, InvocableSyscall::Loose(SyscallName::Exit)) } - // If syscall changes from fallible into infallible or vice versa in future, - // we'll see it by analyzing code coverage stats produced by fuzzer. + /// Checks whether syscall is error-prone either by returning error indicating value + /// or by providing error pointer as a syscall param. + /// + /// There are only 2 syscalls returning error value: `Alloc` and `Free`. + /// + /// If syscall changes from fallible into infallible or vice versa in future, + /// we'll see it by analyzing code coverage stats produced by fuzzer. + pub(crate) fn returns_error(&self) -> bool { + match self { + InvocableSyscall::Loose(syscall) => syscall.returns_error(), + InvocableSyscall::Precise(syscall) => syscall.returns_error(), + } + } + + #[cfg(test)] pub(crate) fn is_fallible(&self) -> bool { match self { InvocableSyscall::Loose(syscall) => syscall.is_fallible(), diff --git a/utils/wasm-gen/src/generator/syscalls/invocator.rs b/utils/wasm-gen/src/generator/syscalls/invocator.rs index 06d0cb1bc4f..6f94384477e 100644 --- a/utils/wasm-gen/src/generator/syscalls/invocator.rs +++ b/utils/wasm-gen/src/generator/syscalls/invocator.rs @@ -29,7 +29,10 @@ use crate::{ use arbitrary::{Result, Unstructured}; use gear_wasm_instrument::{ parity_wasm::elements::{BlockType, Instruction, Internal, ValueType}, - syscalls::{ParamType, PtrInfo, PtrType, SyscallName, SyscallSignature}, + syscalls::{ + FallibleSyscallSignature, ParamType, Ptr, RegularParamType, SyscallName, SyscallSignature, + SystemSyscallSignature, + }, }; use gsys::Hash; use std::{ @@ -43,11 +46,14 @@ pub(crate) enum ProcessedSyscallParams { Alloc { allowed_values: Option, }, + FreeUpperBound { + allowed_values: Option, + }, Value { value_type: ValueType, allowed_values: Option, }, - MemoryArraySize, + MemoryArrayLength, MemoryArrayPtr, MemoryPtrValue, } @@ -56,13 +62,16 @@ pub(crate) fn process_syscall_params( params: &[ParamType], params_config: &SyscallsParamsConfig, ) -> Vec { + use ParamType::*; + use RegularParamType::*; + let length_param_indexes = params .iter() .filter_map(|¶m| match param { - ParamType::Ptr(PtrInfo { - ty: PtrType::SizedBufferStart { length_param_idx }, - .. - }) => Some(length_param_idx), + Regular(Pointer( + Ptr::SizedBufferStart { length_param_idx } + | Ptr::MutSizedBufferStart { length_param_idx }, + )) => Some(length_param_idx), _ => None, }) .collect::>(); @@ -70,21 +79,25 @@ pub(crate) fn process_syscall_params( let mut res = Vec::with_capacity(params.len()); for (param_idx, ¶m) in params.iter().enumerate() { let processed_param = match param { - ParamType::Alloc => ProcessedSyscallParams::Alloc { + Regular(Alloc) => ProcessedSyscallParams::Alloc { allowed_values: params_config.get_rule(¶m), }, - ParamType::Length if length_param_indexes.contains(¶m_idx) => { + Regular(Length) if length_param_indexes.contains(¶m_idx) => { // Due to match guard `ParamType::Size` can be processed in two ways: // 1. The function will return `ProcessedSyscallParams::MemoryArraySize` // if this parameter is associated with PtrType::BufferStart { .. }`. // 2. Otherwise, `ProcessedSyscallParams::Value` will be returned from the function. - ProcessedSyscallParams::MemoryArraySize + ProcessedSyscallParams::MemoryArrayLength + } + Regular(Pointer(Ptr::SizedBufferStart { .. })) => { + ProcessedSyscallParams::MemoryArrayPtr + } + // It's guaranteed that fallible syscall has error pointer as a last param. + Regular(Pointer(_)) | Error(_) => ProcessedSyscallParams::MemoryPtrValue, + Regular(FreeUpperBound) => { + let allowed_values = params_config.get_rule(¶m); + ProcessedSyscallParams::FreeUpperBound { allowed_values } } - ParamType::Ptr(PtrInfo { - ty: PtrType::SizedBufferStart { .. }, - .. - }) => ProcessedSyscallParams::MemoryArrayPtr, - ParamType::Ptr(_) => ProcessedSyscallParams::MemoryPtrValue, _ => ProcessedSyscallParams::Value { value_type: param.into(), allowed_values: params_config.get_rule(¶m), @@ -167,6 +180,10 @@ impl ParamSetter { } } + /// Get value of the instruction. + /// + /// # Panics + /// Panics if the instruction is not `I32Const` or `I64Const`. fn get_value(&self) -> i64 { match self.0 { Instruction::I32Const(value) => value as i64, @@ -279,11 +296,8 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { .get(&syscall) .map(|(_, call_indexes_handle)| *call_indexes_handle) .expect("Syscall presented in syscall_imports"); - let instructions = self.build_syscall_invoke_instructions( - syscall, - syscall.into_signature(), - call_indexes_handle, - )?; + let instructions = + self.build_syscall_invoke_instructions(syscall, call_indexes_handle)?; log::trace!( " -- Inserting syscall `{}` into function with index {insert_into_fn} at position {pos}", @@ -313,7 +327,6 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { fn build_syscall_invoke_instructions( &mut self, invocable: InvocableSyscall, - signature: SyscallSignature, call_indexes_handle: CallIndexesHandle, ) -> Result { log::trace!( @@ -328,33 +341,26 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { invocable.to_str() ); - self.build_call_with_destination( - invocable, - signature, - call_indexes_handle, - argument_index, - ) + self.build_call_with_destination(invocable, call_indexes_handle, argument_index) } else { log::trace!( " -- Building call for a common syscall `{}`", invocable.to_str() ); - self.build_call(invocable, signature, call_indexes_handle) + self.build_call(invocable, call_indexes_handle) } } fn build_call_with_destination( &mut self, invocable: InvocableSyscall, - signature: SyscallSignature, call_indexes_handle: CallIndexesHandle, destination_arg_idx: usize, ) -> Result> { // The value for the destination param is chosen from config. // It's either the result of `gr_source`, some existing address (set in the data section) or a completely random value. - let mut original_instructions = - self.build_call(invocable, signature, call_indexes_handle)?; + let mut original_instructions = self.build_call(invocable, call_indexes_handle)?; let destination_instructions = if self.config.syscall_destination().is_source() { log::trace!(" --- Syscall destination is result of `gr_source`"); @@ -431,10 +437,10 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { fn build_call( &mut self, invocable: InvocableSyscall, - signature: SyscallSignature, call_indexes_handle: CallIndexesHandle, ) -> Result> { - let param_setters = self.build_param_setters(&signature.params)?; + let signature = invocable.into_signature(); + let param_setters = self.build_param_setters(signature.params())?; let mut instructions: Vec<_> = param_setters .iter() .cloned() @@ -443,17 +449,26 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { instructions.push(Instruction::Call(call_indexes_handle as u32)); - let insert_error_processing = self + let process_error = self .config .error_processing_config() - .error_should_be_processed(&invocable); + .error_should_be_processed(invocable); - let mut result_processing = if !insert_error_processing { - Self::build_result_processing_ignored(signature) - } else if invocable.is_fallible() { - Self::build_result_processing_fallible(signature, ¶m_setters) - } else { - Self::build_result_processing_infallible(signature) + let mut result_processing = match signature { + SyscallSignature::Infallible(_) => { + // It's guaranteed here that infallible has no errors to process + // as it has not mut err pointers or error indicating values returned. + Vec::new() + } + signature @ (SyscallSignature::Fallible(_) | SyscallSignature::System(_)) => { + // It's guaranteed by definition that these variants return an error either by returning + // error indicating value or by having err mut pointer in params. + if process_error { + Self::build_error_processing(signature, param_setters) + } else { + Self::build_error_processing_ignored(signature) + } + } }; instructions.append(&mut result_processing); @@ -514,11 +529,11 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { ParamSetter::new_i64(self.unstructured.arbitrary()?) }; - log::trace!(" ---- Pointer value - {}", setter.get_value()); + log::trace!(" ---- Value - {}", setter.get_value()); setters.push(setter); } - ProcessedSyscallParams::MemoryArraySize => { + ProcessedSyscallParams::MemoryArrayLength => { let length; let upper_limit = mem_size.saturating_sub(1) as i32; @@ -561,6 +576,23 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { setters.push(setter); } + ProcessedSyscallParams::FreeUpperBound { allowed_values } => { + // This is the case only for `free_range` syscall. + let previous_param = setters + .last() + .expect("free_range syscall has at least 2 params") + .as_i32() + .expect("referenced param should evaluate to I32Const"); + + let delta = allowed_values + .expect("allowed_values should be set for FreeUpperBound") + .get_i32(self.unstructured)?; + let param = previous_param.saturating_add(delta); + + log::trace!(" ---- Free upper bound - {param}, and delta - {delta}"); + + setters.push(ParamSetter::new_i32(param)) + } } } @@ -574,15 +606,27 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { Ok(setters) } - fn build_result_processing_ignored(signature: SyscallSignature) -> Vec { - iter::repeat(Instruction::Drop) - .take(signature.results.len()) - .collect() + fn build_error_processing( + signature: SyscallSignature, + param_setters: Vec, + ) -> Vec + where + 'a: 'b, + { + match signature { + SyscallSignature::Fallible(fallible) => { + Self::build_fallible_syscall_error_processing(fallible, param_setters) + } + SyscallSignature::System(system) => Self::build_system_syscall_error_processing(system), + SyscallSignature::Infallible(_) => unreachable!( + "Invalid implementation. This function is called only for returning errors syscall" + ), + } } - fn build_result_processing_fallible( - signature: SyscallSignature, - param_setters: &[ParamSetter], + fn build_fallible_syscall_error_processing( + fallible_signature: FallibleSyscallSignature, + param_setters: Vec, ) -> Vec { // TODO: #3129. // Assume here that: @@ -590,60 +634,48 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { // 2. All the errors contain `ErrorCode` in the start of memory where pointer points. static_assertions::assert_eq_size!(gsys::ErrorCode, u32); - assert_eq!(gsys::ErrorCode::default(), 0); - - let params = signature.params; - assert!(matches!( - params - .last() - .expect("The last argument of fallible syscall must be pointer to error code"), - ParamType::Ptr(_) - )); - assert_eq!(params.len(), param_setters.len()); - - if let Some(ptr) = param_setters + let no_error_val = gsys::ErrorCode::default() as i32; + + assert_eq!( + fallible_signature.params().len(), + param_setters.len(), + "ParamsSetter is inconsistent with syscall params." + ); + let res_ptr = param_setters .last() .expect("At least one argument in fallible syscall") .as_i32() - { - vec![ - Instruction::I32Const(ptr), - Instruction::I32Load(2, 0), - Instruction::I32Const(0), - Instruction::I32Ne, - Instruction::If(BlockType::NoResult), - Instruction::Unreachable, - Instruction::End, - ] - } else { - panic!("Incorrect last parameter type: expected pointer"); - } - } - - fn build_result_processing_infallible(signature: SyscallSignature) -> Vec { - // TODO: #3129 - // For now we don't check anywhere that `alloc` and `free` return - // error codes as described here. Also we don't assert that only `alloc` and `free` - // will have their first arguments equal to `ParamType::Alloc` and `ParamType::Free`. - let results_len = signature.results.len(); + .expect("Incorrect last parameter type: expected i32 pointer"); - if results_len == 0 { - return vec![]; - } + vec![ + Instruction::I32Const(res_ptr), + Instruction::I32Load(2, 0), + Instruction::I32Const(no_error_val), + Instruction::I32Ne, + Instruction::If(BlockType::NoResult), + Instruction::Unreachable, + Instruction::End, + ] + } - assert_eq!(results_len, 1); + fn build_system_syscall_error_processing( + system_signature: SystemSyscallSignature, + ) -> Vec { + // That's basically those syscalls, that doesn't have an error pointer, + // but return value indicating error. These are currently `Alloc`, `Free` and `FreeRange`. + assert_eq!(system_signature.results().len(), 1); - let error_code = match signature.params[0] { - ParamType::Alloc => { + let error_code = match system_signature.params()[0] { + ParamType::Regular(RegularParamType::Alloc) => { // Alloc syscall: returns u32::MAX (= -1i32) in case of error. -1 } - ParamType::Free => { - // Free syscall: returns 1 in case of error. + ParamType::Regular(RegularParamType::Free | RegularParamType::FreeUpperBound) => { + // Free/FreeRange syscall: returns 1 in case of error. 1 } _ => { - unimplemented!("Only alloc and free are supported for now") + unimplemented!("Only alloc, free and free_range are supported for now") } }; @@ -656,6 +688,18 @@ impl<'a, 'b> SyscallsInvocator<'a, 'b> { ] } + fn build_error_processing_ignored(signature: SyscallSignature) -> Vec { + match signature { + SyscallSignature::System(system) => iter::repeat(Instruction::Drop) + .take(system.results().len()) + .collect(), + SyscallSignature::Fallible(_) => Vec::new(), + SyscallSignature::Infallible(_) => unreachable!( + "Invalid implementation. This function is called only for returning errors syscall" + ), + } + } + fn resolves_calls_indexes(&mut self) { log::trace!("Resolving calls indexes"); diff --git a/utils/wasm-gen/src/tests.rs b/utils/wasm-gen/src/tests.rs index 8db5c816e40..567133a208a 100644 --- a/utils/wasm-gen/src/tests.rs +++ b/utils/wasm-gen/src/tests.rs @@ -302,7 +302,7 @@ fn precise_syscalls_works() { injection_types.set(syscall, INJECTED_SYSCALLS, INJECTED_SYSCALLS); let mut param_config = SyscallsParamsConfig::default(); - param_config.add_rule(ParamType::Gas, (0..=0).into()); + param_config.add_rule(ParamType::Regular(RegularParamType::Gas), (0..=0).into()); // Assert that syscalls results will be processed. let termination_reason = execute_wasm_with_custom_configs( diff --git a/utils/wasm-instrument/src/syscalls.rs b/utils/wasm-instrument/src/syscalls.rs index c00cace2543..874cf8869a4 100644 --- a/utils/wasm-instrument/src/syscalls.rs +++ b/utils/wasm-instrument/src/syscalls.rs @@ -19,8 +19,10 @@ //! Gear syscalls for smart contracts execution signatures. use crate::parity_wasm::elements::{FunctionType, ValueType}; -use alloc::{collections::BTreeSet, vec::Vec}; +use alloc::{borrow::ToOwned, collections::BTreeSet, vec::Vec}; +use core::iter; use enum_iterator::{self, Sequence}; +pub use pointers::*; /// All available syscalls. /// @@ -93,6 +95,7 @@ pub enum SyscallName { // Hard under the hood calls, serving proper program execution Alloc, Free, + FreeRange, OutOfGas, // Miscellaneous @@ -120,6 +123,7 @@ impl SyscallName { SyscallName::OomPanic => "gr_oom_panic", SyscallName::Exit => "gr_exit", SyscallName::Free => "free", + SyscallName::FreeRange => "free_range", SyscallName::GasAvailable => "gr_gas_available", SyscallName::Leave => "gr_leave", SyscallName::MessageId => "gr_message_id", @@ -180,6 +184,7 @@ impl SyscallName { [ Self::Alloc, Self::Free, + Self::FreeRange, Self::Debug, Self::Panic, Self::OomPanic, @@ -237,347 +242,293 @@ impl SyscallName { /// Returns signature for syscall by name. pub fn signature(self) -> SyscallSignature { - use ParamType::*; - use ValueType::I32; + use RegularParamType::*; + match self { - Self::Alloc => SyscallSignature::system([Alloc], [I32]), - Self::Free => SyscallSignature::system([Free], [I32]), - Self::Debug => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { + Self::Alloc => SyscallSignature::system(([Alloc], [ValueType::I32])), + Self::Free => SyscallSignature::system(([Free], [ValueType::I32])), + Self::FreeRange => SyscallSignature::system(([Free, FreeUpperBound], [ValueType::I32])), + Self::Debug => SyscallSignature::gr_infallible([ + Ptr::SizedBufferStart { length_param_idx: 1, - })), + } + .into(), Length, ]), - Self::Panic => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { + Self::Panic => SyscallSignature::gr_infallible([ + Ptr::SizedBufferStart { length_param_idx: 1, - })), + } + .into(), Length, ]), - Self::OomPanic => SyscallSignature::gr([]), - Self::BlockHeight => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::BlockNumber))]) - } + Self::OomPanic => SyscallSignature::gr_infallible([]), + Self::BlockHeight => SyscallSignature::gr_infallible([Ptr::MutBlockNumber.into()]), Self::BlockTimestamp => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::BlockTimestamp))]) + SyscallSignature::gr_infallible([Ptr::MutBlockTimestamp.into()]) } - Self::Exit => SyscallSignature::gr([Ptr(PtrInfo::new_immutable(PtrType::Hash( - HashType::ActorId, - )))]), - Self::GasAvailable => SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Gas))]), - Self::PayProgramRent => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithBlockNumberAndValue)), - ]), + Self::Exit => SyscallSignature::gr_infallible([Ptr::Hash(HashType::ActorId).into()]), + Self::GasAvailable => SyscallSignature::gr_infallible([Ptr::MutGas.into()]), + Self::PayProgramRent => SyscallSignature::gr_fallible(( + [Ptr::HashWithValue(HashType::ActorId).into()], + ErrPtr::ErrorWithBlockNumberAndValue, + )), Self::ProgramId => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Hash(HashType::ActorId)))]) + SyscallSignature::gr_infallible([Ptr::MutHash(HashType::ActorId).into()]) } - Self::Leave => SyscallSignature::gr([]), - Self::ValueAvailable => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Value))]) + Self::Leave => SyscallSignature::gr_infallible([]), + Self::ValueAvailable => SyscallSignature::gr_infallible([Ptr::MutValue.into()]), + Self::Wait => SyscallSignature::gr_infallible([]), + Self::WaitUpTo => SyscallSignature::gr_infallible([DurationBlockNumber]), + Self::WaitFor => SyscallSignature::gr_infallible([DurationBlockNumber]), + Self::Wake => SyscallSignature::gr_fallible(( + [Ptr::Hash(HashType::MessageId).into(), DelayBlockNumber], + ErrPtr::ErrorCode, + )), + Self::ReplyCode => SyscallSignature::gr_fallible(ErrPtr::ErrorWithReplyCode), + Self::SignalCode => SyscallSignature::gr_fallible(ErrPtr::ErrorWithSignalCode), + Self::MessageId => { + SyscallSignature::gr_infallible([Ptr::MutHash(HashType::MessageId).into()]) } - Self::Wait => SyscallSignature::gr([]), - Self::WaitUpTo => SyscallSignature::gr([DurationBlockNumber]), - Self::WaitFor => SyscallSignature::gr([DurationBlockNumber]), - Self::Wake => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::Hash(HashType::MessageId))), - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::ReplyCode => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::ErrorWithReplyCode))]) + Self::EnvVars => SyscallSignature::gr_infallible([Version, Ptr::MutBufferStart.into()]), + Self::Read => SyscallSignature::gr_fallible(( + [ + Offset, + Length, + Ptr::MutSizedBufferStart { + length_param_idx: 1, + } + .into(), + ], + ErrPtr::ErrorCode, + )), + Self::Reply => SyscallSignature::gr_fallible(( + [ + Ptr::SizedBufferStart { + length_param_idx: 1, + } + .into(), + Length, + Ptr::Value.into(), + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReplyInput => SyscallSignature::gr_fallible(( + [Offset, Length, Ptr::Value.into()], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReplyWGas => SyscallSignature::gr_fallible(( + [ + Ptr::SizedBufferStart { + length_param_idx: 1, + } + .into(), + Length, + Gas, + Ptr::Value.into(), + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReplyInputWGas => SyscallSignature::gr_fallible(( + [Offset, Length, Gas, Ptr::Value.into()], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReplyCommit => SyscallSignature::gr_fallible(( + [Ptr::Value.into()], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReplyCommitWGas => SyscallSignature::gr_fallible(( + [Gas, Ptr::Value.into()], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReservationReply => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::ReservationId).into(), + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReservationReplyCommit => SyscallSignature::gr_fallible(( + [Ptr::HashWithValue(HashType::ReservationId).into()], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReplyPush => SyscallSignature::gr_fallible(( + [ + Ptr::SizedBufferStart { + length_param_idx: 1, + } + .into(), + Length, + ], + ErrPtr::ErrorCode, + )), + Self::ReplyPushInput => { + SyscallSignature::gr_fallible(([Offset, Length], ErrPtr::ErrorCode)) } - Self::SignalCode => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::ErrorWithSignalCode))]) + Self::ReplyTo => { + SyscallSignature::gr_fallible(ErrPtr::ErrorWithHash(HashType::MessageId)) } - Self::MessageId => SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Hash( - HashType::MessageId, - )))]), - Self::EnvVars => { - SyscallSignature::gr([Version, Ptr(PtrInfo::new_mutable(PtrType::BufferStart))]) + Self::SignalFrom => { + SyscallSignature::gr_fallible(ErrPtr::ErrorWithHash(HashType::MessageId)) } - Self::Read => SyscallSignature::gr([ - Offset, - Length, - Ptr(PtrInfo::new_mutable(PtrType::SizedBufferStart { - length_param_idx: 1, - })), - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::Reply => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 1, - })), - Length, - Ptr(PtrInfo::new_immutable(PtrType::Value)), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReplyInput => SyscallSignature::gr([ - Offset, - Length, - Ptr(PtrInfo::new_immutable(PtrType::Value)), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReplyWGas => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 1, - })), - Length, - Gas, - Ptr(PtrInfo::new_immutable(PtrType::Value)), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReplyInputWGas => SyscallSignature::gr([ - Offset, - Length, - Gas, - Ptr(PtrInfo::new_immutable(PtrType::Value)), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReplyCommit => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::Value)), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReplyCommitWGas => SyscallSignature::gr([ - Gas, - Ptr(PtrInfo::new_immutable(PtrType::Value)), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReservationReply => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ReservationId, - ))), - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReservationReplyCommit => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ReservationId, - ))), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReplyPush => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 1, - })), - Length, - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::ReplyPushInput => SyscallSignature::gr([ - Offset, - Length, - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::ReplyTo => SyscallSignature::gr([Ptr(PtrInfo::new_mutable( - PtrType::ErrorWithHash(HashType::MessageId), - ))]), - Self::SignalFrom => SyscallSignature::gr([Ptr(PtrInfo::new_mutable( - PtrType::ErrorWithHash(HashType::MessageId), - ))]), - Self::Send => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::SendInput => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - Offset, - Length, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::SendWGas => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - Gas, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::SendInputWGas => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - Offset, - Length, - Gas, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::SendCommit => SyscallSignature::gr([ - Handler, - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::SendCommitWGas => SyscallSignature::gr([ - Handler, - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::ActorId, - ))), - Gas, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::SendInit => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHandle))]) + Self::Send => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::ActorId).into(), + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::SendInput => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::ActorId).into(), + Offset, + Length, + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::SendWGas => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::ActorId).into(), + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + Gas, + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::SendInputWGas => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::ActorId).into(), + Offset, + Length, + Gas, + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::SendCommit => SyscallSignature::gr_fallible(( + [ + Handler, + Ptr::HashWithValue(HashType::ActorId).into(), + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::SendCommitWGas => SyscallSignature::gr_fallible(( + [ + Handler, + Ptr::HashWithValue(HashType::ActorId).into(), + Gas, + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::SendInit => SyscallSignature::gr_fallible(ErrPtr::ErrorWithHandle), + Self::SendPush => SyscallSignature::gr_fallible(( + [ + Handler, + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + ], + ErrPtr::ErrorCode, + )), + Self::SendPushInput => { + SyscallSignature::gr_fallible(([Handler, Offset, Length], ErrPtr::ErrorCode)) } - Self::SendPush => SyscallSignature::gr([ - Handler, - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::SendPushInput => SyscallSignature::gr([ - Handler, - Offset, - Length, - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::ReservationSend => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::TwoHashesWithValue( - HashType::ReservationId, - HashType::ActorId, - ))), - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::ReservationSendCommit => SyscallSignature::gr([ - Handler, - Ptr(PtrInfo::new_immutable(PtrType::TwoHashesWithValue( - HashType::ReservationId, - HashType::ActorId, - ))), - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::MessageId, - ))), - ]), - Self::Size => SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Length))]), + Self::ReservationSend => SyscallSignature::gr_fallible(( + [ + Ptr::TwoHashesWithValue(HashType::ReservationId, HashType::ActorId).into(), + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::ReservationSendCommit => SyscallSignature::gr_fallible(( + [ + Handler, + Ptr::TwoHashesWithValue(HashType::ReservationId, HashType::ActorId).into(), + DelayBlockNumber, + ], + ErrPtr::ErrorWithHash(HashType::MessageId), + )), + Self::Size => SyscallSignature::gr_infallible([Ptr::MutLength.into()]), Self::Source => { - SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Hash(HashType::ActorId)))]) + SyscallSignature::gr_infallible([Ptr::MutHash(HashType::ActorId).into()]) } - Self::Value => SyscallSignature::gr([Ptr(PtrInfo::new_mutable(PtrType::Value))]), - Self::CreateProgram => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::CodeId, - ))), - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 4, - })), - Length, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithTwoHashes( - HashType::MessageId, - HashType::ActorId, - ))), + Self::Value => SyscallSignature::gr_infallible([Ptr::MutValue.into()]), + Self::CreateProgram => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::CodeId).into(), + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + Ptr::SizedBufferStart { + length_param_idx: 4, + } + .into(), + Length, + DelayBlockNumber, + ], + ErrPtr::ErrorWithTwoHashes(HashType::MessageId, HashType::ActorId), + )), + Self::CreateProgramWGas => SyscallSignature::gr_fallible(( + [ + Ptr::HashWithValue(HashType::CodeId).into(), + Ptr::SizedBufferStart { + length_param_idx: 2, + } + .into(), + Length, + Ptr::SizedBufferStart { + length_param_idx: 4, + } + .into(), + Length, + Gas, + DelayBlockNumber, + ], + ErrPtr::ErrorWithTwoHashes(HashType::MessageId, HashType::ActorId), + )), + Self::ReplyDeposit => SyscallSignature::gr_fallible(( + [Ptr::Hash(HashType::MessageId).into(), Gas], + ErrPtr::ErrorCode, + )), + Self::ReserveGas => SyscallSignature::gr_fallible(( + [Gas, DurationBlockNumber], + ErrPtr::ErrorWithHash(HashType::ReservationId), + )), + Self::UnreserveGas => SyscallSignature::gr_fallible(( + [Ptr::Hash(HashType::ReservationId).into()], + ErrPtr::ErrorWithGas, + )), + Self::SystemReserveGas => SyscallSignature::gr_fallible(([Gas], ErrPtr::ErrorCode)), + Self::Random => SyscallSignature::gr_infallible([ + Ptr::Hash(HashType::SubjectId).into(), + Ptr::MutBlockNumberWithHash(HashType::SubjectId).into(), ]), - Self::CreateProgramWGas => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::HashWithValue( - HashType::CodeId, - ))), - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 2, - })), - Length, - Ptr(PtrInfo::new_immutable(PtrType::SizedBufferStart { - length_param_idx: 4, - })), - Length, - Gas, - DelayBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithTwoHashes( - HashType::MessageId, - HashType::ActorId, - ))), - ]), - Self::ReplyDeposit => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::Hash(HashType::MessageId))), - Gas, - Ptr(PtrInfo::new_mutable(PtrType::ErrorCode)), - ]), - Self::ReserveGas => SyscallSignature::gr([ - Gas, - DurationBlockNumber, - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithHash( - HashType::ReservationId, - ))), - ]), - Self::UnreserveGas => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::Hash( - HashType::ReservationId, - ))), - Ptr(PtrInfo::new_mutable(PtrType::ErrorWithGas)), - ]), - Self::SystemReserveGas => { - SyscallSignature::gr([Gas, Ptr(PtrInfo::new_mutable(PtrType::ErrorCode))]) - } - Self::Random => SyscallSignature::gr([ - Ptr(PtrInfo::new_immutable(PtrType::Hash(HashType::SubjectId))), - Ptr(PtrInfo::new_mutable(PtrType::BlockNumberWithHash( - HashType::SubjectId, - ))), - ]), - other => panic!("Unknown syscall: '{:?}'", other), + Self::OutOfGas => unimplemented!("Unsupported syscall signature for out_of_gas"), } } @@ -594,13 +545,26 @@ impl SyscallName { }) } + /// Checks whether the syscall returns error either by writing to input error pointer + /// or by returning value indicating an error. + /// + /// There are only 3 syscalls returning error value: `Alloc`, `Free` & `FreeRange`. + pub fn returns_error(self) -> bool { + let signature = self.signature(); + + match &signature { + SyscallSignature::Fallible(_) | SyscallSignature::System(_) => true, + SyscallSignature::Infallible(_) => false, + } + } + /// Checks whether the syscall is fallible. /// - /// Literally checks whether syscall contains mutable error pointer. - pub fn is_fallible(&self) -> bool { - self.signature().params.into_iter().any( - |param| matches!(param, ParamType::Ptr(PtrInfo { mutable: true, ty }) if ty.is_error()), - ) + /// ### Note: + /// This differs from `SysCallName::returns_error` as fallible syscalls + /// are those last param of which is a mutable error pointer. + pub fn is_fallible(self) -> bool { + self.signature().is_fallible() } } @@ -610,8 +574,14 @@ impl SyscallName { /// belongs to. See [`PtrInfo`] and [`PtrType`] for more details. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ParamType { + Regular(RegularParamType), + Error(ErrPtr), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum RegularParamType { Length, // i32 buffers length - Ptr(PtrInfo), // i32 pointer + Pointer(Ptr), // i32 non-error pointer Gas, // i64 gas amount Offset, // i32 offset in the input buffer (message payload) DurationBlockNumber, // i32 duration in blocks @@ -619,25 +589,10 @@ pub enum ParamType { Handler, // i32 handler number Alloc, // i32 pages to alloc Free, // i32 page number to free + FreeUpperBound, // i32 free upper bound for use with free_range Version, // i32 version number of exec settings } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct PtrInfo { - pub mutable: bool, - pub ty: PtrType, -} - -impl PtrInfo { - pub fn new_immutable(ty: PtrType) -> PtrInfo { - PtrInfo { mutable: false, ty } - } - - pub fn new_mutable(ty: PtrType) -> PtrInfo { - PtrInfo { mutable: true, ty } - } -} - /// Hash type. /// /// Used to distinguish between different hash types in the syscall signatures. @@ -651,104 +606,252 @@ pub enum HashType { SubjectId, } -/// Pointer type. -/// -/// Used to distinguish between different pointer types in the syscall signatures. -/// Basically it responds to different types from `gsys`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum PtrType { - BlockNumber, - BlockTimestamp, - SizedBufferStart { length_param_idx: usize }, - BufferStart, - Hash(HashType), - Gas, - Length, - Value, - - BlockNumberWithHash(HashType), - HashWithValue(HashType), - TwoHashes(HashType, HashType), - TwoHashesWithValue(HashType, HashType), +impl From for ValueType { + fn from(value: ParamType) -> Self { + use RegularParamType::*; - ErrorCode, + match value { + ParamType::Regular(regular_ptr) => match regular_ptr { + Length | Pointer(_) | Offset | DurationBlockNumber | DelayBlockNumber | Handler + | Alloc | Free | FreeUpperBound | Version => ValueType::I32, + Gas => ValueType::I64, + }, + ParamType::Error(_) => ValueType::I32, + } + } +} - ErrorWithReplyCode, - ErrorWithSignalCode, - ErrorWithGas, - ErrorWithHandle, - ErrorWithHash(HashType), - ErrorWithTwoHashes(HashType, HashType), - ErrorWithBlockNumberAndValue, +/// Syscall signature. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum SyscallSignature { + Fallible(FallibleSyscallSignature), + Infallible(InfallibleSyscallSignature), + System(SystemSyscallSignature), } -impl PtrType { - pub fn is_error(self) -> bool { - use PtrType::*; +impl SyscallSignature { + pub fn gr_fallible(fallible: impl Into) -> Self { + Self::Fallible(fallible.into()) + } + pub fn gr_infallible(infallible: impl Into) -> Self { + Self::Infallible(infallible.into()) + } + + pub fn system(system: impl Into) -> Self { + Self::System(system.into()) + } + + pub fn params(&self) -> &[ParamType] { match self { - ErrorCode - | ErrorWithReplyCode - | ErrorWithSignalCode - | ErrorWithGas - | ErrorWithHandle - | ErrorWithHash(_) - | ErrorWithTwoHashes(_, _) - | ErrorWithBlockNumberAndValue => true, - BlockNumber - | BlockTimestamp - | SizedBufferStart { .. } - | BufferStart - | Hash(_) - | Gas - | Length - | Value - | BlockNumberWithHash(_) - | HashWithValue(_) - | TwoHashes(_, _) - | TwoHashesWithValue(_, _) => false, + SyscallSignature::Fallible(fallible) => &fallible.0, + SyscallSignature::Infallible(infallible) => &infallible.0, + SyscallSignature::System(system) => &system.params, } } -} -impl From for ValueType { - fn from(value: ParamType) -> Self { - match value { - ParamType::Gas => ValueType::I64, - _ => ValueType::I32, + pub fn results(&self) -> Option<&[ValueType]> { + match self { + SyscallSignature::Fallible(_) | SyscallSignature::Infallible(_) => None, + SyscallSignature::System(system) => Some(&system.results), } } + + pub fn func_type(&self) -> FunctionType { + let (params, results) = match self { + SyscallSignature::Fallible(fallible) => (fallible.params(), Vec::new()), + SyscallSignature::Infallible(infallible) => (infallible.params(), Vec::new()), + SyscallSignature::System(system) => (system.params(), system.results().to_owned()), + }; + + FunctionType::new(params.iter().copied().map(Into::into).collect(), results) + } + + pub fn is_fallible(&self) -> bool { + matches!(self, SyscallSignature::Fallible(_)) + } + + pub fn is_infallible(&self) -> bool { + matches!(self, SyscallSignature::Infallible(_)) + } + + pub fn is_system(&self) -> bool { + matches!(self, SyscallSignature::System(_)) + } } -/// Syscall signature. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SyscallSignature { - pub params: Vec, - pub results: Vec, +pub struct FallibleSyscallSignature(Vec); + +impl FallibleSyscallSignature { + pub fn new(params: [RegularParamType; N], err_ptr: ErrPtr) -> Self { + let params = params + .into_iter() + .map(ParamType::Regular) + .chain(iter::once(err_ptr.into())) + .collect(); + + FallibleSyscallSignature(params) + } + + pub fn params(&self) -> &[ParamType] { + &self.0 + } } -impl SyscallSignature { - pub fn gr(params: [ParamType; N]) -> Self { - Self { - params: params.to_vec(), - results: Default::default(), - } +impl From<([RegularParamType; N], ErrPtr)> for FallibleSyscallSignature { + fn from((params, err_ptr): ([RegularParamType; N], ErrPtr)) -> Self { + FallibleSyscallSignature::new(params, err_ptr) + } +} + +impl From for FallibleSyscallSignature { + fn from(err_ptr: ErrPtr) -> Self { + FallibleSyscallSignature::new([], err_ptr) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct InfallibleSyscallSignature(Vec); + +impl InfallibleSyscallSignature { + pub fn new(params: [RegularParamType; N]) -> Self { + InfallibleSyscallSignature(params.into_iter().map(ParamType::Regular).collect()) } - pub fn system( - params: [ParamType; N], + pub fn params(&self) -> &[ParamType] { + &self.0 + } +} + +impl From<[RegularParamType; N]> for InfallibleSyscallSignature { + fn from(params: [RegularParamType; N]) -> Self { + InfallibleSyscallSignature::new(params) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SystemSyscallSignature { + params: Vec, + results: Vec, +} + +impl SystemSyscallSignature { + pub fn new( + params: [RegularParamType; N], results: [ValueType; M], ) -> Self { - Self { - params: params.to_vec(), + SystemSyscallSignature { + params: params.into_iter().map(ParamType::Regular).collect(), results: results.to_vec(), } } - pub fn func_type(&self) -> FunctionType { - FunctionType::new( - self.params.iter().copied().map(Into::into).collect(), - self.results.clone(), - ) + pub fn params(&self) -> &[ParamType] { + &self.params + } + + pub fn results(&self) -> &[ValueType] { + &self.results + } +} + +impl From<([RegularParamType; N], [ValueType; M])> + for SystemSyscallSignature +{ + fn from((params, results): ([RegularParamType; N], [ValueType; M])) -> Self { + SystemSyscallSignature::new(params, results) + } +} + +// TODO: issue write macros +mod pointers { + use super::{HashType, ParamType, RegularParamType}; + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub enum Ptr { + // Const ptrs. + BlockNumber, + BlockTimestamp, + SizedBufferStart { length_param_idx: usize }, + BufferStart, + Hash(HashType), + Gas, + Length, + Value, + BlockNumberWithHash(HashType), + HashWithValue(HashType), + TwoHashes(HashType, HashType), + TwoHashesWithValue(HashType, HashType), + // Mutable ptrs. + MutBlockNumber, + MutBlockTimestamp, + MutSizedBufferStart { length_param_idx: usize }, + MutBufferStart, + MutHash(HashType), + MutGas, + MutLength, + MutValue, + MutBlockNumberWithHash(HashType), + MutHashWithValue(HashType), + MutTwoHashes(HashType, HashType), + MutTwoHashesWithValue(HashType, HashType), + } + + impl Ptr { + pub fn is_mutable(self) -> bool { + use Ptr::*; + + match self { + BlockNumber + | BlockTimestamp + | SizedBufferStart { .. } + | BufferStart + | Hash(_) + | Gas + | Length + | Value + | BlockNumberWithHash(_) + | HashWithValue(_) + | TwoHashes(_, _) + | TwoHashesWithValue(_, _) => false, + MutBlockNumber + | MutBlockTimestamp + | MutSizedBufferStart { .. } + | MutBufferStart + | MutHash(_) + | MutGas + | MutLength + | MutValue + | MutBlockNumberWithHash(_) + | MutHashWithValue(_) + | MutTwoHashes(_, _) + | MutTwoHashesWithValue(_, _) => true, + } + } + } + + impl From for RegularParamType { + fn from(ptr: Ptr) -> RegularParamType { + RegularParamType::Pointer(ptr) + } + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub enum ErrPtr { + ErrorCode, + ErrorWithReplyCode, + ErrorWithSignalCode, + ErrorWithGas, + ErrorWithHandle, + ErrorWithHash(HashType), + ErrorWithTwoHashes(HashType, HashType), + ErrorWithBlockNumberAndValue, + } + + impl From for ParamType { + fn from(err_ptr: ErrPtr) -> ParamType { + ParamType::Error(err_ptr) + } } } diff --git a/utils/wasm-instrument/src/tests.rs b/utils/wasm-instrument/src/tests.rs index de674939ed2..e654144e439 100644 --- a/utils/wasm-instrument/src/tests.rs +++ b/utils/wasm-instrument/src/tests.rs @@ -19,7 +19,7 @@ use super::*; use crate::{ rules::CustomConstantCostRules, - syscalls::{ParamType, PtrInfo, PtrType, SyscallName}, + syscalls::{ParamType::*, Ptr, RegularParamType::*, SyscallName}, }; use alloc::format; use elements::Instruction::*; @@ -624,35 +624,33 @@ fn check_memory_array_pointers_definition_correctness() { for syscall in syscalls { let signature = syscall.signature(); let size_param_indexes = signature - .params + .params() .iter() .filter_map(|param_ty| match param_ty { - ParamType::Ptr(PtrInfo { - ty: PtrType::SizedBufferStart { length_param_idx }, - .. - }) => Some(*length_param_idx), + Regular(Pointer(Ptr::SizedBufferStart { length_param_idx })) => { + Some(*length_param_idx) + } _ => None, }); for idx in size_param_indexes { - assert_eq!(signature.params.get(idx), Some(&ParamType::Length)); + assert_eq!(signature.params().get(idx), Some(&Regular(Length))); } } } // Basically checks that mutable error pointer is always last in every fallible syscall params set. +// WARNING: this test must never fail, unless a huge redesign in syscalls signatures has occurred. #[test] fn check_syscall_err_ptr_position() { for syscall in SyscallName::instrumentable() { if syscall.is_fallible() { let signature = syscall.signature(); let err_ptr = signature - .params + .params() .last() .expect("fallible syscall has at least err ptr"); - assert!( - matches!(err_ptr, ParamType::Ptr(PtrInfo { mutable: true, ty }) if ty.is_error()) - ); + assert!(matches!(err_ptr, Error(_))); } } }