diff --git a/.github/actions/build-pruntime/action.yml b/.github/actions/build-pruntime/action.yml index fdf5b2629e..16c383b3d9 100644 --- a/.github/actions/build-pruntime/action.yml +++ b/.github/actions/build-pruntime/action.yml @@ -15,5 +15,4 @@ runs: with: name: pruntime-binaries path: | - ./standalone/pruntime/bin/pruntime - ./standalone/pruntime/bin/Rocket.toml + ./standalone/pruntime/bin/* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b0debb600a..594fc57a12 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -99,7 +99,7 @@ jobs: submodules: 'true' - uses: ./.github/actions/install_toolchain - name: Run cargo tests - run: cargo test -vv --workspace --exclude node-executor --exclude phala-node + run: cargo test --tests -vv --workspace --exclude node-executor --exclude phala-node cargo-clippy: name: Run cargo clippy diff --git a/Cargo.lock b/Cargo.lock index c6b4184d02..1a579791ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,7 +72,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -187,8 +187,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f270541caec49c15673b0af0e9a00143421ad4f118d2df7edcb68b627632f56" dependencies = [ "actix-router", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -400,9 +400,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "approx" @@ -487,8 +487,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "synstructure", ] @@ -499,8 +499,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "synstructure", ] @@ -511,8 +511,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -654,8 +654,8 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -671,8 +671,8 @@ version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -850,13 +850,35 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "regex", "rustc-hash", "shlex", ] +[[package]] +name = "bindgen" +version = "0.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2 1.0.53", + "quote 1.0.26", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which", +] + [[package]] name = "bitcoin" version = "0.29.2" @@ -1111,8 +1133,8 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb17c862a905d912174daa27ae002326fff56dc8b8ada50a0a5f0976cb174f0" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -1467,8 +1489,8 @@ checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2019,7 +2041,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -2101,8 +2123,8 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "scratch", "syn 1.0.109", ] @@ -2119,8 +2141,8 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2152,8 +2174,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2165,8 +2187,8 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "strsim", "syn 1.0.109", ] @@ -2178,7 +2200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -2189,7 +2211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core 0.14.4", - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -2305,8 +2327,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2316,8 +2338,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2337,8 +2359,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2358,8 +2380,8 @@ version = "0.99.17" source = "git+https://github.com/JelteF/derive_more#3ab6fcc0ce82d53508e904103b5e70bb280e2f76" dependencies = [ "convert_case", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "rustc_version 0.4.0", "syn 1.0.109", "unicode-xid 0.2.3", @@ -2398,7 +2420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" dependencies = [ "devise_core", - "quote 1.0.20", + "quote 1.0.26", ] [[package]] @@ -2408,9 +2430,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" dependencies = [ "bitflags", - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", "proc-macro2-diagnostics", - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -2517,8 +2539,8 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2583,8 +2605,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2604,8 +2626,8 @@ dependencies = [ "byteorder", "lazy_static", "proc-macro-error", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2719,8 +2741,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2739,8 +2761,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2759,8 +2781,8 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2780,8 +2802,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea83a3fbdc1d999ccfbcbee717eab36f8edf2d71693a23ce0d7cca19e085304c" dependencies = [ "darling 0.13.4", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -2995,8 +3017,8 @@ dependencies = [ "fixed", "paste", "proc-macro-error", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -3155,8 +3177,8 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -3264,8 +3286,8 @@ dependencies = [ "derive-syn-parse", "frame-support-procedural-tools", "itertools", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -3276,8 +3298,8 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#18 dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -3286,8 +3308,8 @@ name = "frame-support-procedural-tools-derive" version = "3.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -3392,9 +3414,9 @@ dependencies = [ [[package]] name = "fs_extra" -version = "1.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "fuchsia-cprng" @@ -3489,8 +3511,8 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -4157,8 +4179,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -4181,9 +4203,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "ink" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b4fc39f3bcab7e042becf5c9dbbebc179fff64924025753a5fafa016e8576d" +checksum = "0c0b81ae699fab87b67c4312430e234c1e5b99533aa830dab16cddc9da65cd7a" dependencies = [ "derive_more", "ink_env", @@ -4197,18 +4219,18 @@ dependencies = [ [[package]] name = "ink_allocator" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a54dbbaffb0f97bcae062e628dcdc9da4d3c9044f5a53fb2715a328b07221631" +checksum = "121758652007d56209c7f79af5cc8562b7e869df7ebb72456da79f2a9e72aeea" dependencies = [ "cfg-if", ] [[package]] name = "ink_codegen" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283b022679ef75898db5c28b89388412d93f91cea4f0b1443426901cb391b079" +checksum = "0da21ea8189beef99f92fcea3f07018e3278a0e084b86705d3b5e58c3ee38645" dependencies = [ "blake2", "derive_more", @@ -4221,8 +4243,8 @@ dependencies = [ "itertools", "log", "parity-scale-codec", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "serde", "serde_json", "syn 1.0.109", @@ -4230,24 +4252,24 @@ dependencies = [ [[package]] name = "ink_engine" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daed9b710cba6f50f1fa0372a7e8a47a35624d84af4ef2c3a8d34d4e96202d1c" +checksum = "d4ec97173506ba6f3cf966a42c0d5f776c2ef843da15854fa1f57d23d2be4ee4" dependencies = [ "blake2", "derive_more", "ink_primitives", "parity-scale-codec", - "secp256k1 0.26.0", + "secp256k1 0.27.0", "sha2 0.10.2", "sha3", ] [[package]] name = "ink_env" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41c6a3f4e740e27449f805ed47f536a35fb254ebcd03d2480014589331cda3e" +checksum = "639a8172a9911fc6f7384623d25ff6f0834d48b16f5c21e4b0eb656b3de1f877" dependencies = [ "arrayref", "blake2", @@ -4264,7 +4286,7 @@ dependencies = [ "paste", "rlibc", "scale-info", - "secp256k1 0.26.0", + "secp256k1 0.27.0", "sha2 0.10.2", "sha3", "static_assertions", @@ -4272,39 +4294,39 @@ dependencies = [ [[package]] name = "ink_ir" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946b940d26e69ded558daafead0979f25f2e9d7e2cf86027f250c3942aa4d0f1" +checksum = "8aeb30e90744ebf9cce7300a1d013ab91e1b84ebc9887ddabd9b7688c6ac20c1" dependencies = [ "blake2", "either", "itertools", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] [[package]] name = "ink_macro" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6642450e6169cfaf81717b1d62b2abae48a6b41d3f70f885b6aeff7bb14ea96b" +checksum = "968f443cf4f177c2cc9d147e33336de19700c8f7e01a6ad5942d9a324e9d3a6c" dependencies = [ "ink_codegen", "ink_ir", "ink_primitives", "parity-scale-codec", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "synstructure", ] [[package]] name = "ink_metadata" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfcfa666ada5729c7e4d3d986cd196365a2c469459fced4fa31dc6ad87c4d8f" +checksum = "8a8bb193f81ddda8329568ae05786e12a901ea1684c444f780440ecac2bd57b1" dependencies = [ "derive_more", "impl-serde", @@ -4316,18 +4338,18 @@ dependencies = [ [[package]] name = "ink_prelude" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8080235e5ae921975c2c7772fe9959e1b3c92b4d5a1afcfe104f93fb79aa268" +checksum = "050dcae91877df7def5fe4426df22c35d116bb24560e3e40d5650b09c7854061" dependencies = [ "cfg-if", ] [[package]] name = "ink_primitives" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b3f711d857d2de7c08158369cc32a762833ac211a00aac7931992094e25741" +checksum = "55850e661a97f3158fad3309e0188d6f2dcd5fc7de4c19b969c4c66988886f21" dependencies = [ "derive_more", "ink_prelude", @@ -4338,9 +4360,9 @@ dependencies = [ [[package]] name = "ink_storage" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2872a5ea4559433381b2d82b08b6acd33ce934b07a22ce951c6f00483680c950" +checksum = "f376d6fd2137ea2a42a9f08a83b29e309862a020a0841c0cb9a78c40f1e2e6e5" dependencies = [ "array-init", "cfg-if", @@ -4356,16 +4378,15 @@ dependencies = [ [[package]] name = "ink_storage_traits" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c90e11b60233ae5ab877854739da2c380a337cb31b3900cb50328821c0381b6" +checksum = "3a1ff58a3db0bb76b92981236172a3c4d02823996354006f07032e0d3b091024" dependencies = [ "ink_metadata", "ink_prelude", "ink_primitives", "parity-scale-codec", "scale-info", - "syn 1.0.109", ] [[package]] @@ -4389,8 +4410,8 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c7090af3d300424caa81976b8c97bca41cd70e861272c072e188ae082fb49f9" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -4631,8 +4652,8 @@ checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" dependencies = [ "heck 0.4.1", "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -5107,7 +5128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d527d5827582abd44a6d80c07ff8b50b4ee238a8979e05998474179e79dc400" dependencies = [ "heck 0.4.1", - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -5229,7 +5250,7 @@ version = "0.8.0+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" dependencies = [ - "bindgen", + "bindgen 0.60.1", "bzip2-sys", "cc", "glob", @@ -5418,7 +5439,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" dependencies = [ - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -5657,8 +5678,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" dependencies = [ "cfg-if", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -5742,8 +5763,8 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate", "proc-macro-error", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "synstructure", ] @@ -5793,8 +5814,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -6111,8 +6132,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -6497,8 +6518,8 @@ name = "pallet-contracts-proc-macro" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -7005,8 +7026,8 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -7170,9 +7191,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bfb81cf5c90a222db2fb7b3a7cbf8cc7f38dfb6647aca4d98edf8281f56ed5" +checksum = "dd684a725651d9588ef21f140a328b6b4f64e646b2e931f3e6f14f75eedf9980" dependencies = [ "blake2", "crc32fast", @@ -7184,7 +7205,6 @@ dependencies = [ "memmap2", "parking_lot 0.12.1", "rand 0.8.5", - "siphasher", "snap", ] @@ -7210,8 +7230,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -7331,9 +7351,9 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" dependencies = [ - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", "proc-macro2-diagnostics", - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -7394,8 +7414,8 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -7436,6 +7456,7 @@ dependencies = [ "chrono", "ciborium", "derive_more", + "environmental", "finality-grandpa", "fixed", "fixed-macro", @@ -7464,7 +7485,8 @@ dependencies = [ "phala-serde-more", "phala-trie-storage", "phala-types", - "pink", + "pink-extension-runtime", + "pink-runner", "prpc", "rand 0.8.5", "regex", @@ -7506,6 +7528,7 @@ dependencies = [ "log", "parity-scale-codec", "phala-crypto", + "phala-git-revision", "phala-mq", "phala-node-runtime", "phala-trie-storage", @@ -7563,6 +7586,10 @@ dependencies = [ "typenum", ] +[[package]] +name = "phala-git-revision" +version = "0.1.0" + [[package]] name = "phala-mq" version = "0.1.0" @@ -7836,6 +7863,14 @@ dependencies = [ "rocket", ] +[[package]] +name = "phala-sanitized-logger" +version = "0.1.0" +dependencies = [ + "env_logger 0.10.0", + "log", +] + [[package]] name = "phala-scheduler" version = "0.1.0" @@ -8025,8 +8060,8 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -8050,13 +8085,14 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pink" -version = "0.1.0" +version = "1.0.0" dependencies = [ + "anyhow", "call-trace", - "env_logger 0.9.0", "environmental", "frame-support", "frame-system", + "hash-db", "hex", "hex-literal", "impl-serde", @@ -8072,9 +8108,12 @@ dependencies = [ "parity-wasm", "paste", "phala-crypto", + "phala-git-revision", + "phala-sanitized-logger", "phala-serde-more", "phala-trie-storage", "phala-types", + "pink-capi", "pink-extension", "pink-extension-runtime", "reqwest", @@ -8090,10 +8129,23 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-trie", + "subxt", "wasmi-validation", "wat", ] +[[package]] +name = "pink-capi" +version = "0.1.0" +dependencies = [ + "bindgen 0.64.0", + "parity-scale-codec", + "pink-extension", + "pink-macro", + "sp-core", + "sp-runtime", +] + [[package]] name = "pink-extension" version = "0.4.1" @@ -8115,8 +8167,8 @@ dependencies = [ "ink_ir", "insta", "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "rustfmt-snippet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.109", "unzip3", @@ -8155,6 +8207,41 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "pink-macro" +version = "0.1.1" +dependencies = [ + "heck 0.4.1", + "insta", + "proc-macro-crate", + "proc-macro2 1.0.53", + "rustfmt-snippet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.109", +] + +[[package]] +name = "pink-runner" +version = "0.1.0" +dependencies = [ + "assert_matches", + "env_logger 0.10.0", + "environmental", + "im", + "insta", + "libc", + "log", + "once_cell", + "pallet-contracts-primitives", + "parity-scale-codec", + "phala-crypto", + "pink", + "pink-capi", + "pink-extension-runtime", + "serde", + "sp-runtime", + "sp-weights", +] + [[package]] name = "pink-s3" version = "0.4.1" @@ -8352,7 +8439,7 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" dependencies = [ - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", "syn 1.0.109", ] @@ -8386,8 +8473,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "version_check", ] @@ -8398,8 +8485,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "version_check", ] @@ -8420,9 +8507,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" dependencies = [ "unicode-ident", ] @@ -8433,8 +8520,8 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "version_check", "yansi", @@ -8472,8 +8559,8 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -8560,8 +8647,8 @@ checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" dependencies = [ "anyhow", "itertools", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -8573,8 +8660,8 @@ checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" dependencies = [ "anyhow", "itertools", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -8620,12 +8707,12 @@ dependencies = [ "itertools", "log", "multimap", - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", "prost 0.11.2", "prost-build 0.11.2", "prost-build 0.9.0", "prost-types 0.11.2", - "quote 1.0.20", + "quote 1.0.26", "syn 1.0.109", ] @@ -8653,8 +8740,8 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -8715,11 +8802,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", ] [[package]] @@ -8950,8 +9037,8 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a043824e29c94169374ac5183ac0ed43f5724dc4556b19568007486bd840fa1f" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -9182,8 +9269,8 @@ version = "0.7.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -9276,8 +9363,8 @@ dependencies = [ "devise", "glob", "indexmap", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "rocket_http", "syn 1.0.109", "unicode-xid 0.2.3", @@ -9431,7 +9518,7 @@ dependencies = [ name = "rustfmt-snippet" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", ] [[package]] @@ -9440,7 +9527,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f5e687f088721017e263dedd91e4c7f45f54d5b37afa6eea95fdc34a8b80c80" dependencies = [ - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", ] [[package]] @@ -9660,8 +9747,8 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -10580,8 +10667,8 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -10684,8 +10771,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -10828,11 +10915,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "secp256k1-sys 0.8.0", + "secp256k1-sys 0.8.1", ] [[package]] @@ -10846,9 +10933,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642a62736682fdd8c71da0eb273e453c8ac74e33b9fb310e22ba5b03ec7651ff" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" dependencies = [ "cc", ] @@ -10938,9 +11025,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.156" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] @@ -10968,13 +11055,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", - "syn 1.0.109", + "proc-macro2 1.0.53", + "quote 1.0.26", + "syn 2.0.8", ] [[package]] @@ -11244,7 +11331,7 @@ dependencies = [ "heck 0.4.1", "insta", "proc-macro-crate", - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", "rustfmt-snippet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.109", ] @@ -11420,8 +11507,8 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#18 dependencies = [ "blake2", "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -11660,8 +11747,8 @@ name = "sp-core-hashing-proc-macro" version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "sp-core-hashing", "syn 1.0.109", ] @@ -11680,8 +11767,8 @@ name = "sp-debug-derive" version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -11900,8 +11987,8 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#18 dependencies = [ "Inflector", "proc-macro-crate", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -12067,8 +12154,8 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -12209,8 +12296,8 @@ dependencies = [ "either", "heck 0.4.1", "once_cell", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "sha2 0.10.2", "sqlx-core", "sqlx-rt", @@ -12237,8 +12324,8 @@ checksum = "fa0813c10b9dbdc842c2305f949f724c64866e4ef4d09c9151e96f6a2106773c" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "serde", "serde_json", "unicode-xid 0.2.3", @@ -12306,8 +12393,8 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases", "memchr", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -12331,8 +12418,8 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "serde", "serde_derive", "syn 1.0.109", @@ -12345,8 +12432,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "serde", "serde_derive", "serde_json", @@ -12392,8 +12479,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "rustversion", "syn 1.0.109", ] @@ -12656,8 +12743,8 @@ dependencies = [ "hex", "jsonrpsee", "parity-scale-codec", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "scale-info", "subxt-metadata", "syn 1.0.109", @@ -12702,8 +12789,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9" +dependencies = [ + "proc-macro2 1.0.53", + "quote 1.0.26", "unicode-ident", ] @@ -12713,8 +12811,8 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "unicode-xid 0.2.3", ] @@ -12831,22 +12929,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", - "syn 1.0.109", + "proc-macro2 1.0.53", + "quote 1.0.26", + "syn 2.0.8", ] [[package]] @@ -12945,8 +13043,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "standback", "syn 1.0.109", ] @@ -13030,8 +13128,8 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -13190,8 +13288,8 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -13437,7 +13535,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.3", - "rand 0.4.6", + "rand 0.8.5", "static_assertions", ] @@ -13782,8 +13880,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "wasm-bindgen-shared", ] @@ -13806,7 +13904,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ - "quote 1.0.20", + "quote 1.0.26", "wasm-bindgen-macro-support", ] @@ -13816,8 +13914,8 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -14029,8 +14127,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2894c70a832e05a8734515470322d402b7d4826a9c932e39f8080f516b9acae4" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -14157,7 +14255,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd26fe00d08bd2119870b017d13413dfbd51e7750b6634d649fc7a7bbc057b85" dependencies = [ - "proc-macro2 1.0.52", + "proc-macro2 1.0.53", "syn 1.0.109", "wasmer-wit-bindgen-gen-core", "wasmer-wit-bindgen-gen-rust-wasm", @@ -15109,7 +15207,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#298b4aefe1b07b864b6ef7ede041d73f6a0a7f93" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" dependencies = [ "bounded-collections", "derivative", @@ -15125,11 +15223,11 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#298b4aefe1b07b864b6ef7ede041d73f6a0a7f93" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" dependencies = [ "Inflector", - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", ] @@ -15198,8 +15296,8 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ - "proc-macro2 1.0.52", - "quote 1.0.20", + "proc-macro2 1.0.53", + "quote 1.0.26", "syn 1.0.109", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index 473f6daded..ae4da6467a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [profile.release] -panic = "unwind" +panic = "abort" opt-level = 3 # make sure dev builds with backtrace do @@ -30,6 +30,7 @@ exclude = [ "vendor/ring", "standalone/pruntime", "standalone/prouter", + "standalone/crate-version", "crates/pink-drivers/system", "crates/pink-drivers/sidevm_deployer", "crates/pink-drivers/tokenomic", @@ -51,6 +52,7 @@ members = [ "crates/phala-crypto", "crates/phala-node-rpc-ext", "crates/phala-types", + "crates/phala-git-revision", "crates/prpc", "crates/prpc-build", "crates/phactory", @@ -59,12 +61,16 @@ members = [ "crates/phala-types", "crates/phala-async-executor", "crates/phala-allocator", + "crates/phala-sanitized-logger", "crates/wasmer-tunables", "crates/phala-rocket-middleware", - "crates/pink", + "crates/pink/runner", + "crates/pink/runtime", + "crates/pink/runtime/unittests", + "crates/pink/capi", + "crates/pink/macro", "crates/pink/pink-extension", "crates/pink/pink-extension-runtime", - "crates/pink/unittests", "crates/pink-libs/s3", "crates/pink-libs/utils", "crates/pink-libs/subrpc", diff --git a/crates/phactory/Cargo.toml b/crates/phactory/Cargo.toml index 27e4d2c705..e2abdba542 100644 --- a/crates/phactory/Cargo.toml +++ b/crates/phactory/Cargo.toml @@ -32,7 +32,8 @@ phala-serde-more = { path = "../phala-serde-more" } phala-crypto = { path = "../phala-crypto", features = ["getrandom", "stream"] } prpc = { path = "../prpc" } -pink = { path = "../pink" } +pink = { path = "../pink/runner", package = "pink-runner" } +pink-extension-runtime = { path = "../pink/pink-extension-runtime" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", features = ["disable_panic_handler", "disable_oom", "disable_allocator"] } sp-runtime-interface = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", features = ["disable_target_static_assertions"] } @@ -81,6 +82,8 @@ sgx-api-lite = { path = "../sgx-api-lite" } reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "socks"] } reqwest-env-proxy = { path = "../reqwest-env-proxy" } +environmental = "1" + [dev-dependencies] insta = "1.7.2" rmp-serde = "1" diff --git a/crates/phactory/api/Cargo.toml b/crates/phactory/api/Cargo.toml index 9b0f483bf3..e5ffae4fe3 100644 --- a/crates/phactory/api/Cargo.toml +++ b/crates/phactory/api/Cargo.toml @@ -24,6 +24,7 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false, features = ["full_crypto"] } sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false, features = ["full_crypto"] } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false } +phala-git-revision = { path = "../../phala-git-revision" } # for pruntime_client async-trait = "0.1.57" diff --git a/crates/phactory/api/build.rs b/crates/phactory/api/build.rs index b47294b436..bd6484ffc7 100644 --- a/crates/phactory/api/build.rs +++ b/crates/phactory/api/build.rs @@ -1,5 +1,3 @@ -use std::process::Command; - fn main() { use tera::{Context, Tera}; @@ -29,28 +27,4 @@ fn main() { builder .compile(&["pruntime_rpc.proto"], &[render_dir]) .unwrap(); - export_git_revision(); -} - -fn export_git_revision() { - let cmd = Command::new("git") - .args(["rev-parse", "HEAD"]) - .output() - .unwrap() - .stdout; - let revision = String::from_utf8_lossy(&cmd); - let revision = revision.trim(); - let dirty = !Command::new("git") - .args(["diff", "HEAD", "--quiet"]) - .output() - .unwrap() - .status - .success(); - let tail = if dirty { "-dirty" } else { "" }; - if revision.is_empty() { - println!("cargo:warning=⚠️ Failed to get git revision for pRuntime."); - println!("cargo:warning=⚠️ Please ensure you have git installed and are compiling from a git repository."); - } - println!("cargo:rustc-env=PHALA_GIT_REVISION={revision}{tail}"); - println!("cargo:rerun-if-changed=always-rerun"); } diff --git a/crates/phactory/api/proto b/crates/phactory/api/proto index ea55342eef..3ec8f4d40d 160000 --- a/crates/phactory/api/proto +++ b/crates/phactory/api/proto @@ -1 +1 @@ -Subproject commit ea55342eef5626ab4d618ac180b561f323f00f20 +Subproject commit 3ec8f4d40deaa2acbab56ee3ba87ce246a944fed diff --git a/crates/phactory/api/src/ecall_args.rs b/crates/phactory/api/src/ecall_args.rs index 7044986841..1bcb34d66e 100644 --- a/crates/phactory/api/src/ecall_args.rs +++ b/crates/phactory/api/src/ecall_args.rs @@ -1,6 +1,6 @@ -use alloc::string::{String, ToString}; +use alloc::string::String; use parity_scale_codec::{Decode, Encode}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Encode, Decode, Default, Clone)] pub struct InitArgs { @@ -41,6 +41,4 @@ pub struct InitArgs { pub safe_mode_level: u8, } -pub fn git_revision() -> String { - env!("PHALA_GIT_REVISION").to_string() -} +pub use phala_git_revision::git_revision; diff --git a/crates/phactory/api/src/proto_generated/mod.rs b/crates/phactory/api/src/proto_generated/mod.rs index 31aa6e80ec..f6b936e31a 100644 --- a/crates/phactory/api/src/proto_generated/mod.rs +++ b/crates/phactory/api/src/proto_generated/mod.rs @@ -23,7 +23,7 @@ pub struct Info<'a> { pub rpeak: u64, pub mfree: u64, pub whdr: bool, - pub cluster: bool, + pub cluster: u64, pub gblk: u32, } @@ -47,8 +47,8 @@ impl PhactoryInfo { cluster: self .system .as_ref() - .map(|s| s.number_of_clusters > 0) - .unwrap_or(false), + .map(|s| s.number_of_clusters) + .unwrap_or_default(), gblk: self.system.as_ref().map(|s| s.genesis_block).unwrap_or(0), } } diff --git a/crates/phactory/src/contracts/pink.rs b/crates/phactory/src/contracts/pink.rs index 0c2f44f84c..df4c20406b 100644 --- a/crates/phactory/src/contracts/pink.rs +++ b/crates/phactory/src/contracts/pink.rs @@ -1,18 +1,34 @@ use std::time::Duration; -use crate::contracts; -use crate::system::{TransactionError, TransactionResult}; -use anyhow::{anyhow, Result}; +use crate::{ + contracts::{self, QueryContext, TransactionContext}, + system::{TransactionError, TransactionResult}, +}; +use anyhow::Result; use parity_scale_codec::{Decode, Encode}; -use phala_mq::{ContractClusterId, ContractId, MessageOrigin}; -use phala_types::contract::ConvertTo; -use pink::runtime::{BoxedEventCallbacks, EventCallbacks, ExecSideEffects}; -use pink::types::Weight; -use pink::weights::constants::WEIGHT_REF_TIME_PER_SECOND; -use runtime::{AccountId, BlockNumber, Hash}; +use phala_crypto::sr25519::Persistence; +use phala_mq::{ContractClusterId, MessageOrigin}; +use phala_types::contract::messaging::ResourceType; +use pink::{ + capi::v1::{ + ecall::{ECalls, ECallsRo}, + ocall::{ExecContext, HttpRequest, HttpRequestError, HttpResponse, OCalls, StorageChanges}, + }, + local_cache::{self, StorageQuotaExceeded}, + runtimes::v1::using_ocalls, + types::ExecutionMode, +}; +use serde::{Deserialize, Serialize}; use sidevm::service::{Command as SidevmCommand, CommandSender, SystemMessage}; +use sp_core::sr25519; + +use ::pink::{ + capi::v1, + constants::WEIGHT_REF_TIME_PER_SECOND, + types::{AccountId, Balance, ExecSideEffects, Hash, TransactionArguments}, +}; -pub use phala_types::contract::InkCommand as Command; +pub use phala_types::contract::InkCommand; #[derive(Debug, Encode, Decode)] pub enum Query { @@ -22,6 +38,8 @@ pub enum Query { deposit: u128, /// Amount of tokens transfer from the caller to the target contract. transfer: u128, + /// Whether to use the gas estimation mode. + estimating: bool, }, SidevmQuery(Vec), InkInstantiate { @@ -50,117 +68,482 @@ pub enum QueryError { Timeout, } -#[derive(Encode, Decode, Clone)] -pub struct Pink { - pub(crate) instance: pink::Contract, - cluster_id: ContractClusterId, +#[derive(Serialize, Deserialize, Default, Clone)] +pub struct ClusterConfig { + pub log_handler: Option, + pub runtime_version: (u32, u32), } -impl Pink { - pub fn instantiate( - cluster_id: ContractClusterId, - code_hash: Hash, - input_data: Vec, - salt: Vec, - in_query: bool, - tx_args: ::pink::TransactionArguments, - ) -> Result<(Self, ExecSideEffects)> { - let origin = tx_args.origin.clone(); - let (instance, effects) = - pink::Contract::new(code_hash, input_data, salt, in_query, tx_args).map_err(|err| { - anyhow!("Instantiate contract failed: {:?} origin={:?}", err, origin,) - })?; - Ok(( +#[derive(Serialize, Deserialize, Clone)] +pub struct Cluster { + pub id: ContractClusterId, + pub config: ClusterConfig, + pub storage: pink::storage::ClusterStorage, +} + +pub struct RuntimeHandleMut<'a> { + cluster: &'a mut Cluster, + logger: Option, + pub(crate) effects: Option, +} + +impl RuntimeHandleMut<'_> { + fn readonly(&self) -> RuntimeHandle { + RuntimeHandle { + cluster: self.cluster, + logger: self.logger.clone(), + } + } + fn execute_mut(&mut self, f: impl FnOnce() -> T) -> T { + using_ocalls(self, f) + } +} + +pub struct RuntimeHandle<'a> { + cluster: &'a Cluster, + logger: Option, +} + +impl RuntimeHandle<'_> { + fn dup(&self) -> RuntimeHandle { + RuntimeHandle { + cluster: self.cluster, + logger: self.logger.clone(), + } + } + fn execute(&self, f: impl FnOnce() -> T) -> T { + using_ocalls(&mut self.dup(), f) + } + fn ensure_version(&self, version: (u32, u32)) { + if self.cluster.config.runtime_version != version { + panic!( + "Cross call {version:?} is not supported in runtime version {:?}", + self.cluster.config.runtime_version + ); + } + } +} + +pub(crate) mod context { + use std::time::{Duration, Instant}; + + use pink::{ + capi::v1::ocall::ExecContext, + types::{BlockNumber, ExecutionMode}, + }; + + use crate::ChainStorage; + + environmental::environmental!(exec_context: trait GetContext); + + pub trait GetContext { + fn chain_storage(&self) -> &ChainStorage; + fn exec_context(&self) -> ExecContext; + fn worker_pubkey(&self) -> [u8; 32]; + fn call_elapsed(&self) -> Duration; + } + + pub struct ContractExecContext { + pub mode: ExecutionMode, + pub now_ms: u64, + pub block_number: BlockNumber, + pub worker_pubkey: [u8; 32], + pub chain_storage: ChainStorage, + pub start_at: Instant, + } + + impl ContractExecContext { + pub fn new( + mode: ExecutionMode, + now_ms: u64, + block_number: BlockNumber, + worker_pubkey: [u8; 32], + chain_storage: ChainStorage, + ) -> Self { Self { - cluster_id, - instance, - }, - effects, - )) + mode, + now_ms, + block_number, + worker_pubkey, + chain_storage, + start_at: Instant::now(), + } + } } - pub fn from_address(address: AccountId, cluster_id: ContractClusterId) -> Self { - let instance = pink::Contract::from_address(address); - Self { - instance, - cluster_id, + impl GetContext for ContractExecContext { + fn chain_storage(&self) -> &ChainStorage { + &self.chain_storage + } + + fn exec_context(&self) -> ExecContext { + ExecContext { + mode: self.mode, + block_number: self.block_number, + now_ms: self.now_ms, + } + } + + fn worker_pubkey(&self) -> [u8; 32] { + self.worker_pubkey + } + + fn call_elapsed(&self) -> Duration { + self.start_at.elapsed() } } - pub fn id(&self) -> ContractId { - self.instance.address.convert_to() + pub fn get() -> ExecContext { + exec_context::with(|ctx| ctx.exec_context()).unwrap_or_default() + } + + pub fn using(ctx: &mut impl GetContext, f: impl FnOnce() -> T) -> T { + exec_context::using(ctx, f) + } + + pub fn with(f: impl FnOnce(&dyn GetContext) -> T) -> T { + exec_context::with(|ctx| f(ctx)).expect("exec_context not set") + } + + pub fn worker_pubkey() -> [u8; 32] { + exec_context::with(|ctx| ctx.worker_pubkey()).unwrap_or_default() } - pub fn address(&self) -> AccountId { - self.instance.address.clone() + pub fn call_elapsed() -> Duration { + exec_context::with(|ctx| ctx.call_elapsed()).unwrap_or_else(|| Duration::from_secs(0)) } - pub fn set_on_block_end_selector(&mut self, selector: u32, gas_limit: u64) { - self.instance.set_on_block_end_selector(selector, gas_limit) + pub fn time_remaining() -> u64 { + const MAX_QUERY_TIME: Duration = Duration::from_secs(10); + MAX_QUERY_TIME.saturating_sub(call_elapsed()).as_millis() as _ } } -impl Pink { - pub(crate) async fn handle_query( +impl OCalls for RuntimeHandle<'_> { + fn storage_root(&self) -> Option { + self.cluster.storage.root() + } + + fn storage_get(&self, key: Vec) -> Option> { + self.cluster.storage.get(&key).map(|(_rc, val)| val.clone()) + } + + fn storage_commit(&mut self, _root: Hash, _changes: StorageChanges) { + panic!("storage_commit called on readonly cluster"); + } + + fn log_to_server(&self, contract: AccountId, level: u8, message: String) { + let Some(log_handler) = self.logger.as_ref() else { + return; + }; + let context = self.exec_context(); + let msg = SidevmCommand::PushSystemMessage(SystemMessage::PinkLog { + block_number: context.block_number, + timestamp_ms: std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as _, + exec_mode: context.mode.display().into(), + contract: contract.into(), + level, + message, + }); + if log_handler.try_send(msg).is_err() { + error!("Pink send log to server failed"); + } + } + + fn emit_side_effects(&mut self, _effects: ExecSideEffects) {} + + fn exec_context(&self) -> ExecContext { + context::get() + } + + fn worker_pubkey(&self) -> [u8; 32] { + context::worker_pubkey() + } + + fn cache_get(&self, contract: Vec, key: Vec) -> Option> { + if !context::get().mode.is_query() { + return None; + } + local_cache::get(&contract, &key) + } + + fn cache_set( &self, + contract: Vec, + key: Vec, + value: Vec, + ) -> Result<(), StorageQuotaExceeded> { + if context::get().mode.is_estimating() { + return Ok(()); + } + local_cache::set(&contract, &key, &value) + } + + fn cache_set_expiration(&self, contract: Vec, key: Vec, expiration: u64) { + if context::get().mode.is_estimating() { + return; + } + local_cache::set_expiration(&contract, &key, expiration) + } + + fn cache_remove(&self, contract: Vec, key: Vec) -> Option> { + if context::get().mode.is_estimating() { + return None; + } + local_cache::remove(&contract, &key) + } + + fn latest_system_code(&self) -> Vec { + context::with(|ctx| ctx.chain_storage().pink_system_code().1) + } + + fn http_request( + &self, + _contract: AccountId, + request: HttpRequest, + ) -> Result { + pink_extension_runtime::http_request(request, context::time_remaining()) + } +} + +impl OCalls for RuntimeHandleMut<'_> { + fn storage_root(&self) -> Option { + self.readonly().storage_root() + } + + fn storage_get(&self, key: Vec) -> Option> { + self.readonly().storage_get(key) + } + + fn storage_commit(&mut self, root: Hash, changes: StorageChanges) { + self.cluster.storage.commit(root, changes); + } + + fn log_to_server(&self, contract: AccountId, level: u8, message: String) { + self.readonly().log_to_server(contract, level, message) + } + + fn emit_side_effects(&mut self, effects: ExecSideEffects) { + self.effects = Some(effects); + } + + fn exec_context(&self) -> ExecContext { + self.readonly().exec_context() + } + + fn worker_pubkey(&self) -> [u8; 32] { + self.readonly().worker_pubkey() + } + + fn cache_get(&self, contract: Vec, key: Vec) -> Option> { + self.readonly().cache_get(contract, key) + } + + fn cache_set( + &self, + contract: Vec, + key: Vec, + value: Vec, + ) -> Result<(), StorageQuotaExceeded> { + self.readonly().cache_set(contract, key, value) + } + + fn cache_set_expiration(&self, contract: Vec, key: Vec, expiration: u64) { + self.readonly() + .cache_set_expiration(contract, key, expiration) + } + + fn cache_remove(&self, contract: Vec, key: Vec) -> Option> { + self.readonly().cache_remove(contract, key) + } + + fn latest_system_code(&self) -> Vec { + self.readonly().latest_system_code() + } + + fn http_request( + &self, + contract: AccountId, + request: HttpRequest, + ) -> Result { + self.readonly().http_request(contract, request) + } +} + +impl v1::CrossCall for RuntimeHandle<'_> { + fn cross_call(&self, call_id: u32, data: &[u8]) -> Vec { + self.ensure_version((1, 0)); + self.execute(move || ::pink::runtimes::v1::RUNTIME.ecall(call_id, data)) + } +} + +impl v1::CrossCall for RuntimeHandleMut<'_> { + fn cross_call(&self, call_id: u32, data: &[u8]) -> Vec { + self.readonly().ensure_version((1, 0)); + self.readonly() + .execute(move || ::pink::runtimes::v1::RUNTIME.ecall(call_id, data)) + } +} + +impl v1::CrossCallMut for RuntimeHandleMut<'_> { + fn cross_call_mut(&mut self, call_id: u32, data: &[u8]) -> Vec { + self.readonly().ensure_version((1, 0)); + self.execute_mut(move || ::pink::runtimes::v1::RUNTIME.ecall(call_id, data)) + } +} + +impl v1::ECall for RuntimeHandle<'_> {} +impl v1::ECall for RuntimeHandleMut<'_> {} + +impl Cluster { + pub fn new( + id: &ContractClusterId, + cluster_key: &sr25519::Pair, + runtime_version: (u32, u32), + ) -> Self { + let mut cluster = Cluster { + id: *id, + storage: Default::default(), + config: ClusterConfig { + runtime_version, + ..Default::default() + }, + }; + let mut runtime = cluster.default_runtime_mut(); + runtime.set_key(cluster_key.dump_secret_key()); + cluster + } + + pub fn default_runtime(&self) -> RuntimeHandle { + self.runtime(None) + } + + pub fn default_runtime_mut(&mut self) -> RuntimeHandleMut { + self.runtime_mut(None) + } + + pub fn runtime(&self, logger: Option) -> RuntimeHandle { + RuntimeHandle { + cluster: self, + logger, + } + } + + pub fn runtime_mut(&mut self, logger: Option) -> RuntimeHandleMut { + RuntimeHandleMut { + cluster: self, + logger, + effects: None, + } + } + + pub fn key(&self) -> sr25519::Pair { + let raw_key = self + .default_runtime() + .get_key() + .expect("cluster key not set"); + sr25519::Pair::restore_from_secret_key(&raw_key) + } + + pub fn system_contract(&self) -> Option { + self.default_runtime().system_contract() + } + + pub fn code_hash(&self, address: &AccountId) -> Option { + self.default_runtime().code_hash(address.clone()) + } + + pub fn upload_resource( + &mut self, + origin: &AccountId, + resource_type: ResourceType, + resource_data: Vec, + ) -> Result { + match resource_type { + ResourceType::InkCode => { + self.default_runtime_mut() + .upload_code(origin.clone(), resource_data, true) + } + ResourceType::SidevmCode => self + .default_runtime_mut() + .upload_sidevm_code(origin.clone(), resource_data), + ResourceType::IndeterministicInkCode => { + self.default_runtime_mut() + .upload_code(origin.clone(), resource_data, false) + } + } + } + + pub fn get_resource(&self, resource_type: ResourceType, hash: &Hash) -> Option> { + match resource_type { + ResourceType::InkCode => None, + ResourceType::SidevmCode => self.default_runtime().get_sidevm_code(*hash), + ResourceType::IndeterministicInkCode => None, + } + } + + pub fn deposit(&mut self, who: &::pink::types::AccountId, amount: Balance) { + self.default_runtime_mut().deposit(who.clone(), amount) + } + + pub(crate) async fn handle_query( + &mut self, + contract_id: &AccountId, origin: Option<&AccountId>, req: Query, - context: &mut contracts::QueryContext, - side_effects: &mut ExecSideEffects, - ) -> Result { + context: QueryContext, + ) -> Result<(Response, Option), QueryError> { match req { Query::InkMessage { payload: input_data, deposit, transfer, + estimating, } => { let _guard = context .query_scheduler - .acquire(self.id(), context.weight) + .acquire(contract_id.clone(), context.weight) .await .or(Err(QueryError::ServiceUnavailable))?; - let origin = origin.cloned().ok_or(QueryError::BadOrigin)?; - let storage = &mut context.storage; - if deposit > 0 { - storage.deposit(&origin, deposit); - } - let args = ::pink::TransactionArguments { - origin, - now: context.now_ms, - block_number: context.block_number, - storage, - transfer, - gas_limit: Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND * 10, u64::MAX), - gas_free: true, - storage_deposit_limit: None, - callbacks: ContractEventCallback::from_log_sender( - &context.log_handler, - context.block_number, - ), + let mode = if estimating { + ExecutionMode::Estimating + } else { + ExecutionMode::Query }; - let (ink_result, effects) = self.instance.bare_call(input_data, true, args); - if let Some(log_handler) = &context.log_handler { - if !ink_result.debug_message.is_empty() { - ContractEventCallback::new(log_handler.clone(), context.block_number) - .emit_log( - &self.address(), - true, - log::Level::Debug as usize as _, - String::from_utf8_lossy(&ink_result.debug_message).into_owned(), - ); - } - } - if ink_result.result.is_err() { - log::error!("Pink [{:?}] query exec error: {:?}", self.id(), ink_result); - if !ink_result.debug_message.is_empty() { - let message = String::from_utf8_lossy(&ink_result.debug_message); - log::error!("Pink [{:?}] buffer: {:?}", self.id(), message); + let mut ctx = context::ContractExecContext::new( + mode, + context.now_ms, + context.block_number, + context.worker_pubkey, + context.chain_storage, + ); + let log_handler = context.log_handler.clone(); + context::using(&mut ctx, move || { + let origin = origin.cloned().ok_or(QueryError::BadOrigin)?; + let mut runtime = self.runtime_mut(log_handler); + if deposit > 0 { + runtime.deposit(origin.clone(), deposit); } - } else { - *side_effects = effects.into_query_only_effects(); - } - Ok(Response::Payload(ink_result.encode())) + let args = TransactionArguments { + origin, + transfer, + gas_limit: WEIGHT_REF_TIME_PER_SECOND * 10, + gas_free: true, + storage_deposit_limit: None, + }; + let ink_result = + runtime.contract_call(contract_id.clone(), input_data, mode, args); + let effects = if mode.is_estimating() { + None + } else { + runtime.effects.take().map(|e| e.into_query_only_effects()) + }; + Ok((Response::Payload(ink_result), effects)) + }) } Query::SidevmQuery(payload) => { let handle = context @@ -192,6 +575,7 @@ impl Pink { }) .await .or(Err(QueryError::Timeout))? + .map(|response| (response, None)) } Query::InkInstantiate { code_hash, @@ -202,60 +586,59 @@ impl Pink { } => { let _guard = context .query_scheduler - .acquire(self.id(), context.weight) + .acquire(contract_id.clone(), context.weight) .await .or(Err(QueryError::ServiceUnavailable))?; let origin = origin.cloned().ok_or(QueryError::BadOrigin)?; - let storage = &mut context.storage; - if deposit > 0 { - storage.deposit(&origin, deposit); - } - let args = ::pink::TransactionArguments { - origin, - now: context.now_ms, - block_number: context.block_number, - storage, - transfer, - gas_limit: Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND * 10, u64::MAX), - gas_free: true, - storage_deposit_limit: None, - callbacks: ContractEventCallback::from_log_sender( - &context.log_handler, - context.block_number, - ), - }; - let (ink_result, _effects) = - ::pink::Contract::instantiate(code_hash, instantiate_data, salt, true, args); - if ink_result.result.is_err() { - log::error!( - "Pink [{:?}] est instantiate error: {:?}", - self.id(), - ink_result + let mut ctx = context::ContractExecContext::new( + ExecutionMode::Estimating, + context.now_ms, + context.block_number, + context.worker_pubkey, + context.chain_storage, + ); + let log_handler = context.log_handler.clone(); + context::using(&mut ctx, move || { + let mut runtime = self.runtime_mut(log_handler); + if deposit > 0 { + runtime.deposit(origin.clone(), deposit); + } + let args = TransactionArguments { + origin, + transfer, + gas_limit: WEIGHT_REF_TIME_PER_SECOND * 10, + gas_free: true, + storage_deposit_limit: None, + }; + let ink_result = runtime.contract_instantiate( + code_hash, + instantiate_data, + salt, + ExecutionMode::Estimating, + args, ); - } - Ok(Response::Payload(ink_result.encode())) + Ok((Response::Payload(ink_result), None)) + }) } } } pub(crate) fn handle_command( &mut self, + contract_id: &AccountId, origin: MessageOrigin, - cmd: Command, - context: &mut contracts::TransactionContext, + cmd: InkCommand, + context: &mut TransactionContext, ) -> TransactionResult { match cmd { - Command::InkMessage { + InkCommand::InkMessage { nonce, message, transfer, gas_limit, storage_deposit_limit, } => { - let storage = cluster_storage(context.contract_clusters, &self.cluster_id) - .expect("Pink cluster should always exists!"); - let mut gas_free = false; let origin: runtime::AccountId = match origin { MessageOrigin::AccountId(origin) => origin.0.into(), @@ -263,348 +646,76 @@ impl Pink { // The caller will be set to the system contract if it's from a pallet call // and without charging for gas gas_free = true; - storage - .system_contract() + self.system_contract() .expect("BUG: system contract missing") } _ => return Err(TransactionError::BadOrigin), }; - let args = ::pink::TransactionArguments { + let args = TransactionArguments { origin: origin.clone(), - now: context.block.now_ms, - block_number: context.block.block_number, - storage, transfer, - gas_limit: Weight::from_ref_time(gas_limit), + gas_limit, gas_free, storage_deposit_limit, - callbacks: ContractEventCallback::from_log_sender( - &context.log_handler, - context.block.block_number, - ), }; - let (result, effects) = self.instance.bare_call(message, false, args); + let mut runtime = self.runtime_mut(context.log_handler.clone()); + let output = runtime.contract_call( + contract_id.clone(), + message, + ExecutionMode::Transaction, + args, + ); if let Some(log_handler) = &context.log_handler { let msg = SidevmCommand::PushSystemMessage(SystemMessage::PinkMessageOutput { origin: origin.into(), - contract: self.instance.address.clone().into(), + contract: *contract_id.as_ref(), block_number: context.block.block_number, nonce: nonce.into_inner(), - output: result.result.encode(), + output, }); if log_handler.try_send(msg).is_err() { error!("Pink emit message output to log handler failed"); } - if !result.debug_message.is_empty() { - ContractEventCallback::new(log_handler.clone(), context.block.block_number) - .emit_log( - &self.instance.address, - false, - log::Level::Debug as usize as _, - String::from_utf8_lossy(&result.debug_message).into_owned(), - ); - } - } - - if let Err(err) = result.result { - log::error!("Pink [{:?}] command exec error: {:?}", self.id(), err); - if !result.debug_message.is_empty() { - let message = String::from_utf8_lossy(&result.debug_message); - log::error!("Pink [{:?}] buffer: {:?}", self.id(), message); - } - return Err(TransactionError::Other(format!( - "Call contract method failed: {err:?}" - ))); } - Ok(effects) + Ok(runtime.effects) } } } - pub(crate) fn on_block_end( - &mut self, - context: &mut contracts::TransactionContext, - ) -> TransactionResult { - let storage = cluster_storage(context.contract_clusters, &self.cluster_id) - .expect("Pink cluster should always exists!"); - let effects = self - .instance - .on_block_end( - storage, - context.block.block_number, - context.block.now_ms, - ContractEventCallback::from_log_sender( - &context.log_handler, - context.block.block_number, - ), - ) - .map_err(|err| { - log::error!("Pink [{:?}] on_block_end exec error: {:?}", self.id(), err); - TransactionError::Other(format!("Call contract on_block_end failed: {err:?}")) - })?; - Ok(effects) - } - pub(crate) fn snapshot(&self) -> Self { self.clone() } } -fn cluster_storage<'a>( - clusters: &'a mut cluster::ClusterKeeper, - cluster_id: &ContractClusterId, -) -> Result<&'a mut pink::Storage> { - clusters - .get_cluster_storage_mut(cluster_id) - .ok_or_else(|| anyhow!("Contract cluster {:?} not found! qed!", cluster_id)) -} - -pub mod cluster { - use anyhow::{Context, Result}; - use parity_scale_codec::Decode; - use phala_crypto::sr25519::{Persistence, Sr25519SecretKey, KDF}; - use phala_mq::{ContractClusterId, ContractId}; - use phala_serde_more as more; - use phala_types::contract::messaging::ResourceType; - use pink::{ - types::{AccountId, Balance, Hash}, - weights::Weight, - }; - use serde::{Deserialize, Serialize}; - use sp_core::sr25519; - use sp_runtime::{AccountId32, DispatchError}; - use std::collections::{BTreeMap, BTreeSet}; - - #[derive(Default, Serialize, Deserialize)] - pub struct ClusterKeeper { - clusters: BTreeMap, - } - - impl ClusterKeeper { - pub fn is_empty(&self) -> bool { - self.clusters.is_empty() - } - - pub fn len(&self) -> usize { - self.clusters.len() - } - - pub fn get_cluster_storage_mut( - &mut self, - cluster_id: &ContractClusterId, - ) -> Option<&mut pink::Storage> { - Some(&mut self.clusters.get_mut(cluster_id)?.storage) - } - - pub fn get_cluster_mut(&mut self, cluster_id: &ContractClusterId) -> Option<&mut Cluster> { - self.clusters.get_mut(cluster_id) - } - - pub fn get_cluster_or_default_mut( - &mut self, - cluster_id: &ContractClusterId, - cluster_key: &sr25519::Pair, - ) -> &mut Cluster { - self.clusters.entry(*cluster_id).or_insert_with(|| { - let mut cluster = Cluster { - storage: Default::default(), - contracts: Default::default(), - key: cluster_key.clone(), - config: Default::default(), - }; - let seed_key = cluster_key - .derive_sr25519_pair(&[b"ink key derivation seed"]) - .expect("Derive key seed should always success!"); - cluster.set_id(cluster_id); - cluster.set_key_seed(seed_key.dump_secret_key()); - cluster - }) - } - - pub fn remove_cluster(&mut self, cluster_id: &ContractClusterId) -> Option { - self.clusters.remove(cluster_id) - } - - pub fn iter(&self) -> impl Iterator { - self.clusters.iter() - } - } - - #[derive(Serialize, Deserialize, Default)] - pub struct ClusterConfig { - pub log_handler: Option, - // Version used to control the contract API availability. - pub version: (u16, u16), - } - - #[derive(Serialize, Deserialize)] - pub struct Cluster { - pub storage: pink::Storage, - contracts: BTreeSet, - #[serde(with = "more::key_bytes")] - key: sr25519::Pair, - pub config: ClusterConfig, +pub trait ClusterContainer { + fn is_empty(&self) -> bool { + self.len() == 0 } - - impl Cluster { - /// Add a new contract to the cluster. Returns true if the contract is new. - pub fn add_contract(&mut self, address: ContractId) -> bool { - self.contracts.insert(address) - } - - pub fn key(&self) -> &sr25519::Pair { - &self.key - } - - pub fn system_contract(&self) -> Option { - self.storage.system_contract() - } - - pub fn set_system_contract(&mut self, contract: AccountId32) { - self.storage.set_system_contract(contract); - } - - pub fn set_id(&mut self, id: &ContractClusterId) { - self.storage.set_cluster_id(id.as_bytes()); - } - - pub fn set_key_seed(&mut self, seed: Sr25519SecretKey) { - self.storage.set_key_seed(seed); - } - - pub fn upload_resource( - &mut self, - origin: &AccountId, - resource_type: ResourceType, - resource_data: Vec, - ) -> Result { - match resource_type { - ResourceType::InkCode => self.storage.upload_code(origin, resource_data, true), - ResourceType::SidevmCode => self.storage.upload_sidevm_code(origin, resource_data), - ResourceType::IndeterministicInkCode => { - self.storage.upload_code(origin, resource_data, false) - } - } - } - - pub fn get_resource(&self, resource_type: ResourceType, hash: &Hash) -> Option> { - match resource_type { - ResourceType::InkCode => None, - ResourceType::SidevmCode => self.storage.get_sidevm_code(hash), - ResourceType::IndeterministicInkCode => None, - } - } - - pub fn iter_contracts(&self) -> impl Iterator { - self.contracts.iter() - } - - pub fn setup( - &mut self, - gas_price: Balance, - deposit_per_item: Balance, - deposit_per_byte: Balance, - treasury_account: &::pink::types::AccountId, - ) { - self.storage.setup( - gas_price, - deposit_per_item, - deposit_per_byte, - treasury_account, - ); - } - - pub fn deposit(&mut self, who: &::pink::types::AccountId, amount: Balance) { - self.storage.deposit(who, amount) - } - - pub fn set_system_contract_code(&mut self, code_hash: Hash) -> Result<(), DispatchError> { - self.storage.set_system_contract_code(code_hash)?; - self.sync_system_contract_version() - .expect("Failed to sync the system contract version. Please upgrade pRuntime!"); - Ok(()) - } - - pub fn sync_system_contract_version(&mut self) -> Result<()> { - let Some(system_address) = self.system_contract() else { - anyhow::bail!("No system contract"); - }; - let system = pink::Contract::from_address(system_address.clone()); - // System::version - let selector = 0x87c98a8d_u32.to_be_bytes().to_vec(); - let args = ::pink::TransactionArguments { - origin: system_address, - now: 1, - block_number: 1, - storage: &mut self.storage, - transfer: 0, - gas_limit: Weight::MAX, - gas_free: true, - storage_deposit_limit: None, - callbacks: None, - }; - let (result, _) = system.bare_call(selector, true, args); - let output = result.result.map_err(|err| { - anyhow::anyhow!("Failed to get the system contract version: {err:?}") - })?; - self.config.version = Result::<_, ()>::decode(&mut &output.data[..]) - .context("Failed to decode the system contract version")? - .or(Err(anyhow::anyhow!( - "Failed to get the system contract version" - )))?; - const SUPPORTED_API_VERSION: u16 = 0; - if self.config.version.0 > SUPPORTED_API_VERSION { - anyhow::bail!( - "The pink-system version is not supported, please upgrade the pRuntime" - ); - } - Ok(()) - } - } -} - -pub(crate) struct ContractEventCallback { - log_handler: CommandSender, - block_number: BlockNumber, + fn len(&self) -> usize; + fn get_cluster(&self, cluster_id: &ContractClusterId) -> Option<&Cluster>; + fn get_cluster_mut(&mut self, cluster_id: &ContractClusterId) -> Option<&mut Cluster>; + fn remove_cluster(&mut self, cluster_id: &ContractClusterId) -> Option; } -impl ContractEventCallback { - pub fn new(log_handler: CommandSender, block_number: BlockNumber) -> Self { - ContractEventCallback { - log_handler, - block_number, +impl ClusterContainer for Option { + fn len(&self) -> usize { + if self.is_some() { + 1 + } else { + 0 } } - - pub fn from_log_sender( - log_handler: &Option, - block_number: BlockNumber, - ) -> Option { - Some(Box::new(ContractEventCallback::new( - log_handler.as_ref().cloned()?, - block_number, - ))) + fn get_cluster(&self, cluster_id: &ContractClusterId) -> Option<&Cluster> { + self.as_ref().filter(|c| c.id == *cluster_id) } -} - -impl pink::runtime::EventCallbacks for ContractEventCallback { - fn emit_log(&self, contract: &AccountId, in_query: bool, level: u8, message: String) { - let msg = SidevmCommand::PushSystemMessage(SystemMessage::PinkLog { - block_number: self.block_number, - timestamp_ms: std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as _, - in_query, - contract: contract.clone().into(), - level, - message, - }); - if self.log_handler.try_send(msg).is_err() { - error!("Pink emit_log failed"); - } + fn get_cluster_mut(&mut self, cluster_id: &ContractClusterId) -> Option<&mut Cluster> { + self.as_mut().filter(|c| c.id == *cluster_id) + } + fn remove_cluster(&mut self, cluster_id: &ContractClusterId) -> Option { + _ = self.get_cluster(cluster_id)?; + self.take() } } diff --git a/crates/phactory/src/contracts/support.rs b/crates/phactory/src/contracts/support.rs index 3e2b76933c..22db6627a6 100644 --- a/crates/phactory/src/contracts/support.rs +++ b/crates/phactory/src/contracts/support.rs @@ -1,10 +1,13 @@ use anyhow::{anyhow, bail, Result}; +use pink::{ + capi::v1::ecall::ECalls, + types::{AccountId, ExecutionMode, TransactionArguments}, +}; use serde::{Deserialize, Serialize}; use std::sync::{Arc, Mutex}; use parity_scale_codec::Decode; -use phala_crypto::ecdh::EcdhPublicKey; -use phala_mq::{traits::MessageChannel, SignedMessageChannel}; +use phala_mq::SignedMessageChannel; use phala_scheduler::RequestScheduler; use runtime::BlockNumber; use sidevm::{ @@ -12,21 +15,19 @@ use sidevm::{ OcallAborted, VmId, }; -use super::pink::cluster::ClusterKeeper; +use super::pink::Cluster; use crate::{ hex, secret_channel::{KeyPair, SecretMessageChannel, SecretReceiver}, system::{TransactionError, TransactionResult}, types::BlockInfo, - ContractId, H256, + ChainStorage, H256, }; use phactory_api::prpc as pb; -use phala_serde_more as more; - pub struct ExecuteEnv<'a, 'b> { pub block: &'a mut BlockInfo<'b>, - pub contract_clusters: &'a mut ClusterKeeper, + pub contract_cluster: &'a mut Cluster, pub log_handler: Option, } @@ -34,19 +35,18 @@ pub struct TransactionContext<'a, 'b> { pub block: &'a mut BlockInfo<'b>, pub mq: &'a SignedMessageChannel, pub secret_mq: SecretMessageChannel<'a, SignedMessageChannel>, - pub contract_clusters: &'a mut ClusterKeeper, - pub self_id: ContractId, pub log_handler: Option, } pub struct QueryContext { pub block_number: BlockNumber, pub now_ms: u64, - pub storage: ::pink::Storage, pub sidevm_handle: Option, pub log_handler: Option, - pub query_scheduler: RequestScheduler, + pub query_scheduler: RequestScheduler, pub weight: u32, + pub worker_pubkey: [u8; 32], + pub chain_storage: ChainStorage, } pub(crate) struct RawData(Vec); @@ -119,52 +119,48 @@ pub(crate) enum SidevmCode { #[derive(Serialize, Deserialize)] pub struct FatContract { - #[serde(with = "more::scale_bytes")] - contract: AnyContract, send_mq: SignedMessageChannel, cmd_rcv_mq: SecretReceiver, #[serde(with = "crate::secret_channel::ecdh_serde")] ecdh_key: KeyPair, cluster_id: phala_mq::ContractClusterId, - contract_id: phala_mq::ContractId, + address: AccountId, sidevm_info: Option, weight: u32, code_hash: Option, + on_block_end: Option, +} + +#[derive(Copy, Clone, Serialize, Deserialize)] +struct OnBlockEnd { + selector: u32, + gas_limit: u64, } impl FatContract { pub(crate) fn new( - contract: impl Into, send_mq: SignedMessageChannel, cmd_rcv_mq: SecretReceiver, ecdh_key: KeyPair, cluster_id: phala_mq::ContractClusterId, - contract_id: phala_mq::ContractId, + address: AccountId, code_hash: Option, ) -> Self { FatContract { - contract: contract.into(), send_mq, cmd_rcv_mq, ecdh_key, cluster_id, - contract_id, + address, sidevm_info: None, weight: 0, code_hash, + on_block_end: None, } } - pub(crate) fn id(&self) -> ContractId { - self.contract_id - } - - pub(crate) fn cluster_id(&self) -> phala_mq::ContractClusterId { - self.cluster_id - } - - pub(crate) fn snapshot_for_query(&self) -> AnyContract { - self.contract.snapshot() + pub(crate) fn address(&self) -> &AccountId { + &self.address } pub(crate) fn sidevm_handle(&self) -> Option { @@ -182,16 +178,18 @@ impl FatContract { block: env.block, mq: &self.send_mq, secret_mq, - contract_clusters: env.contract_clusters, - self_id: self.id(), log_handler: env.log_handler.clone(), }; phala_mq::select! { next_cmd = self.cmd_rcv_mq => match next_cmd { Ok((_, cmd, origin)) => { - info!("Contract {:?} handling command", self.id()); - self.contract.handle_command(origin, cmd.0, &mut context) + info!("Contract {:?} handling command", self.address()); + let Ok(command) = Decode::decode(&mut &cmd.0[..]) else { + error!("Failed to decode command input"); + return Some(Err(TransactionError::BadInput)); + }; + env.contract_cluster.handle_command(self.address(), origin, command, &mut context) } Err(_e) => { Err(TransactionError::ChannelError) @@ -201,37 +199,33 @@ impl FatContract { } pub(crate) fn on_block_end(&mut self, env: &mut ExecuteEnv) -> TransactionResult { - let secret_mq = SecretMessageChannel::new(&self.ecdh_key, &self.send_mq); - let mut context = TransactionContext { - block: env.block, - mq: &self.send_mq, - secret_mq, - contract_clusters: env.contract_clusters, - self_id: self.id(), - log_handler: env.log_handler.clone(), + let Some(OnBlockEnd { selector, gas_limit }) = self.on_block_end else { + return Ok(None); }; - self.contract.on_block_end(&mut context) - } - pub(crate) fn set_on_block_end_selector(&mut self, selector: u32, gas_limit: u64) { - let AnyContract::Pink(pink) = &mut self.contract; - pink.set_on_block_end_selector(selector, gas_limit) - } - - pub(crate) fn push_message(&self, payload: Vec, topic: Vec) { - self.send_mq.push_data(payload, topic) + let input_data = selector.to_be_bytes(); + let tx_args = TransactionArguments { + origin: self.address.clone(), + transfer: 0, + gas_free: false, + storage_deposit_limit: None, + gas_limit, + }; + let mut handle = env.contract_cluster.runtime_mut(env.log_handler.clone()); + _ = handle.contract_call( + self.address().clone(), + input_data.to_vec(), + ExecutionMode::Transaction, + tx_args, + ); + Ok(handle.effects) } - pub(crate) fn push_osp_message( - &self, - payload: Vec, - topic: Vec, - remote_pubkey: Option<&EcdhPublicKey>, - ) { - let secret_mq = SecretMessageChannel::new(&self.ecdh_key, &self.send_mq); - secret_mq - .bind_remote_key(remote_pubkey) - .push_data(payload, topic) + pub(crate) fn set_on_block_end_selector(&mut self, selector: u32, gas_limit: u64) { + self.on_block_end = Some(OnBlockEnd { + selector, + gas_limit, + }); } pub(crate) fn start_sidevm( @@ -277,7 +271,7 @@ impl FatContract { ExitReason::WaitingForCode, ))) } else { - do_start_sidevm(spawner, &code, self.contract_id.0, self.weight)? + do_start_sidevm(spawner, &code, *self.address.as_ref(), self.weight)? }; let start_time = chrono::Utc::now().to_rfc3339(); @@ -315,7 +309,12 @@ impl FatContract { return Ok(()); } sidevm_info.start_time = chrono::Utc::now().to_rfc3339(); - do_start_sidevm(spawner, &sidevm_info.code, self.contract_id.0, self.weight)? + do_start_sidevm( + spawner, + &sidevm_info.code, + *self.address.as_ref(), + self.weight, + )? } else { return Ok(()); }; @@ -333,7 +332,7 @@ impl FatContract { .handle .clone(); - let vmid = sidevm::ShortId(&self.contract_id.0); + let vmid = sidevm::ShortId(&self.address); let tx = match &*handle.lock().unwrap() { SidevmHandle::Stopped(_) => { @@ -384,7 +383,11 @@ impl FatContract { pub fn set_weight(&mut self, weight: u32) { self.weight = weight; - info!("Updated weight for contarct {:?} to {}", self.id(), weight); + info!( + "Updated weight for contarct {:?} to {}", + self.address(), + weight + ); if let Some(SidevmHandle::Running(tx)) = self.sidevm_handle() { if tx.try_send(SidevmCommand::UpdateWeight(weight)).is_err() { error!("Failed to update weight for sidevm, maybe it has crashed"); @@ -397,7 +400,7 @@ impl FatContract { pub fn info(&self) -> pb::ContractInfo { pb::ContractInfo { - id: hex(self.contract_id), + id: hex(&self.address), weight: self.weight, code_hash: self.code_hash.as_ref().map(hex).unwrap_or_default(), sidevm: self.sidevm_info.as_ref().map(|info| { diff --git a/crates/phactory/src/contracts/support/keeper.rs b/crates/phactory/src/contracts/support/keeper.rs index 23a81cd368..8cc717e4c8 100644 --- a/crates/phactory/src/contracts/support/keeper.rs +++ b/crates/phactory/src/contracts/support/keeper.rs @@ -1,92 +1,11 @@ -use pink::runtime::ExecSideEffects; +use pink::types::AccountId; use serde::{Deserialize, Serialize}; use sidevm::service::Spawner; use std::collections::BTreeMap; -use crate::{ - contracts::{pink::Pink, FatContract, TransactionContext}, - system::{TransactionError, TransactionResult}, - types::{deopaque_query, OpaqueError, OpaqueQuery, OpaqueReply}, -}; -use parity_scale_codec::{Decode, Encode}; -use phala_mq::{ContractId, MessageOrigin}; +use crate::contracts::FatContract; -use super::QueryContext; - -type ContractMap = BTreeMap; - -macro_rules! define_any_native_contract { - (pub enum $name:ident { $($contract:ident ($contract_type: tt),)* }) => { - #[derive(Encode, Decode)] - pub enum $name { - $($contract($contract_type),)* - } - - impl $name { - pub(crate) fn handle_command( - &mut self, - origin: MessageOrigin, - cmd: Vec, - context: &mut TransactionContext, - ) -> TransactionResult { - match self { - $(Self::$contract(me) => { - let cmd = Decode::decode(&mut &cmd[..]).or(Err(TransactionError::BadInput))?; - me.handle_command(origin, cmd, context) - })* - } - } - - pub(crate) fn on_block_end(&mut self, context: &mut TransactionContext) -> TransactionResult { - match self { - $(Self::$contract(me) => { - me.on_block_end(context) - })* - } - } - - pub(crate) fn snapshot(&self) -> Self { - match self { - $($name::$contract(me) => { - Self::$contract(me.snapshot()) - })* - } - } - - pub(crate) async fn handle_query( - &self, - origin: Option<&runtime::AccountId>, - req: OpaqueQuery, - context: &mut QueryContext, - ) -> Result<(OpaqueReply, ExecSideEffects), OpaqueError> { - match self { - $($name::$contract(me) => { - let mut effects = ExecSideEffects::default(); - let response = me.handle_query(origin, deopaque_query(&req)?, context, &mut effects).await; - if let Err(err) = &response { - warn!("Error handling query: {:?}", err); - } - Ok((response.encode(), effects)) - })* - } - } - } - - $( - impl From<$contract_type> for $name { - fn from(c: $contract_type) -> Self { - $name::$contract(c) - } - } - )* - }; -} - -define_any_native_contract!( - pub enum AnyContract { - Pink(Pink), - } -); +type ContractMap = BTreeMap; #[derive(Default, Serialize, Deserialize)] pub struct ContractsKeeper { @@ -97,18 +16,18 @@ pub struct ContractsKeeper { impl ContractsKeeper { pub fn insert(&mut self, contract: FatContract) { - self.contracts.insert(contract.id(), contract); + self.contracts.insert(contract.address().clone(), contract); } - pub fn keys(&self) -> impl Iterator { + pub fn keys(&self) -> impl Iterator { self.contracts.keys() } - pub fn get_mut(&mut self, id: &ContractId) -> Option<&mut FatContract> { + pub fn get_mut(&mut self, id: &AccountId) -> Option<&mut FatContract> { self.contracts.get_mut(id) } - pub fn get(&self, id: &ContractId) -> Option<&FatContract> { + pub fn get(&self, id: &AccountId) -> Option<&FatContract> { self.contracts.get(id) } @@ -124,11 +43,11 @@ impl ContractsKeeper { } } - pub fn remove(&mut self, id: &ContractId) -> Option { - self.contracts.remove(id) + pub fn drain(&mut self) -> impl Iterator { + std::mem::take(&mut self.contracts).into_values() } - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.contracts.iter() } diff --git a/crates/phactory/src/lib.rs b/crates/phactory/src/lib.rs index bc15a2616d..80fb7098f6 100644 --- a/crates/phactory/src/lib.rs +++ b/crates/phactory/src/lib.rs @@ -6,6 +6,7 @@ extern crate log; extern crate phactory_pal as pal; extern crate runtime as chain; +use ::pink::types::AccountId; use glob::PatternError; use rand::*; use serde::{ @@ -43,7 +44,7 @@ use phala_crypto::{ ecdh::EcdhKey, sr25519::{Persistence, Sr25519SecretKey, KDF, SEED_BYTES}, }; -use phala_mq::{BindTopic, ContractId, MessageDispatcher, MessageSendQueue}; +use phala_mq::{BindTopic, MessageDispatcher, MessageSendQueue}; use phala_scheduler::RequestScheduler; use phala_serde_more as more; use std::time::Instant; @@ -238,7 +239,7 @@ pub struct Phactory { last_checkpoint: Instant, #[serde(skip)] #[serde(default = "default_query_scheduler")] - query_scheduler: RequestScheduler, + query_scheduler: RequestScheduler, #[serde(default)] netconfig: Option, @@ -250,7 +251,7 @@ pub struct Phactory { trusted_sk: bool, } -fn default_query_scheduler() -> RequestScheduler { +fn default_query_scheduler() -> RequestScheduler { const FAIR_QUEUE_BACKLOG: usize = 32; const FAIR_QUEUE_THREADS: u32 = 8; diff --git a/crates/phactory/src/prpc_service.rs b/crates/phactory/src/prpc_service.rs index af20ddfce1..6b25407872 100644 --- a/crates/phactory/src/prpc_service.rs +++ b/crates/phactory/src/prpc_service.rs @@ -8,8 +8,7 @@ use crate::hex; use crate::system::{System, MAX_SUPPORTED_CONSENSUS_VERSION}; use super::*; -use crate::contracts::ContractClusterId; -use ::pink::runtime::ExecSideEffects; +use ::pink::types::{AccountId, ExecSideEffects, ExecutionMode}; use parity_scale_codec::Encode; use pb::{ phactory_api_server::{PhactoryApi, PhactoryApiServer}, @@ -28,6 +27,7 @@ use phala_types::{ ChallengeHandlerInfo, EncryptedWorkerKey, SignedContentType, VersionedWorkerEndpoints, WorkerEndpointPayload, WorkerPublicKey, WorkerRegistrationInfoV2, }; +use sp_application_crypto::UncheckedFrom; use tokio::sync::oneshot::{channel, Sender}; type RpcResult = Result; @@ -156,6 +156,10 @@ impl Phactory can_load_chain_state: self.can_load_chain_state, safe_mode_level: self.args.safe_mode_level as _, current_block_time, + max_supported_pink_runtime_version: { + let (major, minor) = ::pink::runtimes::max_supported_version(); + format!("{major}.{minor}") + }, }; info!("Got info: {:?}", info.debug_info()); info @@ -260,6 +264,7 @@ impl Phactory .unwrap_or(counters.next_block_number - 1); let safe_mode_level = self.args.safe_mode_level; + let pubkey = self.system()?.identity_key.public().0; for block in blocks.into_iter() { info!("Dispatching block: {}", block.block_header.number); @@ -274,8 +279,20 @@ impl Phactory } info!("State synced"); state.purge_mq(); + let now_ms = state.chain_storage.timestamp_now(); + let chain_storage = state.chain_storage.snapshot(); + let block_number = block.block_header.number; + let mut context = contracts::pink::context::ContractExecContext::new( + ExecutionMode::Transaction, + now_ms, + block_number, + pubkey, + chain_storage, + ); self.check_requirements(); - self.handle_inbound_messages(block.block_header.number)?; + contracts::pink::context::using(&mut context, || { + self.handle_inbound_messages(block_number) + })?; if let Err(e) = self.maybe_take_checkpoint() { error!("Failed to take checkpoint: {:?}", e); @@ -362,8 +379,6 @@ impl Phactory let ecdh_hex_pk = hex::encode(ecdh_pubkey.0.as_ref()); info!("ECDH pubkey: {:?}", ecdh_hex_pk); - ::pink::runtime::set_worker_pubkey(ecdh_pubkey.0); - // Measure machine score let cpu_core_num: u32 = self.platform.cpu_core_num(); info!("CPU cores: {}", cpu_core_num); @@ -391,8 +406,6 @@ impl Phactory let send_mq = MessageSendQueue::default(); let recv_mq = MessageDispatcher::default(); - let contracts = contracts::ContractsKeeper::default(); - let mut runtime_state = RuntimeState { send_mq, recv_mq, @@ -424,7 +437,6 @@ impl Phactory ecdh_key, &runtime_state.send_mq, &mut runtime_state.recv_mq, - contracts, self.args.cores as _, ); @@ -537,7 +549,7 @@ impl Phactory Ok(messages) } - fn apply_side_effects(&mut self, cluster_id: ContractClusterId, effects: ExecSideEffects) { + fn apply_side_effects(&mut self, effects: ExecSideEffects) { let Some(state) = self.runtime_state.as_ref() else { error!("Failed to apply side effects: chain storage missing"); return; @@ -546,13 +558,13 @@ impl Phactory error!("Failed to apply side effects: system missing"); return; }; - system.apply_side_effects(cluster_id, effects, &state.chain_storage); + system.apply_side_effects(effects, &state.chain_storage); } fn contract_query( &mut self, request: pb::ContractQueryRequest, - effects_queue: Sender<(ContractClusterId, ExecSideEffects)>, + effects_queue: Sender, ) -> RpcResult>> { if self.args.safe_mode_level > 0 { return Err(from_display("Query is unavailable in safe mode")); @@ -602,19 +614,30 @@ impl Phactory let query_scheduler = self.query_scheduler.clone(); // Dispatch - let query_future = self.system()?.make_query( - &head.id, - accid_origin.as_ref(), - data[data.len() - rest..].to_vec(), - query_scheduler, - )?; + let query_future = self + .system + .as_mut() + .expect("system always exists here") + .make_query( + &AccountId::unchecked_from(head.id), + accid_origin.as_ref(), + data[data.len() - rest..].to_vec(), + query_scheduler, + &self + .runtime_state + .as_ref() + .expect("runtime state always exists here") + .chain_storage, + )?; Ok(async move { - let (response, cluster_id, effects) = query_future.await?; + let (response, effects) = query_future.await?; - effects_queue - .send((cluster_id, effects)) - .map_err(|_| from_display("Failed to apply side effects"))?; + if let Some(effects) = effects { + effects_queue + .send(effects) + .map_err(|_| from_display("Failed to apply side effects"))?; + } let response = contract::ContractQueryResponse { nonce: head.nonce, @@ -825,30 +848,23 @@ impl Phactory } pub fn get_cluster_info(&self) -> RpcResult { - // TODO: use `let else`. - let system = match &self.system { - None => return Ok(Default::default()), - Some(system) => system, + let Some(System{ contract_cluster: Some(cluster), contracts, .. }) = &self.system else { + return Ok(Default::default()); }; - let clusters = system - .contract_clusters - .iter() - .map(|(id, cluster)| { - let contracts = cluster.iter_contracts().map(hex).collect(); - let ver = cluster.config.version; - let version = format!("{}.{}", ver.0, ver.1); - pb::ClusterInfo { - id: hex(id), - state_root: hex(cluster.storage.root()), - contracts, - version, - } - }) - .collect(); - Ok(pb::GetClusterInfoResponse { clusters }) + let ver = cluster.config.runtime_version; + let runtime_version = format!("{}.{}", ver.0, ver.1); + + Ok(pb::GetClusterInfoResponse { + info: Some(pb::ClusterInfo { + id: hex(cluster.id), + state_root: cluster.storage.root().map(hex).unwrap_or_default(), + contracts: contracts.keys().map(hex).collect(), + runtime_version, + }), + }) } - pub fn upload_sidevm_code(&mut self, contract_id: ContractId, code: Vec) -> RpcResult<()> { + pub fn upload_sidevm_code(&mut self, contract_id: AccountId, code: Vec) -> RpcResult<()> { self.system()? .upload_sidevm_code(contract_id, code) .map_err(from_debug) @@ -1091,11 +1107,8 @@ impl PhactoryApi for Rpc let (tx, rx) = channel(); let phactory = self.phactory.clone(); tokio::spawn(async move { - if let Ok((cluster_id, effects)) = rx.await { - phactory - .lock() - .unwrap() - .apply_side_effects(cluster_id, effects); + if let Ok(effects) = rx.await { + phactory.lock().unwrap().apply_side_effects(effects); } }); let query_fut = self.lock_phactory().contract_query(request, tx)?; diff --git a/crates/phactory/src/secret_channel.rs b/crates/phactory/src/secret_channel.rs index 4c77f1f4c2..1b4cfa1c14 100644 --- a/crates/phactory/src/secret_channel.rs +++ b/crates/phactory/src/secret_channel.rs @@ -34,6 +34,7 @@ mod sender { SecretMessageChannel { key, mq } } + #[allow(dead_code)] pub fn bind_remote_key( &self, remote_pubkey: Option<&'a ecdh::EcdhPublicKey>, diff --git a/crates/phactory/src/storage.rs b/crates/phactory/src/storage.rs index 093b0c9b45..59eb9770a8 100644 --- a/crates/phactory/src/storage.rs +++ b/crates/phactory/src/storage.rs @@ -84,6 +84,12 @@ mod storage_ext { me } + pub fn snapshot(&self) -> Self { + Self { + trie_storage: self.trie_storage.snapshot(), + } + } + pub fn load(&mut self, pairs: impl Iterator, impl AsRef<[u8]>)>) { self.trie_storage.load(pairs); } @@ -133,6 +139,13 @@ mod storage_ext { self.execute_with(pallet_fat::PinkSystemCode::::get) } + pub fn pink_runtime_version(&self) -> (u32, u32) { + // !! DO NOT CHANGE THIS VALUE !! + const DEFAULT_VERSION: (u32, u32) = (1, 0); + self.execute_with(pallet_fat::PinkRuntimeVersion::::get) + .unwrap_or(DEFAULT_VERSION) + } + /// Get the next mq sequnce number for given sender. Default to 0 if no message sent. pub fn mq_sequence(&self, sender: &MessageOrigin) -> u64 { self.execute_with(|| pallet_mq::OffchainIngress::::get(sender)) diff --git a/crates/phactory/src/system/mod.rs b/crates/phactory/src/system/mod.rs index adc3f36d76..8fb1fcae13 100644 --- a/crates/phactory/src/system/mod.rs +++ b/crates/phactory/src/system/mod.rs @@ -3,18 +3,19 @@ mod master_key; use crate::{ benchmark, - contracts::{pink::cluster::Cluster, AnyContract, ContractsKeeper, ExecuteEnv, SidevmCode}, - pink::{cluster::ClusterKeeper, ContractEventCallback, Pink}, + contracts::{ContractsKeeper, ExecuteEnv, SidevmCode}, + pink::{Cluster, ClusterContainer}, secret_channel::{ecdh_serde, SecretReceiver}, - types::{BlockInfo, OpaqueError, OpaqueQuery, OpaqueReply}, + types::{deopaque_query, BlockInfo, OpaqueError, OpaqueQuery, OpaqueReply}, + ChainStorage, }; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use core::fmt; use log::info; use phala_scheduler::RequestScheduler; use pink::{ - runtime::ExecSideEffects, - types::{AccountId, Weight}, + capi::v1::ecall::{ClusterSetupConfig, ECalls}, + types::{AccountId, ExecSideEffects, ExecutionMode, TransactionArguments}, }; use runtime::BlockNumber; @@ -56,12 +57,12 @@ use serde::{Deserialize, Serialize}; use sidevm::service::{Command as SidevmCommand, CommandSender, Report, Spawner, SystemMessage}; use sp_core::{hashing::blake2_256, sr25519, Pair, U256}; -use pink::runtime::{HookPoint, PinkEvent}; +use pink::types::{HookPoint, PinkEvent}; use std::cell::Cell; use std::convert::TryFrom; use std::future::Future; -pub type TransactionResult = Result; +pub type TransactionResult = Result, TransactionError>; pub(crate) const MAX_SUPPORTED_CONSENSUS_VERSION: u32 = 0; @@ -118,6 +119,12 @@ impl From for TransactionError { } } +impl From for TransactionError { + fn from(s: String) -> TransactionError { + TransactionError::Other(s) + } +} + #[derive(Debug, Serialize, Deserialize)] struct BenchState { start_block: chain::BlockNumber, @@ -449,7 +456,7 @@ pub struct System { pub(crate) gatekeeper: Option>, pub(crate) contracts: ContractsKeeper, - pub(crate) contract_clusters: ClusterKeeper, + pub(crate) contract_cluster: Option, #[serde(skip)] #[serde(default = "create_sidevm_service_default")] sidevm_spawner: Spawner, @@ -501,7 +508,6 @@ impl System { ecdh_key: EcdhKey, send_mq: &MessageSendQueue, recv_mq: &mut MessageDispatcher, - contracts: ContractsKeeper, worker_threads: usize, ) -> Self { // Trigger panic early if platform is not properly implemented. @@ -528,8 +534,8 @@ impl System { last_challenge: None, worker_state: WorkerState::new(pubkey), gatekeeper: None, - contracts, - contract_clusters: Default::default(), + contracts: Default::default(), + contract_cluster: None, block_number: 0, now_ms: 0, sidevm_spawner: create_sidevm_service(worker_threads), @@ -537,11 +543,10 @@ impl System { } } - pub fn get_system_message_handler(&mut self, cluster_id: &ContractId) -> Option { + pub fn get_system_message_handler(&mut self) -> Option { let handler_contract_id = self - .contract_clusters - .get_cluster_mut(cluster_id) - .expect("BUG: contract cluster should always exists") + .contract_cluster + .as_mut()? .config .log_handler .as_ref()?; @@ -550,14 +555,6 @@ impl System { .get_system_message_handler() } - pub fn get_system_message_handler_for_contract_id( - &mut self, - contract_id: &ContractId, - ) -> Option { - let cluster_id = self.contracts.get(contract_id)?.cluster_id(); - self.get_system_message_handler(&cluster_id) - } - pub fn registered(&self) -> bool { self.worker_state.registered } @@ -601,50 +598,51 @@ impl System { pub fn make_query( &mut self, - contract_id: &ContractId, + contract_id: &AccountId, origin: Option<&chain::AccountId>, query: OpaqueQuery, - query_scheduler: RequestScheduler, + query_scheduler: RequestScheduler, + chain_storage: &ChainStorage, ) -> Result< - impl Future< - Output = Result< - (OpaqueReply, contracts::ContractClusterId, ExecSideEffects), - OpaqueError, - >, - >, + impl Future), OpaqueError>>, OpaqueError, > { - use pink::storage::Snapshot as _; - let contract = self .contracts .get_mut(contract_id) .ok_or(OpaqueError::ContractNotFound)?; - let cluster_id = contract.cluster_id(); - let storage = self - .contract_clusters - .get_cluster_mut(&cluster_id) + let mut cluster = self + .contract_cluster + .as_mut() .expect("BUG: contract cluster should always exists") - .storage .snapshot(); let sidevm_handle = contract.sidevm_handle(); let weight = contract.weight(); - let contract = contract.snapshot_for_query(); - let mut context = contracts::QueryContext { + let context = contracts::QueryContext { block_number: self.block_number, now_ms: self.now_ms, - storage, sidevm_handle, - log_handler: self.get_system_message_handler(&cluster_id), + log_handler: self.get_system_message_handler(), query_scheduler, weight, + worker_pubkey: self.identity_key.public().0, + chain_storage: chain_storage.snapshot(), }; let origin = origin.cloned(); + let query = deopaque_query(&query)?; + let contract_id = contract_id.clone(); Ok(async move { - contract - .handle_query(origin.as_ref(), query, &mut context) - .await - .map(|(reply, effects)| (reply, cluster_id, effects)) + let result = cluster + .handle_query(&contract_id, origin.as_ref(), query, context) + .await; + let (result, effects) = match result { + Ok((reply, effects)) => (Ok(reply), effects), + Err(err) => { + log::error!("Contract query error: {:?}", err); + (Err(err), None) + } + }; + Ok((result.encode(), effects)) }) } @@ -710,19 +708,21 @@ impl System { // So we can not directly iterate over the self.contracts.values_mut() which would keep borrowing on `self.contracts` // in the scope of entire `for loop` body. let contract_ids: Vec<_> = self.contracts.keys().cloned().collect(); - 'outer: for key in contract_ids { + 'next_contract: for key in contract_ids { // Inner loop to handle commands. One command per iteration and apply the command side-effects to make it // availabe for next command. loop { - let log_handler = self.get_system_message_handler_for_contract_id(&key); + let log_handler = self.get_system_message_handler(); + let Some(cluster) = &mut self.contract_cluster else { + return; + }; let contract = match self.contracts.get_mut(&key) { - None => continue 'outer, + None => continue 'next_contract, Some(v) => v, }; - let cluster_id = contract.cluster_id(); let mut env = ExecuteEnv { block, - contract_clusters: &mut self.contract_clusters, + contract_cluster: cluster, log_handler: log_handler.clone(), }; let result = match contract.process_next_message(&mut env) { @@ -731,9 +731,8 @@ impl System { }; handle_contract_command_result( result, - cluster_id, &mut self.contracts, - &mut self.contract_clusters, + cluster, block, &self.egress, &self.sidevm_spawner, @@ -753,35 +752,35 @@ impl System { block, &mut WorkerSMDelegate { egress: &self.egress, - n_clusters: self.contract_clusters.len() as _, + n_clusters: self.contract_cluster.len() as _, n_contracts: self.contracts.len() as _, }, ); - let contract_ids: Vec<_> = self.contracts.keys().cloned().collect(); - 'outer: for key in contract_ids { - let log_handler = self.get_system_message_handler_for_contract_id(&key); - let contract = match self.contracts.get_mut(&key) { - None => continue 'outer, - Some(v) => v, - }; - let mut env = ExecuteEnv { - block, - contract_clusters: &mut self.contract_clusters, - log_handler: log_handler.clone(), - }; - let result = contract.on_block_end(&mut env); - let cluster_id = contract.cluster_id(); - handle_contract_command_result( - result, - cluster_id, - &mut self.contracts, - &mut self.contract_clusters, - block, - &self.egress, - &self.sidevm_spawner, - log_handler, - block.storage, - ); + let log_handler = self.get_system_message_handler(); + if let Some(cluster) = self.contract_cluster.as_mut() { + let contract_ids: Vec<_> = self.contracts.keys().cloned().collect(); + 'next_contract: for key in contract_ids { + let contract = match self.contracts.get_mut(&key) { + None => continue 'next_contract, + Some(v) => v, + }; + let mut env = ExecuteEnv { + block, + contract_cluster: cluster, + log_handler: log_handler.clone(), + }; + let result = contract.on_block_end(&mut env); + handle_contract_command_result( + result, + &mut self.contracts, + cluster, + block, + &self.egress, + &self.sidevm_spawner, + log_handler.clone(), + block.storage, + ); + } } if self.contracts.weight_changed { self.contracts.weight_changed = false; @@ -789,7 +788,7 @@ impl System { } self.contracts.try_restart_sidevms(&self.sidevm_spawner); - let contract_running = !self.contract_clusters.is_empty(); + let contract_running = self.contract_cluster.is_some(); benchmark::set_flag(benchmark::Flags::CONTRACT_RUNNING, contract_running); } @@ -799,7 +798,7 @@ impl System { event, &mut WorkerSMDelegate { egress: &self.egress, - n_clusters: self.contract_clusters.len() as _, + n_clusters: self.contract_cluster.len() as _, n_contracts: self.contracts.len() as _, }, true, @@ -1144,17 +1143,15 @@ impl System { error!("Invalid origin {:?} sent a {:?}", origin, event); anyhow::bail!("Invalid origin"); } - let cluster = match self.contract_clusters.remove_cluster(&cluster_id) { + let _cluster = match self.contract_cluster.remove_cluster(&cluster_id) { // The cluster is not deployed on this worker, just ignore it. None => return Ok(()), Some(cluster) => cluster, }; - info!("Destroying cluster {}", hex_fmt::HexFmt(&cluster_id)); - for contract in cluster.iter_contracts() { - if let Some(contract) = self.contracts.remove(contract) { - contract.destroy(&self.sidevm_spawner); - } + for contract in self.contracts.drain() { + contract.destroy(&self.sidevm_spawner); } + info!("Destroyed cluster {}", hex_fmt::HexFmt(&cluster_id)); } ClusterOperation::UploadResource { origin, @@ -1166,7 +1163,7 @@ impl System { anyhow::bail!("Invalid origin"); } let Some(cluster) = self - .contract_clusters + .contract_cluster .get_cluster_mut(&cluster_id) else { return Ok(()); }; @@ -1176,7 +1173,7 @@ impl System { ) })?; let result = cluster.upload_resource(&origin, resource_type, resource_data); - let log_handler = self.get_system_message_handler(&cluster_id); + let log_handler = self.get_system_message_handler(); // Send the reault to the log server if let Some(log_handler) = &log_handler { macro_rules! send_log { @@ -1185,7 +1182,7 @@ impl System { SystemMessage::PinkLog { block_number: block.block_number, contract: system_contract.into(), - in_query: false, + exec_mode: ExecutionMode::Transaction.display().into(), timestamp_ms: block.now_ms, level: $level as usize as u8, message: $msg, @@ -1223,7 +1220,7 @@ impl System { anyhow::bail!("Invalid origin"); } let Some(cluster) = self - .contract_clusters + .contract_cluster .get_cluster_mut(&cluster_id) else { return Ok(()); }; @@ -1250,9 +1247,10 @@ impl System { gas_limit, storage_deposit_limit, } => { + let log_handler = self.get_system_message_handler(); let cluster_id = contract_info.cluster_id; let Some(cluster) = self - .contract_clusters + .contract_cluster .get_cluster_mut(&cluster_id) else { return Ok(()); }; @@ -1262,94 +1260,33 @@ impl System { match contract_info.code_index { CodeIndex::WasmCode(code_hash) => { let deployer = contract_info.deployer.clone(); - - let log_handler = self.get_system_message_handler(&cluster_id); - - let cluster = self - .contract_clusters - .get_cluster_mut(&cluster_id) - .context("Cluster must exist before instantiation")?; - - let tx_args = ::pink::TransactionArguments { - origin: deployer.clone(), - now: block.now_ms, - block_number: block.block_number, - storage: &mut cluster.storage, + let tx_args = TransactionArguments { + origin: deployer, transfer, - gas_limit: Weight::from_ref_time(gas_limit), + gas_limit, gas_free: false, storage_deposit_limit, - callbacks: ContractEventCallback::from_log_sender( - &log_handler, - block.block_number, - ), }; - let contract_id = { - let buf = phala_types::contract::contract_id_preimage( - deployer.as_ref(), - code_hash.as_ref(), - cluster_id.as_ref(), - &contract_info.salt, - ); - blake2_256(&buf) - }; - let result = Pink::instantiate( - cluster_id, + let mut runtime = cluster.runtime_mut(log_handler.clone()); + let _result = runtime.contract_instantiate( code_hash, contract_info.instantiate_data, contract_info.salt, - false, + ExecutionMode::Transaction, tx_args, - ) - .with_context(|| format!("Contract deployer: {deployer:?}")); - // Send the reault to the log server - if let Some(log_handler) = &log_handler { - macro_rules! send_log { - ($level: expr, $msg: expr) => { - let result = log_handler.try_send( - SidevmCommand::PushSystemMessage(SystemMessage::PinkLog { - block_number: block.block_number, - contract: contract_id, - in_query: false, - timestamp_ms: block.now_ms, - level: $level as usize as u8, - message: $msg, - }), - ); - if result.is_err() { - error!("Failed to send log to log handler"); - } - }; - } - match &result { - Ok(_) => { - send_log!(log::Level::Info, "Instantiated".to_owned()); - } - Err(err) => { - send_log!( - log::Level::Error, - format!("Instantiating failed: {err:?}") - ); - } - } - } - let (_, effects) = result?; - - let cluster = self - .contract_clusters - .get_cluster_mut(&cluster_id) - .expect("Cluster must exist"); - apply_pink_side_effects( - effects, - cluster_id, - &mut self.contracts, - cluster, - block, - &self.egress, - &self.sidevm_spawner, - log_handler, - block.storage, ); + if let Some(effects) = runtime.effects.take() { + apply_pink_side_effects( + effects, + &mut self.contracts, + cluster, + block, + &self.egress, + &self.sidevm_spawner, + log_handler, + block.storage, + ); + } } } } @@ -1550,9 +1487,12 @@ impl System { info!("Worker: successfully decrypt received cluster key"); // TODO(shelven): forget cluster key after expiration time - let cluster = self.contract_clusters.get_cluster_mut(&cluster_id); - if cluster.is_some() { - error!("Cluster {:?} is already deployed", &cluster_id); + if let Some(cluster) = &self.contract_cluster { + error!("Failed to deploy cluster {cluster_id:?}"); + error!( + "Cluster {:?} is already deployed in this worker", + &cluster.id + ); return Err(TransactionError::DuplicatedClusterDeploy.into()); } let system_code = block.storage.pink_system_code().1; @@ -1566,56 +1506,38 @@ impl System { system_code.len() ); // register cluster - let cluster = self - .contract_clusters - .get_cluster_or_default_mut(&event.cluster, &cluster_key); - cluster.setup( + let mut cluster = Cluster::new( + &cluster_id, + &cluster_key, + block.storage.pink_runtime_version(), + ); + let config = ClusterSetupConfig { + cluster_id: event.cluster, + owner, + deposit, gas_price, deposit_per_item, deposit_per_byte, - &treasury_account, - ); - cluster.deposit(&owner, deposit); - let code_hash = cluster - .upload_resource(&owner, ResourceType::InkCode, system_code) - .or(Err(TransactionError::FailedToUploadResourceToCluster))?; - info!("Worker: pink system code hash {:?}", code_hash); - let selector = vec![0xed, 0x4b, 0x9d, 0x1b]; // The default() constructor - - let args = ::pink::TransactionArguments { - origin: owner.clone(), - now: block.now_ms, - block_number: block.block_number, - storage: &mut cluster.storage, - transfer: 0, - gas_limit: Weight::MAX, - gas_free: true, - storage_deposit_limit: None, - callbacks: None, + treasury_account, + system_code, }; - let (pink, effects) = - Pink::instantiate(event.cluster, code_hash, selector, vec![], false, args)?; - cluster.set_system_contract(pink.address()); - cluster - .sync_system_contract_version() - .expect("Failed to sync the system contract version. Please upgrade pRuntime!"); - info!( - "Cluster deployed, id={:?}, system={:?}, version={:?}", - event.cluster, - pink.id(), - cluster.config.version - ); - apply_pink_side_effects( - effects, - event.cluster, - &mut self.contracts, - cluster, - block, - &self.egress, - &self.sidevm_spawner, - None, - block.storage, - ); + let mut runtime = cluster.default_runtime_mut(); + if let Err(err) = runtime.setup(config) { + anyhow::bail!("Cluster {cluster_id:?} setup failed: {err:?}"); + } + if let Some(effects) = runtime.effects { + apply_pink_side_effects( + effects, + &mut self.contracts, + &mut cluster, + block, + &self.egress, + &self.sidevm_spawner, + None, + block.storage, + ); + } + self.contract_cluster = Some(cluster); let message = WorkerClusterReport::ClusterDeployed { id: event.cluster, @@ -1656,7 +1578,7 @@ impl System { SystemInfo { registered: self.is_registered(), gatekeeper: Some(self.gatekeeper_status()), - number_of_clusters: self.contract_clusters.len() as _, + number_of_clusters: self.contract_cluster.is_some() as _, number_of_contracts: self.contracts.len() as _, public_key: hex::encode(self.identity_key.public()), ecdh_public_key: hex::encode(self.ecdh_key.public()), @@ -1668,7 +1590,6 @@ impl System { impl System

{ pub fn on_restored(&mut self, safe_mode_level: u8) -> Result<()> { - ::pink::runtime::set_worker_pubkey(self.ecdh_key.public()); if safe_mode_level > 0 { return Ok(()); } @@ -1679,23 +1600,20 @@ impl System

{ pub(crate) fn apply_side_effects( &mut self, - cluster_id: phala_mq::ContractClusterId, effects: ExecSideEffects, - chain_storage: &crate::ChainStorage, + chain_storage: &ChainStorage, ) { - let cluster = match self.contract_clusters.get_cluster_mut(&cluster_id) { - Some(cluster) => cluster, - None => { - error!( - "Can not apply effects: cluster {:?} is not deployed", - cluster_id - ); - return; - } + let Some(cluster) = &mut self.contract_cluster else { + error!("Can not apply effects: no cluster deployed"); + return; }; + let ExecSideEffects::V1 { + pink_events, + ink_events: _, + instantiated: _, + } = effects; apply_pink_events( - effects.pink_events, - cluster_id, + pink_events, &mut self.contracts, cluster, &self.sidevm_spawner, @@ -1705,7 +1623,7 @@ impl System

{ pub(crate) fn upload_sidevm_code( &mut self, - contract_id: ContractId, + contract_id: AccountId, code: Vec, ) -> Result<()> { let contract = self @@ -1719,35 +1637,24 @@ impl System

{ #[allow(clippy::too_many_arguments)] pub fn handle_contract_command_result( result: TransactionResult, - cluster_id: phala_mq::ContractClusterId, contracts: &mut ContractsKeeper, - clusters: &mut ClusterKeeper, + cluster: &mut Cluster, block: &mut BlockInfo, egress: &SignedMessageChannel, spawner: &Spawner, log_handler: Option, - chain_storage: &crate::ChainStorage, + chain_storage: &ChainStorage, ) { let effects = match result { Err(err) => { error!("Run contract command failed: {:?}", err); return; } - Ok(effects) => effects, - }; - let cluster = match clusters.get_cluster_mut(&cluster_id) { - None => { - error!( - "BUG: contract cluster not found, it should always exsists, cluster_id={:?}", - cluster_id - ); - return; - } - Some(cluster) => cluster, + Ok(Some(effects)) => effects, + Ok(None) => return, }; apply_pink_side_effects( effects, - cluster_id, contracts, cluster, block, @@ -1761,92 +1668,75 @@ pub fn handle_contract_command_result( #[allow(clippy::too_many_arguments)] pub fn apply_pink_side_effects( effects: ExecSideEffects, - cluster_id: phala_mq::ContractClusterId, contracts: &mut ContractsKeeper, cluster: &mut Cluster, block: &mut BlockInfo, egress: &SignedMessageChannel, spawner: &Spawner, log_handler: Option, - chain_storage: &crate::ChainStorage, + chain_storage: &ChainStorage, ) { - apply_instantiating_events( - effects.instantiated, - cluster_id, - contracts, - cluster, - block, - egress, - ); - apply_pink_events( - effects.pink_events, - cluster_id, - contracts, - cluster, - spawner, - chain_storage, - ); - apply_ink_side_effects(effects.ink_events, cluster_id, block, log_handler); + let ExecSideEffects::V1 { + pink_events, + ink_events, + instantiated, + } = effects; + apply_instantiating_events(instantiated, contracts, cluster, block, egress); + apply_pink_events(pink_events, contracts, cluster, spawner, chain_storage); + apply_ink_side_effects(ink_events, block, log_handler); } fn apply_instantiating_events( instantiated_events: Vec<(AccountId, AccountId)>, - cluster_id: phala_mq::ContractClusterId, contracts: &mut ContractsKeeper, cluster: &mut Cluster, block: &mut BlockInfo, _egress: &SignedMessageChannel, ) { for (deployer, address) in instantiated_events { - let pink = Pink::from_address(address.clone(), cluster_id); let contract_id = ContractId::from(address.as_ref()); - let contract_key = get_contract_key(cluster.key(), &contract_id); + let contract_key = get_contract_key(&cluster.key(), &contract_id); let ecdh_key = contract_key .derive_ecdh_key() .expect("Derive ecdh_key should not fail"); - let id = pink.id(); - let code_hash = pink.instance.code_hash(&cluster.storage); + let code_hash = cluster.code_hash(&address); let result = install_contract( contracts, - id, - pink, + address, code_hash, contract_key.clone(), ecdh_key.clone(), block, - cluster_id, + cluster.id, ); if let Err(err) = result { error!("BUG: Install contract failed: {:?}", err); - error!(" address: {:?}", address); - error!(" cluster_id: {:?}", cluster_id); + error!(" address: {:?}", contract_id); + error!(" cluster_id: {:?}", cluster.id); error!(" deployer: {:?}", deployer); continue; }; - cluster.add_contract(id); - let message = ContractRegistryEvent::PubkeyAvailable { contract: contract_id, pubkey: contract_key.public(), deployer: phala_types::messaging::AccountId(deployer.into()), }; - let sender = MessageOrigin::Cluster(cluster_id); + let sender = MessageOrigin::Cluster(cluster.id); let cluster_mq: SignedMessageChannel = block.send_mq.channel(sender, cluster.key().clone().into()); cluster_mq.push_message(&message); - info!("Pink instantiated: cluster={cluster_id} {message:?}"); + info!("Pink instantiated: {message:?}"); } } pub(crate) fn apply_pink_events( pink_events: Vec<(AccountId, PinkEvent)>, - cluster_id: phala_mq::ContractClusterId, contracts: &mut ContractsKeeper, cluster: &mut Cluster, spawner: &Spawner, - chain_storage: &crate::ChainStorage, + _chain_storage: &ChainStorage, ) { for (origin, event) in pink_events { macro_rules! get_contract { @@ -1854,10 +1744,7 @@ pub(crate) fn apply_pink_events( match contracts.get_mut(&$origin.convert_to()) { Some(contract) => contract, None => { - error!( - "Unknown contract sending pink event, address={:?}, cluster_id={:?}", - $origin, cluster_id - ); + error!("Unknown contract sending pink event, address={:?}", $origin); continue; } } @@ -1877,18 +1764,6 @@ pub(crate) fn apply_pink_events( }; } match event { - PinkEvent::Message(message) => { - let contract = get_contract!(&origin); - contract.push_message(message.payload, message.topic); - } - PinkEvent::OspMessage(message) => { - let contract = get_contract!(&origin); - contract.push_osp_message( - message.message.payload, - message.message.topic, - message.remote_pubkey.as_ref(), - ); - } PinkEvent::SetHook { hook, contract: target_contract, @@ -1908,7 +1783,7 @@ pub(crate) fn apply_pink_events( code_hash, } => { ensure_system!(); - let vmid = sidevm::ShortId(target_contract.as_ref()); + let vmid = sidevm::ShortId(&target_contract); let target_contract = get_contract!(&target_contract); let code_hash = code_hash.into(); let code = match cluster.get_resource(ResourceType::SidevmCode, &code_hash) { @@ -1920,7 +1795,7 @@ pub(crate) fn apply_pink_events( } } PinkEvent::SidevmMessage(payload) => { - let vmid = sidevm::ShortId(origin.as_ref()); + let vmid = sidevm::ShortId(&origin); let contract = get_contract!(&origin); if let Err(err) = contract.push_message_to_sidevm(SidevmCommand::PushMessage(payload)) @@ -1932,60 +1807,44 @@ pub(crate) fn apply_pink_events( pink::local_cache::apply_cache_op(&origin, op); } PinkEvent::StopSidevm => { - let vmid = sidevm::ShortId(origin.as_ref()); + let vmid = sidevm::ShortId(&origin); let contract = get_contract!(&origin); if let Err(err) = contract.push_message_to_sidevm(SidevmCommand::Stop) { - error!(target: "sidevm", "[{vmid}] Push message to sidevm failed: {:?}", err); + error!(target: "sidevm", "[{vmid}] Push message to sidevm failed: {err:?}"); } } PinkEvent::ForceStopSidevm { contract: target_contract, } => { ensure_system!(); - let vmid = sidevm::ShortId(target_contract.as_ref()); + let vmid = sidevm::ShortId(&target_contract); let contract = get_contract!(&origin); if let Err(err) = contract.push_message_to_sidevm(SidevmCommand::Stop) { - error!(target: "sidevm", "[{vmid}] Push message to sidevm failed: {:?}", err); + error!(target: "sidevm", "[{vmid}] Push message to sidevm failed: {err:?}"); } } PinkEvent::SetLogHandler(handler) => { ensure_system!(); - info!("Set logger for {:?} to {:?}", cluster_id, handler); + info!("Set logger to {handler:?}"); cluster.config.log_handler = Some(handler.convert_to()); } PinkEvent::SetContractWeight { contract, weight } => { ensure_system!(); - info!("Set contract weight for {:?} to {:?}", contract, weight); + info!("Set contract weight for {contract:?} to {weight:?}"); let contract = get_contract!(&contract); contract.set_weight(weight); contracts.weight_changed = true; } - PinkEvent::UpgradeSystemContract { storage_payer } => { + PinkEvent::UpgradeRuntimeTo { version } => { ensure_system!(); - let system_code = chain_storage.pink_system_code().1; - if system_code.is_empty() { - error!("No pink system code on chain"); - continue; - }; - let storage_payer = storage_payer.convert_to(); - let hash = match cluster.upload_resource( - &storage_payer, - ResourceType::InkCode, - system_code, - ) { - Ok(hash) => hash, - Err(err) => { - error!("Failed to upload the system code to the cluster: {err:?}"); - continue; - } - }; - if let Err(err) = cluster.set_system_contract_code(hash) { - error!("Failed to set the system contract code hash: {err:?}"); + info!("Try to upgrade runtime to {version:?}"); + if version == cluster.config.runtime_version { + info!("Runtime version is already {version:?}"); continue; } - info!( - "The system contract has been upgraded to {:?}, hash={hash:?}", - cluster.config.version + panic!( + "The runtime version {:?} is not supported by this pruntime yet, please upgrade pruntime", + version ); } } @@ -1994,7 +1853,6 @@ pub(crate) fn apply_pink_events( fn apply_ink_side_effects( ink_events: Vec<(AccountId, Vec, Vec)>, - cluster_id: phala_mq::ContractClusterId, block: &mut BlockInfo, log_handler: Option, ) { @@ -2009,7 +1867,7 @@ fn apply_ink_side_effects( })) .is_err() { - warn!("Cluster [{cluster_id}] emit ink event to log handler failed"); + warn!("Emit ink event to log handler failed"); } } } @@ -2018,35 +1876,26 @@ fn apply_ink_side_effects( #[allow(clippy::too_many_arguments)] pub fn install_contract( contracts: &mut ContractsKeeper, - contract_id: phala_mq::ContractId, - contract: impl Into, + address: AccountId, code_hash: Option, contract_key: sr25519::Pair, ecdh_key: EcdhKey, block: &mut BlockInfo, cluster_id: phala_mq::ContractClusterId, ) -> anyhow::Result<()> { - if contracts.get(&contract_id).is_some() { + if contracts.get(&address).is_some() { return Err(anyhow::anyhow!("Contract already exists")); } - let sender = MessageOrigin::Contract(contract_id); + let sender = MessageOrigin::Contract(address.convert_to()); let mq = block.send_mq.channel(sender, contract_key.into()); let cmd_mq = SecretReceiver::new_secret( block .recv_mq - .subscribe(contract::command_topic(contract_id)) + .subscribe(contract::command_topic(address.convert_to())) .into(), ecdh_key.clone(), ); - let wrapped = contracts::FatContract::new( - contract, - mq, - cmd_mq, - ecdh_key, - cluster_id, - contract_id, - code_hash, - ); + let wrapped = contracts::FatContract::new(mq, cmd_mq, ecdh_key, cluster_id, address, code_hash); contracts.insert(wrapped); Ok(()) } diff --git a/crates/phala-git-revision/Cargo.toml b/crates/phala-git-revision/Cargo.toml new file mode 100644 index 0000000000..e661989f7e --- /dev/null +++ b/crates/phala-git-revision/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "phala-git-revision" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/crates/phala-git-revision/build.rs b/crates/phala-git-revision/build.rs new file mode 100644 index 0000000000..3ae5fc1ea7 --- /dev/null +++ b/crates/phala-git-revision/build.rs @@ -0,0 +1,28 @@ +use std::process::Command; + +fn main() { + export_git_revision(); +} + +fn export_git_revision() { + let cmd = Command::new("git") + .args(["rev-parse", "HEAD"]) + .output() + .unwrap() + .stdout; + let revision = String::from_utf8_lossy(&cmd); + let revision = revision.trim(); + let dirty = !Command::new("git") + .args(["diff", "HEAD", "--quiet"]) + .output() + .unwrap() + .status + .success(); + let tail = if dirty { "-dirty" } else { "" }; + if revision.is_empty() { + println!("cargo:warning=⚠️ Failed to get git revision for pRuntime."); + println!("cargo:warning=⚠️ Please ensure you have git installed and are compiling from a git repository."); + } + println!("cargo:rustc-env=PHALA_GIT_REVISION={revision}{tail}"); + println!("cargo:rerun-if-changed=always-rerun"); +} diff --git a/crates/phala-git-revision/src/lib.rs b/crates/phala-git-revision/src/lib.rs new file mode 100644 index 0000000000..84f9849da7 --- /dev/null +++ b/crates/phala-git-revision/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] + +pub fn git_revision() -> &'static str { + env!("PHALA_GIT_REVISION") +} diff --git a/crates/phala-sanitized-logger/Cargo.toml b/crates/phala-sanitized-logger/Cargo.toml new file mode 100644 index 0000000000..e307d12672 --- /dev/null +++ b/crates/phala-sanitized-logger/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "phala-sanitized-logger" +version = "0.1.0" +edition = "2021" + +[dependencies] +log = "0.4" +env_logger = "0.10.0" diff --git a/standalone/pruntime/src/logger/all-log-targets.txt b/crates/phala-sanitized-logger/src/all-log-targets.txt similarity index 100% rename from standalone/pruntime/src/logger/all-log-targets.txt rename to crates/phala-sanitized-logger/src/all-log-targets.txt diff --git a/standalone/pruntime/src/logger.rs b/crates/phala-sanitized-logger/src/lib.rs similarity index 97% rename from standalone/pruntime/src/logger.rs rename to crates/phala-sanitized-logger/src/lib.rs index 75ea873f2c..4a3b363eb6 100644 --- a/standalone/pruntime/src/logger.rs +++ b/crates/phala-sanitized-logger/src/lib.rs @@ -6,7 +6,7 @@ mod test; /// A logger that only allow our codes to print logs struct SanitizedLogger(Logger); -pub(crate) fn init(sanitized: bool) { +pub fn init(sanitized: bool) { let env = env_logger::Env::default().default_filter_or("info"); let mut builder = env_logger::Builder::from_env(env); builder.format_timestamp_micros(); diff --git a/standalone/pruntime/src/logger/test.rs b/crates/phala-sanitized-logger/src/test.rs similarity index 100% rename from standalone/pruntime/src/logger/test.rs rename to crates/phala-sanitized-logger/src/test.rs diff --git a/crates/phala-trie-storage/src/lib.rs b/crates/phala-trie-storage/src/lib.rs index 31c391888c..fc1886458c 100644 --- a/crates/phala-trie-storage/src/lib.rs +++ b/crates/phala-trie-storage/src/lib.rs @@ -3,9 +3,9 @@ pub mod ser; mod memdb; -use std::iter::FromIterator; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::iter::FromIterator; use parity_scale_codec::Codec; use sp_core::storage::ChildInfo; @@ -41,6 +41,15 @@ where } } +impl TrieStorage +where + H::Out: Codec + Ord, +{ + pub fn snapshot(&self) -> Self { + Self(clone_trie_backend(&self.0)) + } +} + pub fn load_trie_backend( pairs: impl Iterator, impl AsRef<[u8]>)>, ) -> TrieBackend, H> diff --git a/crates/phala-trie-storage/src/memdb.rs b/crates/phala-trie-storage/src/memdb.rs index e6c9baadf4..c448604985 100644 --- a/crates/phala-trie-storage/src/memdb.rs +++ b/crates/phala-trie-storage/src/memdb.rs @@ -252,6 +252,11 @@ where self.data.clear(); } + /// Return the internal key-value Map, clearing the current state. + pub fn drain(&mut self) -> Map { + core::mem::take(&mut self.data) + } + /// Grab the raw information associated with a key. Returns None if the key /// doesn't exist. /// diff --git a/crates/pink-drivers/log_server/sideprog/Cargo.toml b/crates/pink-drivers/log_server/sideprog/Cargo.toml index c19cf943d0..500ec43aa2 100644 --- a/crates/pink-drivers/log_server/sideprog/Cargo.toml +++ b/crates/pink-drivers/log_server/sideprog/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib"] [dependencies] log = "0.4.16" once_cell = "1.10.0" -sidevm = "0.1" +sidevm = { version = "0.1", path = "../../../sidevm/sidevm" } tokio = { version = "1", features = ["macros", "io-util"] } futures = "0.3" log_buffer = "1.0" diff --git a/crates/pink-drivers/log_server/sideprog/src/buffer.rs b/crates/pink-drivers/log_server/sideprog/src/buffer.rs index 80c0de9f11..c6a0121cbf 100644 --- a/crates/pink-drivers/log_server/sideprog/src/buffer.rs +++ b/crates/pink-drivers/log_server/sideprog/src/buffer.rs @@ -76,7 +76,7 @@ enum SerMessage { Log { block_number: u32, contract: HexSer, - in_query: bool, + exec_mode: String, #[serde(rename = "timestamp")] timestamp_ms: u64, level: u8, @@ -125,14 +125,14 @@ impl From for SerMessage { SystemMessage::PinkLog { block_number, contract, - in_query, + exec_mode, timestamp_ms, level, message, } => Self::Log { block_number, contract: contract.into(), - in_query, + exec_mode, timestamp_ms, level, message, diff --git a/crates/pink-drivers/system/lib.rs b/crates/pink-drivers/system/lib.rs index 2b90811395..8106347e85 100755 --- a/crates/pink-drivers/system/lib.rs +++ b/crates/pink-drivers/system/lib.rs @@ -10,7 +10,7 @@ pub use system::System; mod system { use super::pink; use alloc::string::String; - use ink::storage::Mapping; + use ink::{codegen::Env, storage::Mapping}; use pink::system::{ContractDeposit, ContractDepositRef, DriverError, Error, Result}; use pink::{HookPoint, PinkEnvironment}; @@ -34,7 +34,9 @@ mod system { drivers: Default::default(), } } + } + impl System { fn ensure_owner(&self) -> Result { let caller = self.env().caller(); if caller == self.owner { @@ -64,12 +66,24 @@ mod system { Err(Error::PermisionDenied) } } + + fn ensure_min_runtime_version(&self, version: (u32, u32)) -> Result<()> { + if pink::ext().runtime_version() >= version { + Ok(()) + } else { + Err(Error::ConditionNotMet) + } + } + + fn version(&self) -> (u16, u16) { + (1, 0) + } } impl pink::system::System for System { #[ink(message)] fn version(&self) -> (u16, u16) { - (0, 0) + self.version() } #[ink(message)] @@ -148,8 +162,52 @@ mod system { #[ink(message)] fn upgrade_system_contract(&self) -> Result<()> { - let owner = self.ensure_owner()?; - pink::upgrade_system_contract(owner); + let caller = self.ensure_owner()?; + pink::info!("Upgrading system contract..."); + let Some(code_hash) = pink::ext().import_latest_system_code(caller) else { + pink::error!("No new version of system contract found."); + return Err(Error::CodeNotFound); + }; + let my_code_hash = self + .env() + .code_hash(&self.env().account_id()) + .expect("Code hash should exists here."); + if my_code_hash == code_hash.into() { + pink::info!("No new version of system contract found."); + return Ok(()); + } + // Call the `do_upgrade` from the new version of system contract. + ink::env::set_code_hash(&code_hash) + .expect("System code should exists here"); + let flags = ink::env::CallFlags::default().set_allow_reentry(true); + pink::system::SystemRef::instance_with_call_flags(flags) + .do_upgrade(self.version()) + // panic here to revert the state change. + .expect("Failed to call do_upgrade on the new system code"); + pink::info!("System contract upgraded successfully."); + Ok(()) + } + + #[ink(message)] + fn do_upgrade(&self, from_version: (u16, u16)) -> Result<()> { + self.ensure_self()?; + self.ensure_min_runtime_version((1, 0))?; + if from_version >= self.version() { + pink::error!("The system contract is already upgraded."); + return Err(Error::ConditionNotMet); + } + Ok(()) + } + + /// Upgrade the contract runtime + /// + /// Be careful when using this function, it would panic the worker if the + /// runtime version is not supported. + #[ink(message)] + fn upgrade_runtime(&self, version: (u32, u32)) -> Result<()> { + let _ = self.ensure_owner()?; + pink::info!("Upgrading pink contract runtime..."); + pink::upgrade_runtime(version); Ok(()) } } diff --git a/crates/pink/capi/Cargo.toml b/crates/pink/capi/Cargo.toml new file mode 100644 index 0000000000..ad806c7d11 --- /dev/null +++ b/crates/pink/capi/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "pink-capi" +version = "0.1.0" +edition = "2021" + +[dependencies] +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +pink-extension = { path = "../pink-extension" } +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = [ + "derive", +] } +pink-macro = { path = "../macro" } + +[build-dependencies] +bindgen = "0.64.0" diff --git a/crates/pink/capi/build.rs b/crates/pink/capi/build.rs new file mode 100644 index 0000000000..aba0f4cf71 --- /dev/null +++ b/crates/pink/capi/build.rs @@ -0,0 +1,20 @@ +fn main() { + let rootdir = std::env::var("CARGO_MANIFEST_DIR").expect("Missing CARGO_MANIFEST_DIR"); + let capi_dir = format!("{rootdir}/src"); + #[allow(clippy::single_element_loop)] + for ver in ["v1"] { + println!("cargo:rerun-if-changed={capi_dir}/{ver}/types.h"); + let bindings = bindgen::Builder::default() + .header(format!("{capi_dir}/{ver}/types.h")) + .use_core() + .derive_default(true) + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .layout_tests(false) + .generate() + .expect("Unable to generate bindings"); + let out_file = format!("{capi_dir}/{ver}/types.rs"); + bindings + .write_to_file(out_file) + .expect("Couldn't write bindings!"); + } +} diff --git a/crates/pink/capi/src/helper.rs b/crates/pink/capi/src/helper.rs new file mode 100644 index 0000000000..2654a60245 --- /dev/null +++ b/crates/pink/capi/src/helper.rs @@ -0,0 +1,14 @@ +pub trait ParamType { + type T; + type E; +} +impl ParamType for Option { + type T = T; + type E = (); +} +impl ParamType for Result { + type T = T; + type E = E; +} +pub type InnerType = ::T; +pub type InnerError = ::E; diff --git a/crates/pink/capi/src/lib.rs b/crates/pink/capi/src/lib.rs new file mode 100644 index 0000000000..924915020f --- /dev/null +++ b/crates/pink/capi/src/lib.rs @@ -0,0 +1,3 @@ +pub mod types; +pub mod v1; +pub mod helper; diff --git a/crates/pink/capi/src/types.rs b/crates/pink/capi/src/types.rs new file mode 100644 index 0000000000..15de25b4d2 --- /dev/null +++ b/crates/pink/capi/src/types.rs @@ -0,0 +1,88 @@ +use scale::{Decode, Encode}; +use sp_core::Hasher; +use sp_runtime::{traits::BlakeTwo256, AccountId32}; + +pub type Hash = ::Out; +pub type Hashing = BlakeTwo256; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = u32; +pub type Index = u64; +pub type Address = AccountId32; +pub type Weight = u64; + +pub use pink_extension::{HookPoint, PinkEvent}; + +#[derive(Decode, Encode, Clone, Copy, Debug, PartialEq, Eq, Default)] +pub enum ExecutionMode { + Query, + #[default] + Estimating, + Transaction, +} + +impl ExecutionMode { + pub fn display(&self) -> &'static str { + match self { + ExecutionMode::Query => "query", + ExecutionMode::Estimating => "estimating", + ExecutionMode::Transaction => "transaction", + } + } + + pub fn is_query(&self) -> bool { + matches!(self, ExecutionMode::Query) + } + + pub fn is_transaction(&self) -> bool { + matches!(self, ExecutionMode::Transaction) + } + + pub fn is_estimating(&self) -> bool { + matches!(self, ExecutionMode::Estimating) + } + + pub fn should_return_coarse_gas(&self) -> bool { + match self { + ExecutionMode::Query => true, + ExecutionMode::Estimating => true, + ExecutionMode::Transaction => false, + } + } + + pub fn deterministic_required(&self) -> bool { + match self { + ExecutionMode::Query => false, + ExecutionMode::Estimating => true, + ExecutionMode::Transaction => true, + } + } +} + +#[derive(Decode, Encode, Debug)] +pub enum ExecSideEffects { + V1 { + pink_events: Vec<(AccountId, PinkEvent)>, + ink_events: Vec<(AccountId, Vec, Vec)>, + instantiated: Vec<(AccountId, AccountId)>, + }, +} + +impl ExecSideEffects { + pub fn into_query_only_effects(self) -> Self { + match self { + ExecSideEffects::V1 { + pink_events, + ink_events: _, + instantiated: _, + } => Self::V1 { + pink_events: pink_events + .into_iter() + .filter(|(_, event)| event.allowed_in_query()) + .collect(), + ink_events: vec![], + instantiated: vec![], + }, + } + } +} diff --git a/crates/pink/capi/src/v1/mod.rs b/crates/pink/capi/src/v1/mod.rs new file mode 100644 index 0000000000..8a9bafa566 --- /dev/null +++ b/crates/pink/capi/src/v1/mod.rs @@ -0,0 +1,185 @@ +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(dead_code)] +mod types; +pub use types::*; + +pub trait CrossCall { + fn cross_call(&self, id: u32, data: &[u8]) -> Vec; +} + +pub trait CrossCallMut { + fn cross_call_mut(&mut self, call_id: u32, data: &[u8]) -> Vec; +} + +pub trait Executing { + fn execute(&self, f: impl FnOnce() -> T) -> T; + fn execute_mut(&mut self, f: impl FnOnce() -> T) -> T; +} + +pub struct IdentExecute; +impl Executing for IdentExecute { + fn execute(&self, f: impl FnOnce() -> T) -> T { + f() + } + + fn execute_mut(&mut self, f: impl FnOnce() -> T) -> T { + f() + } +} + +pub trait ECall: CrossCall {} +pub trait OCall: CrossCall {} + +pub mod ecall { + use super::{CrossCallMut, ECall, Executing}; + use crate::types::{AccountId, Balance, ExecutionMode, Hash, Weight}; + use pink_macro::cross_call; + use scale::{Decode, Encode}; + pub trait EventCallbacks { + fn log_to_server(&self, contract: &AccountId, in_query: bool, level: u8, message: String); + } + + #[derive(Encode, Decode, Clone, Debug)] + pub struct TransactionArguments { + pub origin: AccountId, + pub transfer: Balance, + pub gas_limit: Weight, + pub gas_free: bool, + pub storage_deposit_limit: Option, + } + + #[derive(Encode, Decode, Clone, Debug)] + pub struct ClusterSetupConfig { + pub cluster_id: Hash, + pub owner: AccountId, + pub deposit: Balance, + pub gas_price: Balance, + pub deposit_per_item: Balance, + pub deposit_per_byte: Balance, + pub treasury_account: AccountId, + pub system_code: Vec, + } + + #[cross_call(ECall)] + pub trait ECalls { + #[xcall(id = 1)] + fn cluster_id(&self) -> Hash; + #[xcall(id = 2)] + fn setup(&mut self, config: ClusterSetupConfig) -> Result<(), String>; + #[xcall(id = 3)] + fn deposit(&mut self, who: AccountId, value: Balance); + #[xcall(id = 5)] + fn set_key(&mut self, key: [u8; 64]); + #[xcall(id = 6)] + fn get_key(&self) -> Option<[u8; 64]>; + #[xcall(id = 7)] + fn upload_code( + &mut self, + account: AccountId, + code: Vec, + deterministic: bool, + ) -> Result; + #[xcall(id = 8)] + fn upload_sidevm_code(&mut self, account: AccountId, code: Vec) + -> Result; + #[xcall(id = 9)] + fn get_sidevm_code(&self, hash: Hash) -> Option>; + #[xcall(id = 11)] + fn system_contract(&self) -> Option; + #[xcall(id = 14)] + fn free_balance(&self, account: AccountId) -> Balance; + #[xcall(id = 15)] + fn total_balance(&self, account: AccountId) -> Balance; + #[xcall(id = 16)] + fn code_hash(&self, account: AccountId) -> Option; + #[xcall(id = 19)] + fn contract_instantiate( + &mut self, + code_hash: Hash, + input_data: Vec, + salt: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> Vec; + #[xcall(id = 20)] + fn contract_call( + &mut self, + contract: AccountId, + input_data: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> Vec; + #[xcall(id = 21)] + fn git_revision(&self) -> String; + } +} + +pub mod ocall { + use super::{CrossCallMut, Executing, OCall}; + use crate::types::{AccountId, BlockNumber, ExecSideEffects, ExecutionMode, Hash}; + use pink_macro::cross_call; + use scale::{Decode, Encode}; + + pub use pink_extension::chain_extension::{ + HttpRequest, HttpRequestError, HttpResponse, StorageQuotaExceeded, + }; + pub type StorageChanges = Vec<(Vec, (Vec, i32))>; + + #[derive(Decode, Encode, Clone, Debug, Default)] + pub struct ExecContext { + pub mode: ExecutionMode, + pub block_number: BlockNumber, + pub now_ms: u64, + } + + impl ExecContext { + pub fn new(mode: ExecutionMode, block_number: BlockNumber, now_ms: u64) -> Self { + Self { + mode, + block_number, + now_ms, + } + } + } + + #[cross_call(OCall)] + pub trait OCalls { + #[xcall(id = 1)] + fn storage_root(&self) -> Option; + #[xcall(id = 2)] + fn storage_get(&self, key: Vec) -> Option>; + #[xcall(id = 3)] + fn storage_commit(&mut self, root: Hash, changes: StorageChanges); + #[xcall(id = 5)] + fn log_to_server(&self, contract: AccountId, level: u8, message: String); + #[xcall(id = 6)] + fn emit_side_effects(&mut self, effects: ExecSideEffects); + #[xcall(id = 7)] + fn exec_context(&self) -> ExecContext; + #[xcall(id = 8)] + fn worker_pubkey(&self) -> [u8; 32]; + #[xcall(id = 9)] + fn cache_get(&self, contract: Vec, key: Vec) -> Option>; + #[xcall(id = 10)] + fn cache_set( + &self, + contract: Vec, + key: Vec, + value: Vec, + ) -> Result<(), StorageQuotaExceeded>; + #[xcall(id = 11)] + fn cache_set_expiration(&self, contract: Vec, key: Vec, expiration: u64); + #[xcall(id = 12)] + fn cache_remove(&self, contract: Vec, key: Vec) -> Option>; + #[xcall(id = 13)] + fn latest_system_code(&self) -> Vec; + #[xcall(id = 14)] + fn http_request( + &self, + contract: AccountId, + request: HttpRequest, + ) -> Result; + } +} diff --git a/crates/pink/capi/src/v1/types.h b/crates/pink/capi/src/v1/types.h new file mode 100644 index 0000000000..16421d59ab --- /dev/null +++ b/crates/pink/capi/src/v1/types.h @@ -0,0 +1,38 @@ +// File: types.h +// +// This file defines the pink runtime v1 interface types. +// We use a C header file to make sure that the types are ffi-safe. + +#include +#include + +typedef void (*output_fn_t)(void *ctx, const uint8_t *data, size_t len); +typedef void (*cross_call_fn_t)(uint32_t call_id, const uint8_t *data, size_t len, void *ctx, output_fn_t output); +typedef void (*ecall_get_version_fn_t)(uint32_t *major, uint32_t *minor); +typedef uint8_t *(*alloc_fn_t)(size_t size, size_t align); +typedef void (*dealloc_fn_t)(uint8_t *p, size_t size, size_t align); + +typedef struct +{ + cross_call_fn_t ocall; + alloc_fn_t alloc; + dealloc_fn_t dealloc; +} ocalls_t; + +typedef struct +{ + // Whether the runtime is running in a dylib or compiled into the running binary. + // If it is a dylib, the runtime will init logger inside. + int is_dylib; + // If true, the logger inside will be sanitized. + int enclaved; + ocalls_t ocalls; +} config_t; + +typedef struct +{ + cross_call_fn_t ecall; + ecall_get_version_fn_t get_version; +} ecalls_t; + +typedef int init_t(const config_t *config, ecalls_t *ecalls); diff --git a/crates/pink/capi/src/v1/types.rs b/crates/pink/capi/src/v1/types.rs new file mode 100644 index 0000000000..04fcbe0231 --- /dev/null +++ b/crates/pink/capi/src/v1/types.rs @@ -0,0 +1,426 @@ +/* automatically generated by rust-bindgen 0.64.0 */ + +pub const _INTTYPES_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const __GLIBC_USE_ISOC2X: u32 = 0; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_POSIX_IMPLICITLY: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 31; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __LONG_DOUBLE_USES_FLOAT128: u32 = 0; +pub const __HAVE_GENERIC_SELECTION: u32 = 1; +pub const _STDINT_H: u32 = 1; +pub const __GLIBC_USE_LIB_EXT2: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 0; +pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0; +pub const _BITS_TYPES_H: u32 = 1; +pub const __TIMESIZE: u32 = 64; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __STATFS_MATCHES_STATFS64: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const _BITS_TIME64_H: u32 = 1; +pub const _BITS_WCHAR_H: u32 = 1; +pub const _BITS_STDINT_INTN_H: u32 = 1; +pub const _BITS_STDINT_UINTN_H: u32 = 1; +pub const INT8_MIN: i32 = -128; +pub const INT16_MIN: i32 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; +pub const UINT8_MAX: u32 = 255; +pub const UINT16_MAX: u32 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: i32 = -128; +pub const INT_LEAST16_MIN: i32 = -32768; +pub const INT_LEAST32_MIN: i32 = -2147483648; +pub const INT_LEAST8_MAX: u32 = 127; +pub const INT_LEAST16_MAX: u32 = 32767; +pub const INT_LEAST32_MAX: u32 = 2147483647; +pub const UINT_LEAST8_MAX: u32 = 255; +pub const UINT_LEAST16_MAX: u32 = 65535; +pub const UINT_LEAST32_MAX: u32 = 4294967295; +pub const INT_FAST8_MIN: i32 = -128; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; +pub const INT_FAST8_MAX: u32 = 127; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; +pub const UINT_FAST8_MAX: u32 = 255; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; +pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINTPTR_MAX: i32 = -1; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; +pub const SIG_ATOMIC_MIN: i32 = -2147483648; +pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; +pub const ____gwchar_t_defined: u32 = 1; +pub const __PRI64_PREFIX: &[u8; 2usize] = b"l\0"; +pub const __PRIPTR_PREFIX: &[u8; 2usize] = b"l\0"; +pub const PRId8: &[u8; 2usize] = b"d\0"; +pub const PRId16: &[u8; 2usize] = b"d\0"; +pub const PRId32: &[u8; 2usize] = b"d\0"; +pub const PRId64: &[u8; 3usize] = b"ld\0"; +pub const PRIdLEAST8: &[u8; 2usize] = b"d\0"; +pub const PRIdLEAST16: &[u8; 2usize] = b"d\0"; +pub const PRIdLEAST32: &[u8; 2usize] = b"d\0"; +pub const PRIdLEAST64: &[u8; 3usize] = b"ld\0"; +pub const PRIdFAST8: &[u8; 2usize] = b"d\0"; +pub const PRIdFAST16: &[u8; 3usize] = b"ld\0"; +pub const PRIdFAST32: &[u8; 3usize] = b"ld\0"; +pub const PRIdFAST64: &[u8; 3usize] = b"ld\0"; +pub const PRIi8: &[u8; 2usize] = b"i\0"; +pub const PRIi16: &[u8; 2usize] = b"i\0"; +pub const PRIi32: &[u8; 2usize] = b"i\0"; +pub const PRIi64: &[u8; 3usize] = b"li\0"; +pub const PRIiLEAST8: &[u8; 2usize] = b"i\0"; +pub const PRIiLEAST16: &[u8; 2usize] = b"i\0"; +pub const PRIiLEAST32: &[u8; 2usize] = b"i\0"; +pub const PRIiLEAST64: &[u8; 3usize] = b"li\0"; +pub const PRIiFAST8: &[u8; 2usize] = b"i\0"; +pub const PRIiFAST16: &[u8; 3usize] = b"li\0"; +pub const PRIiFAST32: &[u8; 3usize] = b"li\0"; +pub const PRIiFAST64: &[u8; 3usize] = b"li\0"; +pub const PRIo8: &[u8; 2usize] = b"o\0"; +pub const PRIo16: &[u8; 2usize] = b"o\0"; +pub const PRIo32: &[u8; 2usize] = b"o\0"; +pub const PRIo64: &[u8; 3usize] = b"lo\0"; +pub const PRIoLEAST8: &[u8; 2usize] = b"o\0"; +pub const PRIoLEAST16: &[u8; 2usize] = b"o\0"; +pub const PRIoLEAST32: &[u8; 2usize] = b"o\0"; +pub const PRIoLEAST64: &[u8; 3usize] = b"lo\0"; +pub const PRIoFAST8: &[u8; 2usize] = b"o\0"; +pub const PRIoFAST16: &[u8; 3usize] = b"lo\0"; +pub const PRIoFAST32: &[u8; 3usize] = b"lo\0"; +pub const PRIoFAST64: &[u8; 3usize] = b"lo\0"; +pub const PRIu8: &[u8; 2usize] = b"u\0"; +pub const PRIu16: &[u8; 2usize] = b"u\0"; +pub const PRIu32: &[u8; 2usize] = b"u\0"; +pub const PRIu64: &[u8; 3usize] = b"lu\0"; +pub const PRIuLEAST8: &[u8; 2usize] = b"u\0"; +pub const PRIuLEAST16: &[u8; 2usize] = b"u\0"; +pub const PRIuLEAST32: &[u8; 2usize] = b"u\0"; +pub const PRIuLEAST64: &[u8; 3usize] = b"lu\0"; +pub const PRIuFAST8: &[u8; 2usize] = b"u\0"; +pub const PRIuFAST16: &[u8; 3usize] = b"lu\0"; +pub const PRIuFAST32: &[u8; 3usize] = b"lu\0"; +pub const PRIuFAST64: &[u8; 3usize] = b"lu\0"; +pub const PRIx8: &[u8; 2usize] = b"x\0"; +pub const PRIx16: &[u8; 2usize] = b"x\0"; +pub const PRIx32: &[u8; 2usize] = b"x\0"; +pub const PRIx64: &[u8; 3usize] = b"lx\0"; +pub const PRIxLEAST8: &[u8; 2usize] = b"x\0"; +pub const PRIxLEAST16: &[u8; 2usize] = b"x\0"; +pub const PRIxLEAST32: &[u8; 2usize] = b"x\0"; +pub const PRIxLEAST64: &[u8; 3usize] = b"lx\0"; +pub const PRIxFAST8: &[u8; 2usize] = b"x\0"; +pub const PRIxFAST16: &[u8; 3usize] = b"lx\0"; +pub const PRIxFAST32: &[u8; 3usize] = b"lx\0"; +pub const PRIxFAST64: &[u8; 3usize] = b"lx\0"; +pub const PRIX8: &[u8; 2usize] = b"X\0"; +pub const PRIX16: &[u8; 2usize] = b"X\0"; +pub const PRIX32: &[u8; 2usize] = b"X\0"; +pub const PRIX64: &[u8; 3usize] = b"lX\0"; +pub const PRIXLEAST8: &[u8; 2usize] = b"X\0"; +pub const PRIXLEAST16: &[u8; 2usize] = b"X\0"; +pub const PRIXLEAST32: &[u8; 2usize] = b"X\0"; +pub const PRIXLEAST64: &[u8; 3usize] = b"lX\0"; +pub const PRIXFAST8: &[u8; 2usize] = b"X\0"; +pub const PRIXFAST16: &[u8; 3usize] = b"lX\0"; +pub const PRIXFAST32: &[u8; 3usize] = b"lX\0"; +pub const PRIXFAST64: &[u8; 3usize] = b"lX\0"; +pub const PRIdMAX: &[u8; 3usize] = b"ld\0"; +pub const PRIiMAX: &[u8; 3usize] = b"li\0"; +pub const PRIoMAX: &[u8; 3usize] = b"lo\0"; +pub const PRIuMAX: &[u8; 3usize] = b"lu\0"; +pub const PRIxMAX: &[u8; 3usize] = b"lx\0"; +pub const PRIXMAX: &[u8; 3usize] = b"lX\0"; +pub const PRIdPTR: &[u8; 3usize] = b"ld\0"; +pub const PRIiPTR: &[u8; 3usize] = b"li\0"; +pub const PRIoPTR: &[u8; 3usize] = b"lo\0"; +pub const PRIuPTR: &[u8; 3usize] = b"lu\0"; +pub const PRIxPTR: &[u8; 3usize] = b"lx\0"; +pub const PRIXPTR: &[u8; 3usize] = b"lX\0"; +pub const SCNd8: &[u8; 4usize] = b"hhd\0"; +pub const SCNd16: &[u8; 3usize] = b"hd\0"; +pub const SCNd32: &[u8; 2usize] = b"d\0"; +pub const SCNd64: &[u8; 3usize] = b"ld\0"; +pub const SCNdLEAST8: &[u8; 4usize] = b"hhd\0"; +pub const SCNdLEAST16: &[u8; 3usize] = b"hd\0"; +pub const SCNdLEAST32: &[u8; 2usize] = b"d\0"; +pub const SCNdLEAST64: &[u8; 3usize] = b"ld\0"; +pub const SCNdFAST8: &[u8; 4usize] = b"hhd\0"; +pub const SCNdFAST16: &[u8; 3usize] = b"ld\0"; +pub const SCNdFAST32: &[u8; 3usize] = b"ld\0"; +pub const SCNdFAST64: &[u8; 3usize] = b"ld\0"; +pub const SCNi8: &[u8; 4usize] = b"hhi\0"; +pub const SCNi16: &[u8; 3usize] = b"hi\0"; +pub const SCNi32: &[u8; 2usize] = b"i\0"; +pub const SCNi64: &[u8; 3usize] = b"li\0"; +pub const SCNiLEAST8: &[u8; 4usize] = b"hhi\0"; +pub const SCNiLEAST16: &[u8; 3usize] = b"hi\0"; +pub const SCNiLEAST32: &[u8; 2usize] = b"i\0"; +pub const SCNiLEAST64: &[u8; 3usize] = b"li\0"; +pub const SCNiFAST8: &[u8; 4usize] = b"hhi\0"; +pub const SCNiFAST16: &[u8; 3usize] = b"li\0"; +pub const SCNiFAST32: &[u8; 3usize] = b"li\0"; +pub const SCNiFAST64: &[u8; 3usize] = b"li\0"; +pub const SCNu8: &[u8; 4usize] = b"hhu\0"; +pub const SCNu16: &[u8; 3usize] = b"hu\0"; +pub const SCNu32: &[u8; 2usize] = b"u\0"; +pub const SCNu64: &[u8; 3usize] = b"lu\0"; +pub const SCNuLEAST8: &[u8; 4usize] = b"hhu\0"; +pub const SCNuLEAST16: &[u8; 3usize] = b"hu\0"; +pub const SCNuLEAST32: &[u8; 2usize] = b"u\0"; +pub const SCNuLEAST64: &[u8; 3usize] = b"lu\0"; +pub const SCNuFAST8: &[u8; 4usize] = b"hhu\0"; +pub const SCNuFAST16: &[u8; 3usize] = b"lu\0"; +pub const SCNuFAST32: &[u8; 3usize] = b"lu\0"; +pub const SCNuFAST64: &[u8; 3usize] = b"lu\0"; +pub const SCNo8: &[u8; 4usize] = b"hho\0"; +pub const SCNo16: &[u8; 3usize] = b"ho\0"; +pub const SCNo32: &[u8; 2usize] = b"o\0"; +pub const SCNo64: &[u8; 3usize] = b"lo\0"; +pub const SCNoLEAST8: &[u8; 4usize] = b"hho\0"; +pub const SCNoLEAST16: &[u8; 3usize] = b"ho\0"; +pub const SCNoLEAST32: &[u8; 2usize] = b"o\0"; +pub const SCNoLEAST64: &[u8; 3usize] = b"lo\0"; +pub const SCNoFAST8: &[u8; 4usize] = b"hho\0"; +pub const SCNoFAST16: &[u8; 3usize] = b"lo\0"; +pub const SCNoFAST32: &[u8; 3usize] = b"lo\0"; +pub const SCNoFAST64: &[u8; 3usize] = b"lo\0"; +pub const SCNx8: &[u8; 4usize] = b"hhx\0"; +pub const SCNx16: &[u8; 3usize] = b"hx\0"; +pub const SCNx32: &[u8; 2usize] = b"x\0"; +pub const SCNx64: &[u8; 3usize] = b"lx\0"; +pub const SCNxLEAST8: &[u8; 4usize] = b"hhx\0"; +pub const SCNxLEAST16: &[u8; 3usize] = b"hx\0"; +pub const SCNxLEAST32: &[u8; 2usize] = b"x\0"; +pub const SCNxLEAST64: &[u8; 3usize] = b"lx\0"; +pub const SCNxFAST8: &[u8; 4usize] = b"hhx\0"; +pub const SCNxFAST16: &[u8; 3usize] = b"lx\0"; +pub const SCNxFAST32: &[u8; 3usize] = b"lx\0"; +pub const SCNxFAST64: &[u8; 3usize] = b"lx\0"; +pub const SCNdMAX: &[u8; 3usize] = b"ld\0"; +pub const SCNiMAX: &[u8; 3usize] = b"li\0"; +pub const SCNoMAX: &[u8; 3usize] = b"lo\0"; +pub const SCNuMAX: &[u8; 3usize] = b"lu\0"; +pub const SCNxMAX: &[u8; 3usize] = b"lx\0"; +pub const SCNdPTR: &[u8; 3usize] = b"ld\0"; +pub const SCNiPTR: &[u8; 3usize] = b"li\0"; +pub const SCNoPTR: &[u8; 3usize] = b"lo\0"; +pub const SCNuPTR: &[u8; 3usize] = b"lu\0"; +pub const SCNxPTR: &[u8; 3usize] = b"lx\0"; +pub type __u_char = ::core::ffi::c_uchar; +pub type __u_short = ::core::ffi::c_ushort; +pub type __u_int = ::core::ffi::c_uint; +pub type __u_long = ::core::ffi::c_ulong; +pub type __int8_t = ::core::ffi::c_schar; +pub type __uint8_t = ::core::ffi::c_uchar; +pub type __int16_t = ::core::ffi::c_short; +pub type __uint16_t = ::core::ffi::c_ushort; +pub type __int32_t = ::core::ffi::c_int; +pub type __uint32_t = ::core::ffi::c_uint; +pub type __int64_t = ::core::ffi::c_long; +pub type __uint64_t = ::core::ffi::c_ulong; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; +pub type __quad_t = ::core::ffi::c_long; +pub type __u_quad_t = ::core::ffi::c_ulong; +pub type __intmax_t = ::core::ffi::c_long; +pub type __uintmax_t = ::core::ffi::c_ulong; +pub type __dev_t = ::core::ffi::c_ulong; +pub type __uid_t = ::core::ffi::c_uint; +pub type __gid_t = ::core::ffi::c_uint; +pub type __ino_t = ::core::ffi::c_ulong; +pub type __ino64_t = ::core::ffi::c_ulong; +pub type __mode_t = ::core::ffi::c_uint; +pub type __nlink_t = ::core::ffi::c_ulong; +pub type __off_t = ::core::ffi::c_long; +pub type __off64_t = ::core::ffi::c_long; +pub type __pid_t = ::core::ffi::c_int; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct __fsid_t { + pub __val: [::core::ffi::c_int; 2usize], +} +pub type __clock_t = ::core::ffi::c_long; +pub type __rlim_t = ::core::ffi::c_ulong; +pub type __rlim64_t = ::core::ffi::c_ulong; +pub type __id_t = ::core::ffi::c_uint; +pub type __time_t = ::core::ffi::c_long; +pub type __useconds_t = ::core::ffi::c_uint; +pub type __suseconds_t = ::core::ffi::c_long; +pub type __daddr_t = ::core::ffi::c_int; +pub type __key_t = ::core::ffi::c_int; +pub type __clockid_t = ::core::ffi::c_int; +pub type __timer_t = *mut ::core::ffi::c_void; +pub type __blksize_t = ::core::ffi::c_long; +pub type __blkcnt_t = ::core::ffi::c_long; +pub type __blkcnt64_t = ::core::ffi::c_long; +pub type __fsblkcnt_t = ::core::ffi::c_ulong; +pub type __fsblkcnt64_t = ::core::ffi::c_ulong; +pub type __fsfilcnt_t = ::core::ffi::c_ulong; +pub type __fsfilcnt64_t = ::core::ffi::c_ulong; +pub type __fsword_t = ::core::ffi::c_long; +pub type __ssize_t = ::core::ffi::c_long; +pub type __syscall_slong_t = ::core::ffi::c_long; +pub type __syscall_ulong_t = ::core::ffi::c_ulong; +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut ::core::ffi::c_char; +pub type __intptr_t = ::core::ffi::c_long; +pub type __socklen_t = ::core::ffi::c_uint; +pub type __sig_atomic_t = ::core::ffi::c_int; +pub type int_least8_t = __int_least8_t; +pub type int_least16_t = __int_least16_t; +pub type int_least32_t = __int_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least8_t = __uint_least8_t; +pub type uint_least16_t = __uint_least16_t; +pub type uint_least32_t = __uint_least32_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = ::core::ffi::c_schar; +pub type int_fast16_t = ::core::ffi::c_long; +pub type int_fast32_t = ::core::ffi::c_long; +pub type int_fast64_t = ::core::ffi::c_long; +pub type uint_fast8_t = ::core::ffi::c_uchar; +pub type uint_fast16_t = ::core::ffi::c_ulong; +pub type uint_fast32_t = ::core::ffi::c_ulong; +pub type uint_fast64_t = ::core::ffi::c_ulong; +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; +pub type __gwchar_t = ::core::ffi::c_int; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct imaxdiv_t { + pub quot: ::core::ffi::c_long, + pub rem: ::core::ffi::c_long, +} +extern "C" { + pub fn imaxabs(__n: intmax_t) -> intmax_t; +} +extern "C" { + pub fn imaxdiv(__numer: intmax_t, __denom: intmax_t) -> imaxdiv_t; +} +extern "C" { + pub fn strtoimax( + __nptr: *const ::core::ffi::c_char, + __endptr: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> intmax_t; +} +extern "C" { + pub fn strtoumax( + __nptr: *const ::core::ffi::c_char, + __endptr: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> uintmax_t; +} +extern "C" { + pub fn wcstoimax( + __nptr: *const __gwchar_t, + __endptr: *mut *mut __gwchar_t, + __base: ::core::ffi::c_int, + ) -> intmax_t; +} +extern "C" { + pub fn wcstoumax( + __nptr: *const __gwchar_t, + __endptr: *mut *mut __gwchar_t, + __base: ::core::ffi::c_int, + ) -> uintmax_t; +} +pub type wchar_t = ::core::ffi::c_int; +#[repr(C)] +#[repr(align(16))] +#[derive(Debug, Default, Copy, Clone)] +pub struct max_align_t { + pub __clang_max_align_nonce1: ::core::ffi::c_longlong, + pub __bindgen_padding_0: u64, + pub __clang_max_align_nonce2: u128, +} +pub type output_fn_t = ::core::option::Option< + unsafe extern "C" fn(ctx: *mut ::core::ffi::c_void, data: *const u8, len: usize), +>; +pub type cross_call_fn_t = ::core::option::Option< + unsafe extern "C" fn( + call_id: u32, + data: *const u8, + len: usize, + ctx: *mut ::core::ffi::c_void, + output: output_fn_t, + ), +>; +pub type ecall_get_version_fn_t = + ::core::option::Option; +pub type alloc_fn_t = + ::core::option::Option *mut u8>; +pub type dealloc_fn_t = + ::core::option::Option; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct ocalls_t { + pub ocall: cross_call_fn_t, + pub alloc: alloc_fn_t, + pub dealloc: dealloc_fn_t, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct config_t { + pub is_dylib: ::core::ffi::c_int, + pub enclaved: ::core::ffi::c_int, + pub ocalls: ocalls_t, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct ecalls_t { + pub ecall: cross_call_fn_t, + pub get_version: ecall_get_version_fn_t, +} +pub type init_t = ::core::option::Option< + unsafe extern "C" fn(config: *const config_t, ecalls: *mut ecalls_t) -> ::core::ffi::c_int, +>; diff --git a/crates/pink/macro/Cargo.toml b/crates/pink/macro/Cargo.toml new file mode 100644 index 0000000000..243354bca9 --- /dev/null +++ b/crates/pink/macro/Cargo.toml @@ -0,0 +1,20 @@ +[package] +description = "Helper macros for pink runtime" +homepage = "https://github.com/Phala-Network/phala-blockchain" +license = "Apache-2.0" +edition = "2021" +name = "pink-macro" +version = "0.1.1" + +[lib] +proc-macro = true + +[dependencies] +proc-macro-crate = "1.0.0" +proc-macro2 = "1.0" +syn = { version = "1.0", features = ["full", "visit-mut", "extra-traits", "parsing"] } +heck = "0.4.0" + +[dev-dependencies] +insta = "1.14.0" +rustfmt-snippet = { version = "0.1.0" } diff --git a/crates/pink/macro/src/lib.rs b/crates/pink/macro/src/lib.rs new file mode 100644 index 0000000000..cf75c7f6cb --- /dev/null +++ b/crates/pink/macro/src/lib.rs @@ -0,0 +1,14 @@ +use proc_macro::TokenStream; + +mod macro_xcall; +#[cfg(test)] +mod tests; + +#[proc_macro_attribute] +pub fn cross_call(config: TokenStream, input: TokenStream) -> TokenStream { + macro_xcall::patch( + syn::parse_macro_input!(config), + syn::parse_macro_input!(input), + ) + .into() +} diff --git a/crates/pink/macro/src/macro_xcall.rs b/crates/pink/macro/src/macro_xcall.rs new file mode 100644 index 0000000000..409d22e756 --- /dev/null +++ b/crates/pink/macro/src/macro_xcall.rs @@ -0,0 +1,338 @@ +use proc_macro2::{Ident, Literal, Span, TokenStream}; +use syn::{parse_quote, Result}; + +struct Method { + id: u32, + args: Vec, + method: syn::TraitItemMethod, +} + +impl Method { + fn parse(method: &syn::TraitItemMethod) -> Result { + let mut id = None; + + for attr in method.attrs.iter() { + if !attr.is_xcall() { + continue; + } + match attr.parse_meta()? { + syn::Meta::List(list) => { + for nested in list.nested.iter() { + match nested { + syn::NestedMeta::Meta(syn::Meta::NameValue(name_value)) => { + match name_value + .path + .get_ident() + .ok_or_else(|| { + syn::Error::new_spanned( + &name_value.path, + "Expected an identifier", + ) + })? + .to_string() + .as_str() + { + "id" => match &name_value.lit { + syn::Lit::Int(value) => { + let parsed_id = value.base10_parse::()?; + if parsed_id == 0 { + return Err(syn::Error::new_spanned( + &name_value.lit, + "Id must be non-zero", + )); + } + id = Some(parsed_id); + } + _ => { + return Err(syn::Error::new_spanned( + &name_value.lit, + "Expected an integer", + )); + } + }, + attr => { + return Err(syn::Error::new_spanned( + name_value, + format!("Unknown attribute: {attr}"), + )); + } + } + } + _ => { + return Err(syn::Error::new_spanned(nested, "Invalid attribute")); + } + } + } + } + _ => { + let err = syn::Error::new_spanned(attr, "call attribute must be a list"); + return Err(err); + } + } + } + + match id { + None => Err(syn::Error::new_spanned( + &method.sig, + "Missing call id attribute", + )), + Some(id) => { + let mut method = method.clone(); + let args = parse_args(&method)?; + method.attrs.retain(|attr| !attr.is_xcall()); + Ok(Method { id, args, method }) + } + } + } +} + +pub(crate) fn patch(config: TokenStream, input: TokenStream) -> TokenStream { + match patch_or_err(config, input) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error(), + } +} + +fn patch_or_err(config: TokenStream, input: TokenStream) -> Result { + let impl_for: syn::Ident = syn::parse2(config)?; + let trait_item: syn::ItemTrait = syn::parse2(input)?; + let call_methods: Result> = trait_item + .items + .iter() + .filter_map(|item| { + if let syn::TraitItem::Method(method) = item { + Some(Method::parse(method)) + } else { + None + } + }) + .collect(); + let call_methods = call_methods?; + check_redundant_call_id(&call_methods)?; + check_args_multi_ref(&call_methods)?; + + let trait_item = patch_call_trait(trait_item); + + let call_impl = gen_call_impl(&call_methods, &trait_item.ident, &impl_for)?; + let trait_ro = gen_call_impl_ro(&call_methods, &trait_item.ident, &impl_for)?; + + let exec_dispatcher = gen_exec_dispatcher(&call_methods, &trait_item.ident)?; + + let id2name = gen_id2name(&call_methods)?; + + Ok(parse_quote! { + #trait_item + + #call_impl + + #trait_ro + + #exec_dispatcher + + #id2name + }) +} + +fn gen_exec_dispatcher(call_methods: &[Method], trait_name: &Ident) -> Result { + let mut calls: Vec = Vec::new(); + + for method in call_methods { + let id = Literal::u32_unsuffixed(method.id); + let sig = &method.method.sig; + let name = &sig.ident; + let args = &method.args; + let exec_fn = if is_mut_self(method) { + Ident::new("execute_mut", Span::call_site()) + } else { + Ident::new("execute", Span::call_site()) + }; + + calls.push(parse_quote! { + #id => { + let (#(#args),*) = Decode::decode(&mut &input[..]).expect("Failed to decode args"); + executor.#exec_fn(move || srv.#name(#(#args),*)).encode() + } + }); + } + + Ok(parse_quote! { + pub fn dispatch( + executor: &mut (impl Executing + ?Sized), + srv: &mut (impl #trait_name + ?Sized), + id: u32, + input: &[u8], + ) -> Vec { + match id { + #(#calls)* + _ => panic!("Unknown call id {}", id), + } + } + }) +} + +fn gen_id2name(methods: &[Method]) -> Result { + let (ids, names): (Vec<_>, Vec<_>) = methods + .iter() + .map(|m| (m.id, Literal::string(&m.method.sig.ident.to_string()))) + .unzip(); + Ok(parse_quote! { + pub fn id2name(id: u32) -> &'static str { + match id { + #(#ids => #names,)* + _ => "unknown", + } + } + }) +} + +fn parse_args(method: &syn::TraitItemMethod) -> Result> { + method + .sig + .inputs + .iter() + .filter_map(|arg| { + if let syn::FnArg::Typed(arg) = arg { + if let syn::Pat::Ident(ident) = &*arg.pat { + Some(Ok(parse_quote!(#ident))) + } else { + Some(Err(syn::Error::new_spanned( + &arg.pat, + "Expected an identifier", + ))) + } + } else { + None + } + }) + .collect() +} + +fn gen_call_impl( + call_methods: &[Method], + trait_name: &Ident, + impl_for: &Ident, +) -> Result { + let impl_methods: Result> = + call_methods.iter().map(gen_call_impl_method).collect(); + let impl_methods = impl_methods?; + Ok(parse_quote! { + impl #trait_name for T { + #(#impl_methods)* + } + }) +} + +fn gen_call_impl_ro( + call_methods: &[Method], + trait_name: &Ident, + impl_for: &Ident, +) -> Result { + let methods: Vec<_> = call_methods.iter().filter(|m| !is_mut_self(m)).collect(); + let trait_methods: Vec<_> = methods.iter().map(|m| m.method.clone()).collect(); + let impl_methods: Result> = + methods.into_iter().map(gen_call_impl_method).collect(); + let impl_methods = impl_methods?; + let trait_ro = Ident::new(&format!("{trait_name}Ro"), Span::call_site()); + Ok(parse_quote! { + pub trait #trait_ro { + #(#trait_methods)* + } + impl #trait_ro for T { + #(#impl_methods)* + } + }) +} + +fn is_mut_self(method: &Method) -> bool { + match method.method.sig.inputs.first() { + Some(syn::FnArg::Receiver(recv)) => recv.mutability.is_some(), + _ => false, + } +} + +fn gen_call_impl_method(method: &Method) -> Result { + let sig = method.method.sig.clone(); + let call_id = Literal::u32_unsuffixed(method.id); + let args = &method.args; + let cross_fn = if is_mut_self(method) { + Ident::new("cross_call_mut", Span::call_site()) + } else { + Ident::new("cross_call", Span::call_site()) + }; + Ok(parse_quote! { + #sig { + let inputs = (#(#args),*); + let ret = self.#cross_fn(#call_id, &inputs.encode()); + Decode::decode(&mut &ret[..]).expect("Decode failed") + } + }) +} + +fn check_redundant_call_id(methods: &[Method]) -> Result<()> { + let mut ids = Vec::new(); + for method in methods { + if ids.contains(&method.id) { + return Err(syn::Error::new_spanned( + &method.method.sig, + format!("Duplicate call id: {}", method.id), + )); + } + ids.push(method.id); + } + Ok(()) +} + +fn check_args_multi_ref(methods: &[Method]) -> Result<()> { + for method in methods { + let mut n_ref = 0; + let mut has_mut_ref = false; + for arg in method.method.sig.inputs.iter() { + let syn::FnArg::Typed(arg) = arg else { + continue; + }; + let syn::Type::Reference(ty) = &*arg.ty else { + continue; + }; + n_ref += 1; + if ty.mutability.is_some() { + has_mut_ref = true; + } + } + if has_mut_ref && n_ref > 1 { + return Err(syn::Error::new_spanned( + &method.method.sig, + "Only one &mut ref argument is allowed", + )); + } + } + Ok(()) +} + +fn patch_call_trait(mut input: syn::ItemTrait) -> syn::ItemTrait { + for item in input.items.iter_mut() { + if let syn::TraitItem::Method(method) = item { + // Remove the call attribute + method.attrs.retain(|attr| !attr.is_xcall()); + // Add &mut self as receiver + if !matches!(&method.sig.inputs.first(), Some(syn::FnArg::Receiver(_))) { + method.sig.inputs.insert( + 0, + parse_quote! { + &mut self + }, + ); + } + } + } + input +} + +trait AttributeExt { + fn is_xcall(&self) -> bool; +} + +impl AttributeExt for syn::Attribute { + fn is_xcall(&self) -> bool { + self.path.is_ident("xcall") + } +} diff --git a/crates/pink/macro/src/snapshots/pink_macro__tests__xcall.snap b/crates/pink/macro/src/snapshots/pink_macro__tests__xcall.snap new file mode 100644 index 0000000000..46a2ef57db --- /dev/null +++ b/crates/pink/macro/src/snapshots/pink_macro__tests__xcall.snap @@ -0,0 +1,84 @@ +--- +source: crates/pink/macro/src/tests.rs +assertion_line: 21 +expression: "rustfmt_snippet::rustfmt_token_stream(&stream).unwrap()" +--- +pub trait ECalls { + fn instantiate( + &self, + code_hash: Hash, + endowment: Balance, + gas_limit: u64, + input_data: Vec, + ) -> Result; + fn set_id(&mut self, id: Hash) -> Result; +} +impl ECalls for T { + fn instantiate( + &self, + code_hash: Hash, + endowment: Balance, + gas_limit: u64, + input_data: Vec, + ) -> Result { + let inputs = (code_hash, endowment, gas_limit, input_data); + let ret = self.cross_call(1, &inputs.encode()); + Decode::decode(&mut &ret[..]).expect("Decode failed") + } + fn set_id(&mut self, id: Hash) -> Result { + let inputs = (id); + let ret = self.cross_call_mut(2, &inputs.encode()); + Decode::decode(&mut &ret[..]).expect("Decode failed") + } +} +pub trait ECallsRo { + fn instantiate( + &self, + code_hash: Hash, + endowment: Balance, + gas_limit: u64, + input_data: Vec, + ) -> Result; +} +impl ECallsRo for T { + fn instantiate( + &self, + code_hash: Hash, + endowment: Balance, + gas_limit: u64, + input_data: Vec, + ) -> Result { + let inputs = (code_hash, endowment, gas_limit, input_data); + let ret = self.cross_call(1, &inputs.encode()); + Decode::decode(&mut &ret[..]).expect("Decode failed") + } +} +pub fn dispatch( + executor: &mut (impl Executing + ?Sized), + srv: &mut (impl ECalls + ?Sized), + id: u32, + input: &[u8], +) -> Vec { + match id { + 1 => { + let (code_hash, endowment, gas_limit, input_data) = + Decode::decode(&mut &input[..]).expect("Failed to decode args"); + executor + .execute(move || srv.instantiate(code_hash, endowment, gas_limit, input_data)) + .encode() + } + 2 => { + let (id) = Decode::decode(&mut &input[..]).expect("Failed to decode args"); + executor.execute_mut(move || srv.set_id(id)).encode() + } + _ => panic!("Unknown call id {}", id), + } +} +pub fn id2name(id: u32) -> &'static str { + match id { + 1u32 => "instantiate", + 2u32 => "set_id", + _ => "unknown", + } +} + diff --git a/crates/pink/macro/src/tests.rs b/crates/pink/macro/src/tests.rs new file mode 100644 index 0000000000..905c3e6084 --- /dev/null +++ b/crates/pink/macro/src/tests.rs @@ -0,0 +1,22 @@ +#[cfg(all(target_arch="x86_64", target_os = "linux"))] +#[test] +fn test_xcall() { + let stream = crate::macro_xcall::patch(syn::parse_quote!(Impl), syn::parse_quote! { + pub trait ECalls { + #[xcall(id = 1)] + fn instantiate( + &self, + code_hash: Hash, + endowment: Balance, + gas_limit: u64, + input_data: Vec, + ) -> Result; + #[xcall(id = 2)] + fn set_id( + &mut self, + id: Hash, + ) -> Result; + } + }); + insta::assert_display_snapshot!(rustfmt_snippet::rustfmt_token_stream(&stream).unwrap()) +} diff --git a/crates/pink/pink-extension-runtime/src/lib.rs b/crates/pink/pink-extension-runtime/src/lib.rs index cae1c55d5e..4202b513cd 100644 --- a/crates/pink/pink-extension-runtime/src/lib.rs +++ b/crates/pink/pink-extension-runtime/src/lib.rs @@ -7,7 +7,8 @@ use std::{ use pink_extension::{ chain_extension::{ - self as ext, HttpRequest, HttpResponse, PinkExtBackend, SigType, StorageQuotaExceeded, + self as ext, HttpRequest, HttpRequestError, HttpResponse, PinkExtBackend, SigType, + StorageQuotaExceeded, }, Balance, EcdhPublicKey, EcdsaPublicKey, EcdsaSignature, Hash, }; @@ -25,7 +26,6 @@ pub trait PinkRuntimeEnv { type AccountId: AsRef<[u8]> + Display; fn address(&self) -> &Self::AccountId; - fn call_elapsed(&self) -> Option; } pub struct DefaultPinkExtension<'a, T, Error> { @@ -42,87 +42,90 @@ impl<'a, T, E> DefaultPinkExtension<'a, T, E> { } } -impl> PinkExtBackend for DefaultPinkExtension<'_, T, E> { - type Error = E; - fn http_request(&self, request: HttpRequest) -> Result { - // Hardcoded limitations for now - const MAX_QUERY_TIME: Duration = Duration::from_secs(10); - const MAX_BODY_SIZE: usize = 1024 * 256; // 256KB - - let elapsed = self.env.call_elapsed().ok_or("Invalid exec env")?; - if elapsed >= MAX_QUERY_TIME { - return Err("Query time limitation exceeded".into()); - } - let timeout = MAX_QUERY_TIME.saturating_sub(elapsed); - - let url: reqwest::Url = request.url.parse().or(Err("Invalid url"))?; - - let client = reqwest::blocking::Client::builder() - .timeout(timeout) - .env_proxy(url.host_str().unwrap_or_default()) - .build() - .or(Err("Failed to create client"))?; - - let method: Method = - FromStr::from_str(request.method.as_str()).or(Err("Invalid HTTP method"))?; - let mut headers = HeaderMap::new(); - for (key, value) in &request.headers { - let key = HeaderName::from_str(key.as_str()).or(Err("Invalid HTTP header key"))?; - let value = HeaderValue::from_str(value).or(Err("Invalid HTTP header value"))?; - headers.insert(key, value); - } - - let result = client - .request(method, url) - .headers(headers) - .body(request.body) - .send(); - - let mut response = match result { - Ok(response) => response, - Err(err) => { - // If there is somthing wrong with the network, we can not inspect the reason too - // much here. Let it return a non-standard 523 here. - log::info!("HTTP request error: {err}"); - return Ok(HttpResponse { - status_code: 523, - reason_phrase: "Unreachable".into(), - body: format!("{err:?}").into_bytes(), - headers: vec![], - }); - } - }; - - let headers: Vec<_> = response - .headers() - .iter() - .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().into())) - .collect(); - - let mut body = Vec::new(); - let mut writer = LimitedWriter::new(&mut body, MAX_BODY_SIZE); +pub fn http_request( + request: HttpRequest, + timeout_ms: u64, +) -> Result { + if timeout_ms == 0 { + return Err(HttpRequestError::Timeout); + } + let timeout = Duration::from_millis(timeout_ms); + let url: reqwest::Url = request.url.parse().or(Err(HttpRequestError::InvalidUrl))?; + let client = reqwest::blocking::Client::builder() + .timeout(timeout) + .env_proxy(url.host_str().unwrap_or_default()) + .build() + .or(Err(HttpRequestError::FailedToCreateClient))?; + + let method: Method = + FromStr::from_str(request.method.as_str()).or(Err(HttpRequestError::InvalidMethod))?; + let mut headers = HeaderMap::new(); + for (key, value) in &request.headers { + let key = + HeaderName::from_str(key.as_str()).or(Err(HttpRequestError::InvalidHeaderName))?; + let value = HeaderValue::from_str(value).or(Err(HttpRequestError::InvalidHeaderValue))?; + headers.insert(key, value); + } - if let Err(err) = response.copy_to(&mut writer) { - log::info!("Failed to read HTTP body: {err}"); + let result = client + .request(method, url) + .headers(headers) + .body(request.body) + .send(); + + let mut response = match result { + Ok(response) => response, + Err(err) => { + // If there is somthing wrong with the network, we can not inspect the reason too + // much here. Let it return a non-standard 523 here. + log::info!("HTTP request error: {err}"); return Ok(HttpResponse { - status_code: 524, - reason_phrase: "IO Error".into(), + status_code: 523, + reason_phrase: "Unreachable".into(), body: format!("{err:?}").into_bytes(), headers: vec![], }); - }; + } + }; + + let headers: Vec<_> = response + .headers() + .iter() + .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().into())) + .collect(); + + const MAX_BODY_SIZE: usize = 1024 * 16; // 16KB + + let mut body = Vec::new(); + let mut writer = LimitedWriter::new(&mut body, MAX_BODY_SIZE); + + if let Err(err) = response.copy_to(&mut writer) { + log::info!("Failed to read HTTP body: {err}"); + return Ok(HttpResponse { + status_code: 524, + reason_phrase: "IO Error".into(), + body: format!("{err:?}").into_bytes(), + headers: vec![], + }); + }; + + let response = HttpResponse { + status_code: response.status().as_u16(), + reason_phrase: response + .status() + .canonical_reason() + .unwrap_or_default() + .into(), + body, + headers, + }; + Ok(response) +} - let response = HttpResponse { - status_code: response.status().as_u16(), - reason_phrase: response - .status() - .canonical_reason() - .unwrap_or_default() - .into(), - body, - headers, - }; - Ok(response) +impl> PinkExtBackend for DefaultPinkExtension<'_, T, E> { + type Error = E; + fn http_request(&self, request: HttpRequest) -> Result { + http_request(request, 10 * 1000).map_err(|err| err.display().into()) } fn sign( @@ -280,6 +283,21 @@ impl> PinkExtBackend for DefaultPinkExt fn worker_pubkey(&self) -> Result { Ok(Default::default()) } + + fn code_exists(&self, _code_hash: Hash, _sidevm: bool) -> Result { + Ok(false) + } + + fn import_latest_system_code( + &self, + _payer: ext::AccountId, + ) -> Result, Self::Error> { + Ok(None) + } + + fn runtime_version(&self) -> Result<(u32, u32), Self::Error> { + Ok((1, 0)) + } } struct LimitedWriter { diff --git a/crates/pink/pink-extension-runtime/src/mock_ext.rs b/crates/pink/pink-extension-runtime/src/mock_ext.rs index 0f4978aff4..403eb0146f 100644 --- a/crates/pink/pink-extension-runtime/src/mock_ext.rs +++ b/crates/pink/pink-extension-runtime/src/mock_ext.rs @@ -17,10 +17,6 @@ impl super::PinkRuntimeEnv for MockExtension { static ADDRESS: AccountId32 = AccountId32::new([0; 32]); &ADDRESS } - - fn call_elapsed(&self) -> Option { - Some(std::time::Duration::from_secs(0)) - } } impl ext::PinkExtBackend for MockExtension { @@ -129,6 +125,18 @@ impl ext::PinkExtBackend for MockExtension { fn worker_pubkey(&self) -> Result { Ok(Default::default()) } + + fn code_exists(&self, _code_hash: Hash, _sidevm: bool) -> Result { + Ok(false) + } + + fn import_latest_system_code(&self, _payer: ext::AccountId) -> Result, Self::Error> { + Ok(None) + } + + fn runtime_version(&self) -> Result<(u32, u32), Self::Error> { + Ok((1, 0)) + } } thread_local! { diff --git a/crates/pink/pink-extension/src/chain_extension.rs b/crates/pink/pink-extension/src/chain_extension.rs index 9507741afd..16759a2edd 100644 --- a/crates/pink/pink-extension/src/chain_extension.rs +++ b/crates/pink/pink-extension/src/chain_extension.rs @@ -2,7 +2,7 @@ use alloc::borrow::Cow; use alloc::vec::Vec; use ink::ChainExtensionInstance; -pub use http_request::{HttpRequest, HttpResponse}; +pub use http_request::{HttpRequest, HttpResponse, HttpRequestError}; pub use ink::primitives::AccountId; pub use signing::SigType; @@ -185,6 +185,20 @@ pub trait PinkExt { /// Get current millis since unix epoch from the OS. (Query only) #[ink(extension = 18, handle_status = false)] fn untrusted_millis_since_unix_epoch() -> u64; + + /// Check whether the code exists in the cluster storage. + #[ink(extension = 19, handle_status = false)] + fn code_exists(code_hash: Hash, sidevm: bool) -> bool; + + /// This loads the latest system contract code from chain storage to the cluster storage. + /// + /// Returns the code hash of the latest system contract code. + #[ink(extension = 20, handle_status = false)] + fn import_latest_system_code(payer: AccountId) -> Option; + + /// Get the version of the current contract runtime in this cluster. + #[ink(extension = 21, handle_status = false)] + fn runtime_version() -> (u32, u32); } pub fn pink_extension_instance() -> ::Instance { diff --git a/crates/pink/pink-extension/src/chain_extension/http_request.rs b/crates/pink/pink-extension/src/chain_extension/http_request.rs index f3cfddb1d5..cf02d4b9cc 100644 --- a/crates/pink/pink-extension/src/chain_extension/http_request.rs +++ b/crates/pink/pink-extension/src/chain_extension/http_request.rs @@ -18,6 +18,30 @@ pub struct HttpResponse { pub body: Vec, } +#[derive(scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum HttpRequestError { + InvalidUrl, + InvalidMethod, + InvalidHeaderName, + InvalidHeaderValue, + FailedToCreateClient, + Timeout, +} + +impl HttpRequestError { + pub fn display(&self) -> &'static str { + match self { + Self::InvalidUrl => "Invalid URL", + Self::InvalidMethod => "Invalid method", + Self::InvalidHeaderName => "Invalid header name", + Self::InvalidHeaderValue => "Invalid header value", + Self::FailedToCreateClient => "Failed to create client", + Self::Timeout => "Timeout", + } + } +} + impl HttpResponse { pub fn ok(body: Vec) -> Self { Self { diff --git a/crates/pink/pink-extension/src/lib.rs b/crates/pink/pink-extension/src/lib.rs index 7c597b96ec..4a8e0f7ddc 100644 --- a/crates/pink/pink-extension/src/lib.rs +++ b/crates/pink/pink-extension/src/lib.rs @@ -71,11 +71,8 @@ pub enum HookPoint { #[derive(Encode, Decode, Debug)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] pub enum PinkEvent { - /// Contract pushed a raw message - Message(Message), - /// Contract pushed an osp message - OspMessage(OspMessage), /// Set contract hook + #[codec(index = 2)] SetHook { /// The event to hook hook: HookPoint, @@ -87,6 +84,7 @@ pub enum PinkEvent { gas_limit: u64, }, /// Deploy a sidevm instance to given contract instance + #[codec(index = 3)] DeploySidevmTo { /// The target contract address contract: AccountId, @@ -94,29 +92,34 @@ pub enum PinkEvent { code_hash: Hash, }, /// Push a message to the associated sidevm instance. + #[codec(index = 4)] SidevmMessage(Vec), /// CacheOperation + #[codec(index = 5)] CacheOp(CacheOp), /// Stop the side VM instance if it is running. + #[codec(index = 6)] StopSidevm, /// Force stop the side VM instance if it is running. + #[codec(index = 7)] ForceStopSidevm { /// The target contract address contract: AccountId, }, /// Set the log handler contract for current cluster. + #[codec(index = 8)] SetLogHandler(AccountId), /// Set the weight of contract used to schedule queries and sidevm vruntime + #[codec(index = 9)] SetContractWeight { contract: AccountId, weight: u32 }, - /// Upgrade the system contract to latest version. - UpgradeSystemContract { storage_payer: AccountId }, + /// Upgrade the runtime to given version + #[codec(index = 10)] + UpgradeRuntimeTo { version: (u32, u32) }, } impl PinkEvent { pub fn allowed_in_query(&self) -> bool { match self { - PinkEvent::Message(_) => false, - PinkEvent::OspMessage(_) => false, PinkEvent::SetHook { .. } => false, PinkEvent::DeploySidevmTo { .. } => true, PinkEvent::SidevmMessage(_) => true, @@ -125,14 +128,12 @@ impl PinkEvent { PinkEvent::ForceStopSidevm { .. } => true, PinkEvent::SetLogHandler(_) => false, PinkEvent::SetContractWeight { .. } => false, - PinkEvent::UpgradeSystemContract { .. } => false, + PinkEvent::UpgradeRuntimeTo { .. } => false, } } pub fn name(&self) -> &'static str { match self { - PinkEvent::Message(_) => "Message", - PinkEvent::OspMessage(_) => "OspMessage", PinkEvent::SetHook { .. } => "SetHook", PinkEvent::DeploySidevmTo { .. } => "DeploySidevmTo", PinkEvent::SidevmMessage(_) => "SidevmMessage", @@ -141,7 +142,7 @@ impl PinkEvent { PinkEvent::ForceStopSidevm { .. } => "ForceStopSidevm", PinkEvent::SetLogHandler(_) => "SetLogHandler", PinkEvent::SetContractWeight { .. } => "SetContractWeight", - PinkEvent::UpgradeSystemContract { .. } => "UpgradeSystemContract", + PinkEvent::UpgradeRuntimeTo { .. } => "UpgradeRuntimeTo", } } } @@ -182,23 +183,6 @@ impl PinkEvent { } } -/// Push a raw message to a topic accepting only vanilla messages -/// -/// Most phala system topics accept vanilla messages -pub fn push_message(payload: Vec, topic: Vec) { - emit_event::(PinkEvent::Message(Message { payload, topic })) -} - -/// Push a message to a topic accepting optional secret messages -/// -/// Contract commands topic accept osp messages -pub fn push_osp_message(payload: Vec, topic: Vec, remote_pubkey: Option) { - emit_event::(PinkEvent::OspMessage(OspMessage { - message: Message { payload, topic }, - remote_pubkey, - })) -} - /// Turn on on_block_end feature and set it's selector /// pub fn set_hook(hook: HookPoint, contract: AccountId, selector: u32, gas_limit: u64) { @@ -255,9 +239,9 @@ pub fn set_contract_weight(contract: AccountId, weight: u32) { emit_event::(PinkEvent::SetContractWeight { contract, weight }); } -/// Upgrade the system contract to latest version -pub fn upgrade_system_contract(storage_payer: AccountId) { - emit_event::(PinkEvent::UpgradeSystemContract { storage_payer }); +/// Upgrade the runtime to given version +pub fn upgrade_runtime(version: (u32, u32)) { + emit_event::(PinkEvent::UpgradeRuntimeTo { version }); } /// Pink defined environment. Used this environment to access the fat contract runtime features. diff --git a/crates/pink/pink-extension/src/system.rs b/crates/pink/pink-extension/src/system.rs index 931915416b..c9623f70e0 100644 --- a/crates/pink/pink-extension/src/system.rs +++ b/crates/pink/pink-extension/src/system.rs @@ -13,6 +13,8 @@ use crate::{AccountId, Balance, Hash}; pub enum Error { PermisionDenied, DriverNotFound, + CodeNotFound, + ConditionNotMet, } /// Result type for the system contract messages @@ -90,6 +92,17 @@ pub trait System { /// Upgrade the system contract to the latest version. #[ink(message)] fn upgrade_system_contract(&self) -> Result<()>; + + /// Do the upgrade condition checks and state migration if necessary. + /// + /// This function is called by the system contract itself on the new version + /// of code in the upgrading process. + #[ink(message)] + fn do_upgrade(&self, from_version: (u16, u16)) -> Result<()>; + + /// Upgrade the contract runtime + #[ink(message)] + fn upgrade_runtime(&self, version: (u32, u32)) -> Result<()>; } /// Errors that can occur upon calling a driver contract. diff --git a/crates/pink/runner/Cargo.toml b/crates/pink/runner/Cargo.toml new file mode 100644 index 0000000000..cf8c7f5875 --- /dev/null +++ b/crates/pink/runner/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "pink-runner" +version = "0.1.0" +edition = "2021" + +[dependencies] +pink-capi = { path = "../capi" } +pink-extension-runtime = { path = "../pink-extension-runtime" } +phala-crypto = { path = "../../phala-crypto" } +serde = { version = "1", features = ["derive"] } +sp-weights = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +im = "15" +once_cell = "1" +libc = "0.2" +log = "0.4" +environmental = "1" + +[dev-dependencies] +pink = { path = "../runtime" } +scale = { package = "parity-scale-codec", version = "3.1", default-features = false, features = [ + "derive", +] } +insta = "1" +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +pallet-contracts-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +env_logger = "0.10.0" +assert_matches = "1.5.0" diff --git a/crates/pink/runner/src/lib.rs b/crates/pink/runner/src/lib.rs new file mode 100644 index 0000000000..4c576c4280 --- /dev/null +++ b/crates/pink/runner/src/lib.rs @@ -0,0 +1,11 @@ +pub use pink_capi as capi; +pub use sp_weights::constants; +pub use pink_extension_runtime::local_cache; + +pub mod types { + pub use crate::capi::types::*; + pub use crate::capi::v1::ecall::TransactionArguments; +} + +pub mod storage; +pub mod runtimes; diff --git a/crates/pink/runner/src/runtimes.rs b/crates/pink/runner/src/runtimes.rs new file mode 100644 index 0000000000..f5b6133092 --- /dev/null +++ b/crates/pink/runner/src/runtimes.rs @@ -0,0 +1,51 @@ +use std::ffi::CString; +use std::os::unix::ffi::OsStrExt; + +use log::error; + +/// Load given version of lib pink library using dlopen and return a handle to it. +/// This is the low level support function. Upper level `PinkRuntime` will manage the +/// lifecycle of the handle(closing it on drop). +fn load_pink_library((major, minor): (u32, u32)) -> *mut libc::c_void { + let runtime_dir = match std::env::var("PINK_RUNTIME_PATH") { + Ok(path) => std::path::Path::new(&path).to_owned(), + Err(_) => std::env::current_exe() + .expect("Failed to get current exe path") + .parent() + .unwrap() + .to_owned(), + }; + let filename = format!("libpink.so.{major}.{minor}"); + let path = runtime_dir.join(filename); + let Ok(path) = CString::new(path.as_os_str().as_bytes()) else { + return std::ptr::null_mut(); + }; + let handle = unsafe { libc::dlopen(path.as_ptr(), libc::RTLD_NOW) }; + if handle.is_null() { + let err = unsafe { std::ffi::CStr::from_ptr(libc::dlerror()) }; + error!( + "Failed to load {}: {}", + path.to_string_lossy(), + err.to_string_lossy() + ); + } + handle +} + +/// Check if we are running in an enclave according to the existence of /dev/attestation/user_report_data +/// +/// False positive is possible. +fn in_enclave() -> i32 { + let path = std::path::Path::new("/dev/attestation/user_report_data"); + if path.exists() { + 1 + } else { + 0 + } +} + +pub mod v1; + +pub fn max_supported_version() -> (u32, u32) { + (1, 0) +} diff --git a/crates/pink/runner/src/runtimes/v1.rs b/crates/pink/runner/src/runtimes/v1.rs new file mode 100644 index 0000000000..35807360ac --- /dev/null +++ b/crates/pink/runner/src/runtimes/v1.rs @@ -0,0 +1,153 @@ +use super::{in_enclave, load_pink_library}; +use once_cell::sync::Lazy; +use pink_capi::{ + helper::InnerType, + v1::{ + config_t, cross_call_fn_t, ecalls_t, init_t, + ocall::{self, OCalls}, + ocalls_t, output_fn_t, IdentExecute, + }, +}; +use std::ffi::c_void; + +pub struct Runtime { + handle: *const c_void, + ecall_fn: InnerType, +} + +unsafe impl Send for Runtime {} +unsafe impl Sync for Runtime {} + +pub static RUNTIME: Lazy = Lazy::new(Default::default); + +impl Default for Runtime { + fn default() -> Self { + Self::load_by_version((1, 0)) + } +} + +impl Runtime { + pub fn load_by_version(version: (u32, u32)) -> Self { + let (major, minor) = version; + let handle = load_pink_library(version); + if handle.is_null() { + panic!("Failed to load pink dylib {major}.{minor}"); + } + let init: init_t = unsafe { + std::mem::transmute(libc::dlsym( + handle, + b"__pink_runtime_init\0".as_ptr() as *const _, + )) + }; + let Some(init) = init else { + panic!("Failed to get initialize entry in pink dylib {major}.{minor}"); + }; + Runtime::from_fn(init, handle, version) + } + + pub fn from_fn(init: InnerType, handle: *mut c_void, version: (u32, u32)) -> Self { + let filename = format!("libpink.so.{}.{}", version.0, version.1); + let is_dylib = !handle.is_null(); + let config = config_t { + is_dylib: is_dylib as _, + enclaved: in_enclave(), + ocalls: ocalls_t { + ocall: Some(handle_ocall), + alloc: is_dylib.then_some(ocall_alloc), + dealloc: is_dylib.then_some(ocall_dealloc), + }, + }; + let mut ecalls = ecalls_t::default(); + let ret = unsafe { init(&config, &mut ecalls) }; + if ret != 0 { + panic!("Failed to initialize {filename}, ret={ret}"); + } + let Some(get_version) = ecalls.get_version else { + panic!("Failed to get ecall entry in {filename}"); + }; + let (mut major, mut minor) = (0, 0); + unsafe { get_version(&mut major, &mut minor) }; + if (major, minor) != version { + panic!("Version mismatch in {filename}, expect {version:?}, got ({major},{minor})"); + } + let Some(ecall) = ecalls.ecall else { + panic!("Failed to get ecall entry in {filename}"); + }; + Runtime { + handle, + ecall_fn: ecall, + } + } + + /// # Safety + /// + /// This is for unit test only. The pointer's in the runtime will be invalid if the original + /// runtime is dropped. + pub unsafe fn dup(&self) -> Self { + Runtime { + handle: std::ptr::null_mut(), + ecall_fn: self.ecall_fn, + } + } +} + +impl Drop for Runtime { + fn drop(&mut self) { + if self.handle.is_null() { + return; + } + unsafe { + libc::dlclose(self.handle as *mut _); + } + } +} + +impl Runtime { + pub fn ecall(&self, call_id: u32, data: &[u8]) -> Vec { + unsafe extern "C" fn output_fn(ctx: *mut ::core::ffi::c_void, data: *const u8, len: usize) { + let output = &mut *(ctx as *mut Vec); + output.extend_from_slice(std::slice::from_raw_parts(data, len)); + } + let mut output = Vec::new(); + let ctx = &mut output as *mut _ as *mut c_void; + unsafe { (self.ecall_fn)(call_id, data.as_ptr(), data.len(), ctx, Some(output_fn)) }; + output + } +} + +environmental::environmental! { current_ocalls: trait OCalls } + +pub fn using_ocalls(ocalls: &mut impl OCalls, f: F) -> R +where + F: FnOnce() -> R, +{ + current_ocalls::using(ocalls, f) +} + +unsafe extern "C" fn handle_ocall( + call_id: u32, + data: *const u8, + len: usize, + ctx: *mut ::core::ffi::c_void, + output_fn: output_fn_t, +) { + let input = std::slice::from_raw_parts(data, len); + let output = current_ocalls::with(move |ocalls| { + ocall::dispatch(&mut IdentExecute, ocalls, call_id, input) + }) + .expect("No OCalls set"); + if let Some(output_fn) = output_fn { + unsafe { output_fn(ctx, output.as_ptr(), output.len()) }; + } +} + +unsafe extern "C" fn ocall_alloc(size: usize, align: usize) -> *mut u8 { + std::alloc::alloc(std::alloc::Layout::from_size_align(size, align).unwrap()) +} + +unsafe extern "C" fn ocall_dealloc(ptr: *mut u8, size: usize, align: usize) { + std::alloc::dealloc( + ptr, + std::alloc::Layout::from_size_align(size, align).unwrap(), + ) +} diff --git a/crates/pink/runner/src/storage.rs b/crates/pink/runner/src/storage.rs new file mode 100644 index 0000000000..71218a6c53 --- /dev/null +++ b/crates/pink/runner/src/storage.rs @@ -0,0 +1,49 @@ +use im::OrdMap; +use pink_capi::{types::Hash, v1::ocall::StorageChanges}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Serialize, Deserialize)] +pub struct ClusterStorage { + root: Option, + kv_store: OrdMap, (i32, Vec)>, +} + +impl ClusterStorage { + pub fn root(&self) -> Option { + self.root + } + + pub fn set_root(&mut self, root: Hash) { + self.root = Some(root); + } + + pub fn get(&self, key: &[u8]) -> Option<&(i32, Vec)> { + self.kv_store.get(key) + } + + fn update(&mut self, key: Vec, value: Vec, rc: i32) { + if rc == 0 { + return; + } + match self.kv_store.get_mut(&key) { + Some((ref mut old_rc, ref mut old_value)) => { + *old_rc += rc; + if *old_rc == 0 { + self.kv_store.remove(&key); + } else { + *old_value = value; + } + } + None => { + self.kv_store.insert(key, (rc, value)); + } + } + } + + pub fn commit(&mut self, root: Hash, changes: StorageChanges) { + for (key, (value, rc)) in changes { + self.update(key, value, rc); + } + self.set_root(root); + } +} diff --git a/crates/pink/tests/fixtures/cross/cross.contract b/crates/pink/runner/tests/fixtures/cross/cross.contract similarity index 100% rename from crates/pink/tests/fixtures/cross/cross.contract rename to crates/pink/runner/tests/fixtures/cross/cross.contract diff --git a/crates/pink/tests/fixtures/cross/cross.wasm b/crates/pink/runner/tests/fixtures/cross/cross.wasm similarity index 100% rename from crates/pink/tests/fixtures/cross/cross.wasm rename to crates/pink/runner/tests/fixtures/cross/cross.wasm diff --git a/crates/pink/tests/fixtures/cross/metadata.json b/crates/pink/runner/tests/fixtures/cross/metadata.json similarity index 100% rename from crates/pink/tests/fixtures/cross/metadata.json rename to crates/pink/runner/tests/fixtures/cross/metadata.json diff --git a/crates/pink/tests/fixtures/crypto_hashes.wat b/crates/pink/runner/tests/fixtures/crypto_hashes.wat similarity index 100% rename from crates/pink/tests/fixtures/crypto_hashes.wat rename to crates/pink/runner/tests/fixtures/crypto_hashes.wat diff --git a/crates/pink/tests/fixtures/event_size.wat b/crates/pink/runner/tests/fixtures/event_size.wat similarity index 100% rename from crates/pink/tests/fixtures/event_size.wat rename to crates/pink/runner/tests/fixtures/event_size.wat diff --git a/crates/pink/tests/fixtures/flip/flip.contract b/crates/pink/runner/tests/fixtures/flip/flip.contract similarity index 100% rename from crates/pink/tests/fixtures/flip/flip.contract rename to crates/pink/runner/tests/fixtures/flip/flip.contract diff --git a/crates/pink/tests/fixtures/flip/flip.wasm b/crates/pink/runner/tests/fixtures/flip/flip.wasm similarity index 100% rename from crates/pink/tests/fixtures/flip/flip.wasm rename to crates/pink/runner/tests/fixtures/flip/flip.wasm diff --git a/crates/pink/tests/fixtures/flip/metadata.json b/crates/pink/runner/tests/fixtures/flip/metadata.json similarity index 100% rename from crates/pink/tests/fixtures/flip/metadata.json rename to crates/pink/runner/tests/fixtures/flip/metadata.json diff --git a/crates/pink/tests/fixtures/hooks_test/hooks_test.contract b/crates/pink/runner/tests/fixtures/hooks_test/hooks_test.contract similarity index 100% rename from crates/pink/tests/fixtures/hooks_test/hooks_test.contract rename to crates/pink/runner/tests/fixtures/hooks_test/hooks_test.contract diff --git a/crates/pink/tests/fixtures/hooks_test/hooks_test.wasm b/crates/pink/runner/tests/fixtures/hooks_test/hooks_test.wasm similarity index 100% rename from crates/pink/tests/fixtures/hooks_test/hooks_test.wasm rename to crates/pink/runner/tests/fixtures/hooks_test/hooks_test.wasm diff --git a/crates/pink/tests/fixtures/hooks_test/metadata.json b/crates/pink/runner/tests/fixtures/hooks_test/metadata.json similarity index 100% rename from crates/pink/tests/fixtures/hooks_test/metadata.json rename to crates/pink/runner/tests/fixtures/hooks_test/metadata.json diff --git a/crates/pink/tests/fixtures/logging.wasm b/crates/pink/runner/tests/fixtures/logging.wasm similarity index 100% rename from crates/pink/tests/fixtures/logging.wasm rename to crates/pink/runner/tests/fixtures/logging.wasm diff --git a/crates/pink/tests/fixtures/mqproxy/metadata.json b/crates/pink/runner/tests/fixtures/mqproxy/metadata.json similarity index 100% rename from crates/pink/tests/fixtures/mqproxy/metadata.json rename to crates/pink/runner/tests/fixtures/mqproxy/metadata.json diff --git a/crates/pink/tests/fixtures/mqproxy/mqproxy.contract b/crates/pink/runner/tests/fixtures/mqproxy/mqproxy.contract similarity index 100% rename from crates/pink/tests/fixtures/mqproxy/mqproxy.contract rename to crates/pink/runner/tests/fixtures/mqproxy/mqproxy.contract diff --git a/crates/pink/tests/fixtures/mqproxy/mqproxy.wasm b/crates/pink/runner/tests/fixtures/mqproxy/mqproxy.wasm similarity index 100% rename from crates/pink/tests/fixtures/mqproxy/mqproxy.wasm rename to crates/pink/runner/tests/fixtures/mqproxy/mqproxy.wasm diff --git a/crates/pink/tests/fixtures/signing/metadata.json b/crates/pink/runner/tests/fixtures/signing/metadata.json similarity index 100% rename from crates/pink/tests/fixtures/signing/metadata.json rename to crates/pink/runner/tests/fixtures/signing/metadata.json diff --git a/crates/pink/tests/fixtures/signing/signing.contract b/crates/pink/runner/tests/fixtures/signing/signing.contract similarity index 100% rename from crates/pink/tests/fixtures/signing/signing.contract rename to crates/pink/runner/tests/fixtures/signing/signing.contract diff --git a/crates/pink/tests/fixtures/signing/signing.wasm b/crates/pink/runner/tests/fixtures/signing/signing.wasm similarity index 100% rename from crates/pink/tests/fixtures/signing/signing.wasm rename to crates/pink/runner/tests/fixtures/signing/signing.wasm diff --git a/crates/pink/tests/fixtures/use_cache/metadata.json b/crates/pink/runner/tests/fixtures/use_cache/metadata.json similarity index 100% rename from crates/pink/tests/fixtures/use_cache/metadata.json rename to crates/pink/runner/tests/fixtures/use_cache/metadata.json diff --git a/crates/pink/tests/fixtures/use_cache/use_cache.wasm b/crates/pink/runner/tests/fixtures/use_cache/use_cache.wasm similarity index 100% rename from crates/pink/tests/fixtures/use_cache/use_cache.wasm rename to crates/pink/runner/tests/fixtures/use_cache/use_cache.wasm diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate-2.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate-2.snap new file mode 100644 index 0000000000..20a889874e --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate-2.snap @@ -0,0 +1,21 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +assertion_line: 121 +expression: cluster.effects.take() +--- +Some( + V1 { + pink_events: [], + ink_events: [], + instantiated: [ + ( + 056a8ab55cc7f7405e121302a0af5b46d8c5fd78d2dbc8c2ac994802bdfb71dc (5CBokECH...), + 21987f6137bade4149694c00329d55d598d109be0b22535758528d14fc12b4e9 (5Cpkjnu5...), + ), + ( + 0101010101010101010101010101010101010101010101010101010101010101 (5C62Ck4U...), + 056a8ab55cc7f7405e121302a0af5b46d8c5fd78d2dbc8c2ac994802bdfb71dc (5CBokECH...), + ), + ], + }, +) diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate.snap new file mode 100644 index 0000000000..404fd51de9 --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate.snap @@ -0,0 +1,28 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +assertion_line: 124 +expression: result +--- +ContractResult { + gas_consumed: Weight { + ref_time: 2106925205, + proof_size: 36732, + }, + gas_required: Weight { + ref_time: 97203631081, + proof_size: 2105952, + }, + storage_deposit: StorageDeposit::Charge( + 2, + ), + debug_message: [], + result: Ok( + InstantiateReturnValue { + result: ExecReturnValue { + flags: (empty), + data: [], + }, + account_id: 056a8ab55cc7f7405e121302a0af5b46d8c5fd78d2dbc8c2ac994802bdfb71dc (5CBokECH...), + }, + ), +} diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instantiate-2.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instantiate-2.snap new file mode 100644 index 0000000000..311f4c902d --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instantiate-2.snap @@ -0,0 +1,20 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +expression: cluster.effects.take() +--- +Some( + V1 { + pink_events: [], + ink_events: [], + instantiated: [ + ( + 056a8ab55cc7f7405e121302a0af5b46d8c5fd78d2dbc8c2ac994802bdfb71dc (5CBokECH...), + 21987f6137bade4149694c00329d55d598d109be0b22535758528d14fc12b4e9 (5Cpkjnu5...), + ), + ( + 0101010101010101010101010101010101010101010101010101010101010101 (5C62Ck4U...), + 056a8ab55cc7f7405e121302a0af5b46d8c5fd78d2dbc8c2ac994802bdfb71dc (5CBokECH...), + ), + ], + }, +) diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instantiate.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instantiate.snap new file mode 100644 index 0000000000..bfa3df9c28 --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_cross_contract_instantiate.snap @@ -0,0 +1,27 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +expression: result +--- +ContractResult { + gas_consumed: Weight { + ref_time: 1670460672, + proof_size: 201180, + }, + gas_required: Weight { + ref_time: 66475808693, + proof_size: 10546826, + }, + storage_deposit: StorageDeposit::Charge( + 4, + ), + debug_message: [], + result: Ok( + InstantiateReturnValue { + result: ExecReturnValue { + flags: (empty), + data: [], + }, + account_id: 056a8ab55cc7f7405e121302a0af5b46d8c5fd78d2dbc8c2ac994802bdfb71dc (5CBokECH...), + }, + ), +} diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip-2.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip-2.snap new file mode 100644 index 0000000000..737cb19124 --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip-2.snap @@ -0,0 +1,17 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +assertion_line: 60 +expression: cluster.effects.take() +--- +Some( + V1 { + pink_events: [], + ink_events: [], + instantiated: [ + ( + 0101010101010101010101010101010101010101010101010101010101010101 (5C62Ck4U...), + 35db55bc9f81c9b14ae536cc43c37786f3ff62fe5247a4dccfd7ba3c8bf316af (5DHKYvFE...), + ), + ], + }, +) diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip-3.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip-3.snap new file mode 100644 index 0000000000..6ae6180e00 --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip-3.snap @@ -0,0 +1,26 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +expression: result +--- +ContractResult { + gas_consumed: Weight { + ref_time: 1345245023, + proof_size: 27932, + }, + gas_required: Weight { + ref_time: 96468992000, + proof_size: 2097152, + }, + storage_deposit: StorageDeposit::Charge( + 0, + ), + debug_message: [], + result: Ok( + ExecReturnValue { + flags: (empty), + data: [ + 1, + ], + }, + ), +} diff --git a/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip.snap b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip.snap new file mode 100644 index 0000000000..7d51a35512 --- /dev/null +++ b/crates/pink/runner/tests/snapshots/test_pink_contract__ink_flip.snap @@ -0,0 +1,27 @@ +--- +source: crates/pink/runner/tests/test_pink_contract.rs +expression: result +--- +ContractResult { + gas_consumed: Weight { + ref_time: 897860439, + proof_size: 139822, + }, + gas_required: Weight { + ref_time: 65728937984, + proof_size: 10485760, + }, + storage_deposit: StorageDeposit::Charge( + 2, + ), + debug_message: [], + result: Ok( + InstantiateReturnValue { + result: ExecReturnValue { + flags: (empty), + data: [], + }, + account_id: 35db55bc9f81c9b14ae536cc43c37786f3ff62fe5247a4dccfd7ba3c8bf316af (5DHKYvFE...), + }, + ), +} diff --git a/crates/pink/runner/tests/test_pink_contract.rs b/crates/pink/runner/tests/test_pink_contract.rs new file mode 100644 index 0000000000..3ed4d37651 --- /dev/null +++ b/crates/pink/runner/tests/test_pink_contract.rs @@ -0,0 +1,498 @@ +use assert_matches::assert_matches; +use phala_crypto::sr25519::Persistence; +use pink_capi::v1::ecall::{ECalls, TransactionArguments}; +use pink_runner::{ + local_cache, + types::{AccountId, Balance, ExecutionMode, Weight}, +}; +use sp_runtime::{app_crypto::sr25519, AccountId32}; + +use test_cluster::TestCluster; + +pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); +pub const ENOUGH: Balance = u128::MAX / 2; + +fn tx_args() -> TransactionArguments { + TransactionArguments { + origin: ALICE.clone(), + transfer: 0, + gas_limit: Weight::MAX, + gas_free: true, + storage_deposit_limit: None, + } +} + +fn alice() -> AccountId { + ALICE.clone() +} + +#[test] +fn test_ink_flip() { + let mut cluster = TestCluster::for_test(); + + let code_hash = cluster + .upload_code( + alice(), + include_bytes!("./fixtures/flip/flip.wasm").to_vec(), + true, + ) + .unwrap(); + + let result = cluster.instantiate( + code_hash, + 0x9bae9d5e, + true, + vec![], + cluster.mode(), + tx_args(), + ); + + insta::assert_debug_snapshot!(result); + insta::assert_debug_snapshot!(cluster.effects.take()); + let contract = result.result.unwrap().account_id; + + let result = cluster.call_typed::<_, bool>( + &contract, + 0x2f865bd9, // get + (), + cluster.mode(), + tx_args(), + ); + assert_matches!(result, Ok(true)); + + let result = cluster.call_typed::<_, ()>( + &contract, + 0x633aa551, // flip + (), + cluster.mode(), + tx_args(), + ); + assert_matches!(result, Ok(())); + + let result = cluster.call_typed::<_, bool>( + &contract, + 0x2f865bd9, // get + (), + cluster.mode(), + tx_args(), + ); + assert_matches!(result, Ok(false)); + + let result = cluster.call_typed::<_, (u32, u128)>( + &contract, + 0xf7dff04c, // echo + (42u32, 24u128), + cluster.mode(), + tx_args(), + ); + assert_matches!(result, Ok((42, 24))); +} + +#[test] +fn test_ink_cross_contract_instantiate() { + let mut cluster = TestCluster::for_test(); + + let _code_hash = cluster + .upload_code( + alice(), + include_bytes!("./fixtures/flip/flip.wasm").to_vec(), + true, + ) + .unwrap(); + + let code_hash = cluster + .upload_code( + alice(), + include_bytes!("./fixtures/cross/cross.wasm").to_vec(), + true, + ) + .unwrap(); + + let mut args = tx_args(); + args.transfer = ENOUGH / 100; + let result = cluster.instantiate(code_hash, 0x9bae9d5e, true, vec![], cluster.mode(), args); + insta::assert_debug_snapshot!(result); + insta::assert_debug_snapshot!(cluster.effects.take()); + let contract = result.result.unwrap().account_id; + + let result = cluster.call_typed::<_, bool>( + &contract, + 0xc3220014, // get + (), + cluster.mode(), + tx_args(), + ); + assert_matches!(result, Ok(true)); +} + +fn generate_key() -> [u8; 64] { + let key = sr25519::Pair::restore_from_seed(&[42; 32]); + key.dump_secret_key() +} + +fn test_with_wasm(wasm: &[u8], constructor: u32, message: u32, query: bool) { + let mut cluster = TestCluster::for_test(); + cluster.set_key(generate_key()); + if query { + cluster.context.mode = ExecutionMode::Query; + } + + let code_hash = cluster.upload_code(alice(), wasm.to_vec(), true).unwrap(); + + let contract = cluster + .instantiate_typed( + code_hash, + constructor, + (), + vec![], + cluster.mode(), + tx_args(), + ) + .expect("Failed to instantiate contract"); + + local_cache::apply_quotas([(contract.as_ref(), 1024)]); + + let result = cluster.call_typed::<_, ()>(&contract, message, (), cluster.mode(), tx_args()); + assert_matches!(result, Ok(())); +} + +#[test] +fn test_signing() { + test_with_wasm( + include_bytes!("./fixtures/signing/signing.wasm"), + 0xed4b9d1b, + 0x928b2036, + true, + ); +} + +#[test] +fn test_logging() { + env_logger::init(); + test_with_wasm( + include_bytes!("./fixtures/logging.wasm"), + 0xed4b9d1b, + 0x928b2036, + false, + ); +} + +#[test] +fn test_use_cache() { + test_with_wasm( + include_bytes!("./fixtures/use_cache/use_cache.wasm"), + 0xed4b9d1b, + 0x928b2036, + true, + ); +} + +#[test] +#[ignore = "for dev"] +fn test_qjs() { + use scale::{Decode, Encode}; + + env_logger::init(); + + let mut cluster = TestCluster::for_test(); + cluster.set_key(generate_key()); + + let checker = []; + let qjs = []; + // let checker = include_bytes!("../../../../e2e/res/check_system/target/ink/check_system.wasm"); + // let qjs = include_bytes!("qjs.wasm"); + + #[derive(Debug, Encode, Decode)] + pub enum Output { + String(String), + Bytes(Vec), + Undefined, + } + + let checker_hash = cluster + .upload_code(alice(), checker.to_vec(), true) + .unwrap(); + let qjs_hash = cluster.upload_code(alice(), qjs.to_vec(), false).unwrap(); + + let contract = cluster + .instantiate_typed( + checker_hash, + 0xed4b9d1b, + (), + vec![], + cluster.mode(), + tx_args(), + ) + .expect("Failed to instantiate contract"); + + local_cache::apply_quotas([(contract.as_ref(), 1024)]); + + let js = r#" + (function(){ + console.log("Hello, World!"); + // return scriptArgs[1]; + return new Uint8Array([21, 31]); + })() + "#; + let t0 = std::time::Instant::now(); + let args: Vec = vec!["Hello".to_string(), "World".to_string()]; + cluster.context.mode = ExecutionMode::Query; + type LangError = (); + let result = cluster + .call_typed::<_, Result, LangError>>( + &contract, + 0xf32e54c5, + (qjs_hash, js, args), + cluster.mode(), + tx_args(), + ) + .expect("Failed to call contract"); + println!("evaluate result={result:?}, dt={:?}", t0.elapsed()); +} + +mod test_cluster { + use pink_capi::v1::{ + ecall::ECalls, + ocall::{ExecContext, HttpRequest, HttpRequestError, HttpResponse, OCalls, StorageChanges}, + CrossCall, CrossCallMut, ECall, + }; + use pink_runner::{ + local_cache::{self, StorageQuotaExceeded}, + runtimes::v1::{using_ocalls, Runtime}, + storage::ClusterStorage, + types::{AccountId, Balance, ExecSideEffects, ExecutionMode, Hash, TransactionArguments}, + }; + use scale::{Decode, Encode}; + use sp_runtime::DispatchError; + + use crate::ENOUGH; + + use super::ALICE; + + pub type ContractExecResult = pallet_contracts_primitives::ContractExecResult; + pub type ContractInstantiateResult = + pallet_contracts_primitives::ContractInstantiateResult; + + pub struct TestCluster { + pub storage: ClusterStorage, + pub context: ExecContext, + pub worker_pubkey: [u8; 32], + pub runtime: Runtime, + pub(crate) effects: Option, + } + + impl Clone for TestCluster { + fn clone(&self) -> Self { + Self { + storage: self.storage.clone(), + context: self.context.clone(), + runtime: unsafe { self.runtime.dup() }, + worker_pubkey: self.worker_pubkey, + effects: None, + } + } + } + + impl TestCluster { + pub fn for_test() -> Self { + let storage = ClusterStorage::default(); + let context = ExecContext { + mode: ExecutionMode::Transaction, + block_number: 1, + now_ms: 1, + }; + let runtime = Runtime::from_fn( + pink::capi::__pink_runtime_init, + std::ptr::null_mut(), + (1, 0), + ); + let mut me = Self { + storage, + context, + runtime, + effects: None, + worker_pubkey: [1; 32], + }; + me.deposit(ALICE.clone(), ENOUGH); + me + } + } + + impl TestCluster { + pub fn mode(&self) -> ExecutionMode { + self.context.mode + } + + fn execute_mut(&mut self, f: impl FnOnce() -> T) -> T { + using_ocalls(self, f) + } + + fn execute(&self, f: impl FnOnce() -> T) -> T { + let mut tmp = self.clone(); + using_ocalls(&mut tmp, f) + } + + pub fn instantiate( + &mut self, + code_hash: Hash, + selector: u32, + input: I, + salt: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> ContractInstantiateResult { + let input_data = Encode::encode(&(selector.to_be_bytes(), input)); + let result = self.contract_instantiate(code_hash, input_data, salt, mode, tx_args); + Decode::decode(&mut &result[..]).unwrap() + } + + pub fn instantiate_typed( + &mut self, + code_hash: Hash, + selector: u32, + input: I, + salt: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> Result { + let result = self.instantiate(code_hash, selector, input, salt, mode, tx_args); + match result.result { + Ok(ret) => { + if ret.result.did_revert() { + Err(DispatchError::Other("Contract instantiation reverted")) + } else { + Ok(ret.account_id) + } + } + Err(err) => Err(err), + } + } + + pub fn call( + &mut self, + contract: &AccountId, + selector: u32, + input: I, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> ContractExecResult { + let input_data = Encode::encode(&(selector.to_be_bytes(), input)); + let result = self.contract_call(contract.clone(), input_data, mode, tx_args); + Decode::decode(&mut &result[..]).unwrap() + } + + pub fn call_typed( + &mut self, + contract: &AccountId, + selector: u32, + input: I, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> Result { + let result = self.call(contract, selector, input, mode, tx_args); + match result.result { + Ok(ret) => { + if ret.did_revert() { + Err(DispatchError::Other("Contract reverted")) + } else { + Decode::decode(&mut &ret.data[..]).map_err(|_| { + DispatchError::Other("Failed to decode contract return value") + }) + } + } + Err(e) => Err(e), + } + } + } + + impl OCalls for TestCluster { + fn storage_root(&self) -> Option { + self.storage.root() + } + + fn storage_get(&self, key: Vec) -> Option> { + self.storage.get(&key).map(|(_rc, val)| val.clone()) + } + + fn storage_commit(&mut self, root: Hash, changes: StorageChanges) { + self.storage.commit(root, changes); + } + + fn log_to_server(&self, contract: AccountId, level: u8, message: String) { + log::log!( + match level { + 0 => log::Level::Error, + 1 => log::Level::Warn, + 2 => log::Level::Info, + 3 => log::Level::Debug, + 4 => log::Level::Trace, + _ => log::Level::Info, + }, + "log_server: contract={:?}, message={}", + contract, + message + ) + } + + fn emit_side_effects(&mut self, effects: ExecSideEffects) { + self.effects = Some(effects) + } + + fn exec_context(&self) -> ExecContext { + self.context.clone() + } + + fn worker_pubkey(&self) -> [u8; 32] { + self.worker_pubkey + } + + fn cache_get(&self, contract: Vec, key: Vec) -> Option> { + local_cache::get(&contract, &key) + } + + fn cache_set( + &self, + contract: Vec, + key: Vec, + value: Vec, + ) -> Result<(), StorageQuotaExceeded> { + local_cache::set(&contract, &key, &value) + } + + fn cache_set_expiration(&self, contract: Vec, key: Vec, expiration: u64) { + local_cache::set_expiration(&contract, &key, expiration) + } + + fn cache_remove(&self, contract: Vec, key: Vec) -> Option> { + local_cache::remove(&contract, &key) + } + + fn latest_system_code(&self) -> Vec { + vec![] + } + + fn http_request( + &self, + _contract: AccountId, + request: HttpRequest, + ) -> Result { + pink_extension_runtime::http_request(request, 10 * 1000) + } + } + + impl CrossCall for TestCluster { + fn cross_call(&self, call_id: u32, data: &[u8]) -> Vec { + self.execute(move || self.runtime.ecall(call_id, data)) + } + } + + impl CrossCallMut for TestCluster { + fn cross_call_mut(&mut self, call_id: u32, data: &[u8]) -> Vec { + let runtime = unsafe { self.runtime.dup() }; + self.execute_mut(move || runtime.ecall(call_id, data)) + } + } + + impl ECall for TestCluster {} +} diff --git a/crates/pink/Cargo.toml b/crates/pink/runtime/Cargo.toml similarity index 68% rename from crates/pink/Cargo.toml rename to crates/pink/runtime/Cargo.toml index e2a85902a3..cf7423a2c2 100644 --- a/crates/pink/Cargo.toml +++ b/crates/pink/runtime/Cargo.toml @@ -1,8 +1,11 @@ [package] name = "pink" -version = "0.1.0" +version = "1.0.0" edition = "2021" +[lib] +crate-type = ["lib", "cdylib"] + [dependencies] sha2 = "0.10.2" log = "0.4.14" @@ -24,8 +27,8 @@ sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = " sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -scale = { package = "parity-scale-codec", version = "3.3", default-features = false, features = ["derive"] } -scale-info = { version = "2.3", default-features = false, features = ["derive", "serde", "decode"] } +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive", "serde", "decode"] } parity-wasm = { version = "0.45.0", default-features = false } wasmi-validation = { version = "0.5.0", default-features = false } @@ -36,18 +39,27 @@ impl-serde = "0.4.0" hex = "0.4.3" serde = { version = "1.0.101", features = ["derive"] } serde_json = "1.0.67" -phala-serde-more = { path = "../phala-serde-more" } - -phala-trie-storage = { path = "../phala-trie-storage" } -phala-types = { path = "../phala-types" } -phala-crypto = { path = "../phala-crypto" } -pink-extension = { path = "pink-extension" } -pink-extension-runtime = { path = "pink-extension-runtime" } -reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "socks", "blocking"] } -reqwest-env-proxy = { path = "../reqwest-env-proxy" } +phala-serde-more = { path = "../../phala-serde-more" } + +phala-trie-storage = { path = "../../phala-trie-storage" } +phala-types = { path = "../../phala-types" } +phala-crypto = { path = "../../phala-crypto" } +pink-extension = { path = "../pink-extension" } +pink-extension-runtime = { path = "../pink-extension-runtime" } +pink-capi = { path = "../capi" } +reqwest = { version = "0.11", default-features = false, features = [ + "rustls-tls", + "socks", + "blocking", +] } +reqwest-env-proxy = { path = "../../reqwest-env-proxy" } environmental = "1.1.3" +phala-sanitized-logger = { path = "../../phala-sanitized-logger" } +hash-db = "0.15" +anyhow = "1" +phala-git-revision = { path = "../../phala-git-revision" } +subxt = { path = "../../../subxt/subxt" } [dev-dependencies] insta = "1.7.2" hex-literal = "0.3.3" -env_logger = "0.9.0" diff --git a/crates/pink/runtime/src/capi/ecall_impl.rs b/crates/pink/runtime/src/capi/ecall_impl.rs new file mode 100644 index 0000000000..b0bcb11d2a --- /dev/null +++ b/crates/pink/runtime/src/capi/ecall_impl.rs @@ -0,0 +1,245 @@ +use frame_support::traits::Currency; +use log::info; +use pallet_contracts::{AddressGenerator, Determinism}; +use phala_crypto::sr25519::Sr25519SecretKey; +use pink_capi::{ + types::{AccountId, Balance, ExecutionMode, Hash, Weight}, + v1::{ + ecall::{self, ClusterSetupConfig, TransactionArguments}, + ocall::OCalls, + Executing, + }, +}; +use scale::Encode; + +use crate::{ + contract::check_instantiate_result, + runtime::{Balances as PalletBalances, Contracts as PalletContracts, Pink as PalletPink}, +}; + +use super::OCallImpl; + +pub struct ECallImpl; + +pub(crate) fn storage() -> crate::storage::ExternalStorage { + crate::storage::ExternalStorage::instantiate() +} + +impl Executing for crate::storage::ExternalStorage { + fn execute(&self, f: impl FnOnce() -> T) -> T { + let context = OCallImpl.exec_context(); + let (rv, _effects, _) = self.execute_with(&context, f); + rv + } + + fn execute_mut(&mut self, f: impl FnOnce() -> T) -> T { + let context = OCallImpl.exec_context(); + let (rv, effects) = self.execute_mut(&context, f); + OCallImpl.emit_side_effects(effects); + rv + } +} + +impl ecall::ECalls for ECallImpl { + fn cluster_id(&self) -> Hash { + PalletPink::cluster_id() + } + fn setup(&mut self, config: ClusterSetupConfig) -> Result<(), String> { + let ClusterSetupConfig { + cluster_id, + owner, + deposit, + gas_price, + deposit_per_item, + deposit_per_byte, + treasury_account, + system_code, + } = config; + PalletPink::set_cluster_id(cluster_id); + PalletPink::set_gas_price(gas_price); + PalletPink::set_deposit_per_item(deposit_per_item); + PalletPink::set_deposit_per_byte(deposit_per_byte); + PalletPink::set_treasury_account(&treasury_account); + + self.deposit(owner.clone(), deposit); + let code_hash = self + .upload_code(owner.clone(), system_code, true) + .or(Err("FailedToUploadResourceToCluster"))?; + info!("Worker: pink system code hash {:?}", code_hash); + let selector = vec![0xed, 0x4b, 0x9d, 0x1b]; // The default() constructor + let args = TransactionArguments { + origin: owner, + transfer: 0, + gas_limit: Weight::MAX, + gas_free: true, + storage_deposit_limit: None, + }; + let result = crate::contract::instantiate( + code_hash, + selector, + vec![], + ExecutionMode::Transaction, + args, + ); + let address = match check_instantiate_result(&result) { + Err(err) => { + info!("Worker: failed to deploy system contract: {:?}", err); + return Err("FailedToDeploySystemContract".into()); + } + Ok(address) => address, + }; + PalletPink::set_system_contract(&address); + info!( + "Cluster deployed, id={:?}, system={:?}", + cluster_id, address + ); + Ok(()) + } + + fn deposit(&mut self, who: AccountId, value: Balance) { + let _ = PalletBalances::deposit_creating(&who, value); + } + + fn set_key(&mut self, key: Sr25519SecretKey) { + PalletPink::set_key(key); + } + + fn get_key(&self) -> Option { + PalletPink::key() + } + + fn upload_code( + &mut self, + account: AccountId, + code: Vec, + deterministic: bool, + ) -> Result { + crate::runtime::Contracts::bare_upload_code( + account, + code, + None, + if deterministic { + Determinism::Deterministic + } else { + Determinism::AllowIndeterminism + }, + ) + .map(|v| v.code_hash) + .map_err(|err| format!("{err:?}")) + } + + fn upload_sidevm_code(&mut self, account: AccountId, code: Vec) -> Result { + PalletPink::put_sidevm_code(account, code).map_err(|err| format!("{err:?}")) + } + + fn get_sidevm_code(&self, hash: Hash) -> Option> { + PalletPink::sidevm_codes(&hash).map(|v| v.code) + } + + fn system_contract(&self) -> Option { + PalletPink::system_contract() + } + + fn free_balance(&self, account: AccountId) -> Balance { + PalletBalances::free_balance(&account) + } + + fn total_balance(&self, account: AccountId) -> Balance { + PalletBalances::total_balance(&account) + } + + fn code_hash(&self, account: AccountId) -> Option { + PalletContracts::code_hash(&account) + } + + fn contract_instantiate( + &mut self, + code_hash: Hash, + input_data: Vec, + salt: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> Vec { + let address = PalletPink::contract_address(&tx_args.origin, &code_hash, &input_data, &salt); + let result = crate::contract::instantiate(code_hash, input_data, salt, mode, tx_args); + if !result.debug_message.is_empty() { + let message = String::from_utf8_lossy(&result.debug_message).into_owned(); + OCallImpl.log_to_server( + address.clone(), + log::Level::Debug as usize as _, + message.clone(), + ); + log::debug!("[{address:?}][{mode:?}] debug_message: {message:?}"); + } + match &result.result { + Err(err) => { + log::error!("[{address:?}][{mode:?}] instantiate error: {err:?}"); + OCallImpl.log_to_server( + address, + log::Level::Error as usize as _, + format!("instantiate failed: {err:?}"), + ); + } + Ok(ret) if ret.result.did_revert() => { + log::error!("[{address:?}][{mode:?}] instantiate reverted"); + OCallImpl.log_to_server( + address, + log::Level::Error as usize as _, + "instantiate reverted".into(), + ); + } + Ok(_) => { + log::info!("[{address:?}][{mode:?}] instantiated"); + OCallImpl.log_to_server( + address, + log::Level::Info as usize as _, + "instantiated".to_owned(), + ); + } + } + result.encode() + } + + fn contract_call( + &mut self, + address: AccountId, + input_data: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, + ) -> Vec { + let result = crate::contract::bare_call(address.clone(), input_data, mode, tx_args); + if !result.debug_message.is_empty() { + let message = String::from_utf8_lossy(&result.debug_message).into_owned(); + OCallImpl.log_to_server( + address.clone(), + log::Level::Debug as usize as _, + message.clone(), + ); + log::debug!("[{address:?}][{mode:?}] debug_message: {:?}", message); + } + match &result.result { + Err(err) => { + log::error!("[{address:?}][{mode:?}] command exec error: {:?}", err); + OCallImpl.log_to_server( + address, + log::Level::Error as usize as _, + format!("contract call failed: {err:?}"), + ); + } + Ok(ret) if ret.did_revert() => { + log::error!("[{address:?}][{mode:?}] contract reverted: {:?}", ret); + OCallImpl.log_to_server( + address, + log::Level::Error as usize as _, + "contract call reverted".into(), + ); + } + Ok(_) => {} + } + result.encode() + } + + fn git_revision(&self) -> String { + phala_git_revision::git_revision().to_string() + } +} diff --git a/crates/pink/runtime/src/capi/mod.rs b/crates/pink/runtime/src/capi/mod.rs new file mode 100644 index 0000000000..e1c1be4cb4 --- /dev/null +++ b/crates/pink/runtime/src/capi/mod.rs @@ -0,0 +1,66 @@ +use pink_capi::v1; +use v1::*; + +use phala_sanitized_logger as logger; + +pub(crate) use ocall_impl::OCallImpl; + +const _: init_t = Some(__pink_runtime_init); + +/// This is the entry point of the runtime. It will initialize the runtime and +/// fill the ecalls table. +/// +/// # Safety +/// +/// Make sure pointers are valid. +#[no_mangle] +pub unsafe extern "C" fn __pink_runtime_init( + config: *const config_t, + ecalls: *mut ecalls_t, +) -> ::core::ffi::c_int { + let config = unsafe { &*config }; + if let Err(err) = ocall_impl::set_ocall_fn(config.ocalls) { + log::error!("Failed to init runtime: {err}"); + return -1; + } + if ecalls.is_null() { + log::error!("Failed to init runtime: ecalls is null"); + return -1; + } + unsafe { + (*ecalls).ecall = Some(ecall); + (*ecalls).get_version = Some(get_version); + } + if config.is_dylib != 0 { + logger::init(config.enclaved != 0); + } + 0 +} + +unsafe extern "C" fn get_version(major: *mut u32, minor: *mut u32) { + let ver = crate::version(); + *major = ver.0; + *minor = ver.1; +} + +unsafe extern "C" fn ecall( + call_id: u32, + data: *const u8, + len: usize, + ctx: *mut ::core::ffi::c_void, + output_fn: output_fn_t, +) { + let input = unsafe { std::slice::from_raw_parts(data, len) }; + let output = ecall::dispatch( + &mut ecall_impl::storage(), + &mut ecall_impl::ECallImpl, + call_id, + input, + ); + if let Some(output_fn) = output_fn { + unsafe { output_fn(ctx, output.as_ptr(), output.len()) }; + } +} + +mod ecall_impl; +mod ocall_impl; diff --git a/crates/pink/runtime/src/capi/ocall_impl.rs b/crates/pink/runtime/src/capi/ocall_impl.rs new file mode 100644 index 0000000000..02d6455d9c --- /dev/null +++ b/crates/pink/runtime/src/capi/ocall_impl.rs @@ -0,0 +1,95 @@ +use pink_capi::{ + helper::InnerType, + v1::{cross_call_fn_t, ocalls_t, output_fn_t, CrossCall, CrossCallMut, OCall}, +}; + +static mut OCALL: InnerType = _default_ocall; + +unsafe extern "C" fn _default_ocall( + _call_id: u32, + _data: *const u8, + _len: usize, + _ctx: *mut ::core::ffi::c_void, + _output: output_fn_t, +) { + panic!("No ocall function provided"); +} + +pub(super) fn set_ocall_fn(ocalls: ocalls_t) -> Result<(), &'static str> { + let Some(ocall) = ocalls.ocall else { + return Err("No ocall function provided"); + }; + unsafe { + OCALL = ocall; + if let Some(alloc) = ocalls.alloc { + allocator::ALLOC_FUNC = alloc; + } + if let Some(dealloc) = ocalls.dealloc { + allocator::DEALLOC_FUNC = dealloc; + } + } + Ok(()) +} + +pub(crate) struct OCallImpl; +impl CrossCallMut for OCallImpl { + fn cross_call_mut(&mut self, call_id: u32, data: &[u8]) -> Vec { + self.cross_call(call_id, data) + } +} +impl CrossCall for OCallImpl { + fn cross_call(&self, id: u32, data: &[u8]) -> Vec { + unsafe extern "C" fn output_fn(ctx: *mut ::core::ffi::c_void, data: *const u8, len: usize) { + let output = &mut *(ctx as *mut Vec); + output.extend_from_slice(std::slice::from_raw_parts(data, len)); + } + unsafe { + let mut output = Vec::new(); + let ctx = &mut output as *mut _ as *mut ::core::ffi::c_void; + OCALL(id, data.as_ptr(), data.len(), ctx, Some(output_fn)); + output + } + } +} +impl OCall for OCallImpl {} + +mod allocator { + //! # Rust memory allocator in dynamic runtimes + //! + //! By default, Rust std comes with a default allocator which uses the alloc + //! APIs from libc. As a result, every dynamic library written in Rust will + //! have its own allocator. This is not what we want because we have a common + //! allocator in the main executable which have some metrices and statistics. + //! If we use the default allocator, the statistics will be not accurate. + //! So we make this allocator in the runtime and delegate the calls to the + //! allocator in the main executable. + + use pink_capi::{helper::InnerType, v1}; + use std::alloc::{GlobalAlloc, Layout, System}; + + pub(super) static mut ALLOC_FUNC: InnerType = system_alloc; + pub(super) static mut DEALLOC_FUNC: InnerType = system_dealloc; + unsafe extern "C" fn system_alloc(size: usize, align: usize) -> *mut u8 { + // Safety: The layout is valid because it is always passed from the PinkAllocator below. + System.alloc(Layout::from_size_align(size, align).unwrap_unchecked()) + } + unsafe extern "C" fn system_dealloc(ptr: *mut u8, size: usize, align: usize) { + // Safety: The layout is valid because it is always passed from the PinkAllocator below. + System.dealloc(ptr, Layout::from_size_align(size, align).unwrap_unchecked()) + } + + struct PinkAllocator; + + #[global_allocator] + static ALLOCATOR: PinkAllocator = PinkAllocator; + + unsafe impl GlobalAlloc for PinkAllocator { + unsafe fn alloc(&self, layout: std::alloc::Layout) -> *mut u8 { + ALLOC_FUNC(layout.size(), layout.align()) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: std::alloc::Layout) { + DEALLOC_FUNC(ptr, layout.size(), layout.align()) + } + } +} diff --git a/crates/pink/runtime/src/contract.rs b/crates/pink/runtime/src/contract.rs new file mode 100644 index 0000000000..8da637c91e --- /dev/null +++ b/crates/pink/runtime/src/contract.rs @@ -0,0 +1,239 @@ +use frame_support::weights::Weight; +use pallet_contracts::Determinism; +use pallet_contracts_primitives::StorageDeposit; +use pink_capi::{types::ExecutionMode, v1::ecall::TransactionArguments}; +use sp_runtime::DispatchError; + +use crate::{ + runtime::{Contracts, Pink as PalletPink}, + types::{AccountId, Balance, Hash}, +}; +use anyhow::Result; + +type ContractExecResult = pallet_contracts_primitives::ContractExecResult; +type ContractInstantiateResult = + pallet_contracts_primitives::ContractInstantiateResult; +type ContractResult = + pallet_contracts_primitives::ContractResult, Balance>; + +macro_rules! define_mask_fn { + ($name: ident, $bits: expr, $typ: ty) => { + /// Mask given number's lowest bits. + /// + /// Given a number 0x1000beef, in binary representation: + /// 0b_10000_00000000_10111110_11101111 + /// We want to mask it to 0x100fffff. + /// Rough steps: + /// 0b_10000_00000000_10111110_11101111 + /// ^ + /// 1. we find the most left bit position here + /// 0b_10000_00000000_10111110_11101111 + /// ^^^^^^^^^^^^^^^^^^^^^^ + /// 2. than calculate these bits need to be mask + /// 0b_10000_00001111_11111111_11111111 + /// ^^^^^^^^^^^^^^^^^^^^^^ + /// 3. mask it + fn $name(v: $typ, min_mask_bits: u32) -> $typ { + // Given v = 0x1000_beef + // Suppose we have: + // bits = 64 + // v =0b010000_00000000_10111110_11101111 + let pos = $bits - v.leading_zeros(); + // 0b010000_00000000_10111110_11101111 + // ^ + // here, pos=30 + // shift right by 9 + let pos = pos.max(9) - 9; + // Now pos = 0b_10000_00000000_00000000 + // ^ + // now here, pos=21 + // If min_mask_bits = 16 + // 0b_10000000_00000000 + // ^ + // min_mask_bits here + let pos = pos.clamp(min_mask_bits, $bits - 1); + let cursor: $typ = 1 << pos; + // 0b_10000_00000000_00000000 + // ^ + // cursor here + let mask = cursor.saturating_sub(1); + // mask = 0b_00001111_11111111_11111111 + // v | mask = + // 0b10000_00001111_11111111_11111111 + // = 0x100fffff + v | mask + } + }; +} + +define_mask_fn!(mask_low_bits64, 64, u64); +define_mask_fn!(mask_low_bits128, 128, u128); + +fn mask_deposit(deposit: u128, deposit_per_byte: u128) -> u128 { + let min_mask_bits = 128 - (deposit_per_byte * 1024).leading_zeros(); + mask_low_bits128(deposit, min_mask_bits) +} + +fn mask_gas(weight: Weight) -> Weight { + Weight::from_ref_time(mask_low_bits64(weight.ref_time(), 28)) +} + +#[test] +fn mask_low_bits_works() { + let min_mask_bits = 24; + assert_eq!(mask_low_bits64(0, min_mask_bits), 0xffffff); + assert_eq!(mask_low_bits64(0x10, min_mask_bits), 0xffffff); + assert_eq!(mask_low_bits64(0x1000_0000, min_mask_bits), 0x10ff_ffff); + assert_eq!( + mask_low_bits64(0x10_0000_0000, min_mask_bits), + 0x10_0fff_ffff + ); + assert_eq!( + mask_low_bits64(0x10_0000_0000_0000, min_mask_bits), + 0x10_0fff_ffff_ffff + ); + assert_eq!( + mask_low_bits64(0xffff_ffff_0000_0000, min_mask_bits), + 0xffff_ffff_ffff_ffff + ); + + let price = 10; + assert_eq!(mask_deposit(0, price), 0x3fff); + assert_eq!(mask_deposit(0x10, price), 0x3fff); + assert_eq!(mask_deposit(0x10_0000, price), 0x10_3fff); + assert_eq!(mask_deposit(0x10_0000_0000, price), 0x10_0fff_ffff); + assert_eq!( + mask_deposit(0x10_0000_0000_0000, price), + 0x10_0fff_ffff_ffff + ); +} + +fn coarse_grained(mut result: ContractResult, deposit_per_byte: u128) -> ContractResult { + result.gas_consumed = mask_gas(result.gas_consumed); + result.gas_required = mask_gas(result.gas_required); + + match &mut result.storage_deposit { + StorageDeposit::Charge(v) => { + *v = mask_deposit(*v, deposit_per_byte); + } + StorageDeposit::Refund(v) => { + *v = mask_deposit(*v, deposit_per_byte); + } + } + result +} + +pub fn check_instantiate_result(result: &ContractInstantiateResult) -> Result { + let ret = result + .result + .as_ref() + .map_err(|err| anyhow::anyhow!("{err:?}"))?; + if ret.result.did_revert() { + anyhow::bail!("contract instantiation failed: {:?}", ret.result) + } + Ok(ret.account_id.clone()) +} + +pub fn instantiate( + code_hash: Hash, + input_data: Vec, + salt: Vec, + mode: ExecutionMode, + args: TransactionArguments, +) -> ContractInstantiateResult { + let TransactionArguments { + origin, + transfer, + gas_limit, + storage_deposit_limit, + gas_free, + } = args; + let gas_limit = Weight::from_ref_time(gas_limit).set_proof_size(u64::MAX); + let result = contract_tx(origin.clone(), gas_limit, gas_free, move || { + Contracts::bare_instantiate( + origin, + transfer, + gas_limit, + storage_deposit_limit, + pallet_contracts_primitives::Code::Existing(code_hash), + input_data, + salt, + true, + ) + }); + log::info!("Contract instantiation result: {:?}", &result.result); + if mode.should_return_coarse_gas() { + coarse_grained(result, PalletPink::deposit_per_byte()) + } else { + result + } +} + +/// Call a contract method +/// +/// # Parameters +/// * `input_data`: The SCALE encoded arguments including the 4-bytes selector as prefix. +/// # Return +/// Returns the SCALE encoded method return value. +pub fn bare_call( + address: AccountId, + input_data: Vec, + mode: ExecutionMode, + tx_args: TransactionArguments, +) -> ContractExecResult { + let TransactionArguments { + origin, + transfer, + gas_limit, + gas_free, + storage_deposit_limit, + } = tx_args; + let gas_limit = Weight::from_ref_time(gas_limit).set_proof_size(u64::MAX); + let determinism = if mode.deterministic_required() { + Determinism::Deterministic + } else { + Determinism::AllowIndeterminism + }; + let result = contract_tx(origin.clone(), gas_limit, gas_free, move || { + Contracts::bare_call( + origin, + address, + transfer, + gas_limit, + storage_deposit_limit, + input_data, + true, + determinism, + ) + }); + if mode.should_return_coarse_gas() { + coarse_grained(result, PalletPink::deposit_per_byte()) + } else { + result + } +} + +fn contract_tx( + origin: AccountId, + gas_limit: Weight, + gas_free: bool, + tx_fn: impl FnOnce() -> ContractResult, +) -> ContractResult { + if !gas_free && PalletPink::pay_for_gas(&origin, gas_limit).is_err() { + return ContractResult { + gas_consumed: Weight::zero(), + gas_required: Weight::zero(), + storage_deposit: Default::default(), + debug_message: Default::default(), + result: Err(DispatchError::Other("InsufficientBalance")), + }; + } + let result = tx_fn(); + if !gas_free { + let refund = gas_limit + .checked_sub(&result.gas_consumed) + .expect("BUG: consumed gas more than the gas limit"); + PalletPink::refund_gas(&origin, refund).expect("BUG: failed to refund gas"); + } + result +} diff --git a/crates/pink/src/export_fixtures.rs b/crates/pink/runtime/src/export_fixtures.rs similarity index 100% rename from crates/pink/src/export_fixtures.rs rename to crates/pink/runtime/src/export_fixtures.rs diff --git a/crates/pink/runtime/src/lib.rs b/crates/pink/runtime/src/lib.rs new file mode 100644 index 0000000000..a31fa380c8 --- /dev/null +++ b/crates/pink/runtime/src/lib.rs @@ -0,0 +1,27 @@ +extern crate alloc; + +pub mod capi; +mod contract; +mod runtime; +mod storage; +mod types; + +/// Returns a tuple containing the major and minor version numbers of the current crate. +/// +/// # Examples +/// +/// ``` +/// let (major, minor) = pink::version(); +/// println!("Current version: {}.{}", major, minor); +/// ``` +pub fn version() -> (u32, u32) { + let major = env!("CARGO_PKG_VERSION_MAJOR") + .parse() + .expect("Invalid major version"); + + let minor = env!("CARGO_PKG_VERSION_MINOR") + .parse() + .expect("Invalid minor version"); + + (major, minor) +} diff --git a/crates/pink/runtime/src/runtime.rs b/crates/pink/runtime/src/runtime.rs new file mode 100644 index 0000000000..8a9277c856 --- /dev/null +++ b/crates/pink/runtime/src/runtime.rs @@ -0,0 +1,166 @@ +mod extension; +mod pallet_pink; +mod weights; + +use crate::types::{AccountId, Balance, BlockNumber, Hash, Hashing, Index}; +use frame_support::{ + parameter_types, + traits::ConstBool, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, +}; +use pallet_contracts::{Config, Frame, Schedule}; +use sp_runtime::{generic::Header, traits::IdentityLookup, Perbill}; + +pub use extension::get_side_effects; +pub use pink_capi::types::ExecSideEffects; +pub use pink_extension::{EcdhPublicKey, HookPoint, Message, OspMessage, PinkEvent}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime! { + pub enum PinkRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Randomness: pallet_insecure_randomness_collective_flip, + Contracts: pallet_contracts, + Pink: pallet_pink, + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +parameter_types! { + pub const BlockHashCount: u32 = 250; + pub RuntimeBlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::with_sensible_defaults( + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + NORMAL_DISPATCH_RATIO, + ); + pub const ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_pink::Config for PinkRuntime { + type Currency = Balances; +} + +impl pallet_balances::Config for PinkRuntime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = frame_system::Pallet; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; +} + +impl frame_system::Config for PinkRuntime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = RuntimeBlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = Index; + type BlockNumber = BlockNumber; + type Hash = Hash; + type RuntimeCall = RuntimeCall; + type Hashing = Hashing; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_insecure_randomness_collective_flip::Config for PinkRuntime {} + +parameter_types! { + pub const MinimumPeriod: u64 = 1; +} + +impl pallet_timestamp::Config for PinkRuntime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +// Workaround for the test failure in runtime_integrity_tests +// https://github.com/paritytech/substrate/pull/12993/files#diff-67684005af418e25ff88c2ae5b520f0c040371f1d817e03a3652e76b9485224aR1217 +#[cfg(test)] +const MAX_CODE_NAME: u32 = 64 * 1024; +#[cfg(not(test))] +const MAX_CODE_NAME: u32 = 2 * 1024 * 1024; + +parameter_types! { + pub DepositPerStorageByte: Balance = Pink::deposit_per_byte(); + pub DepositPerStorageItem: Balance = Pink::deposit_per_item(); + pub const DeletionQueueDepth: u32 = 1024; + pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000); + pub const MaxCodeLen: u32 = MAX_CODE_NAME; + pub const MaxStorageKeyLen: u32 = 128; + pub const MaxDebugBufferLen: u32 = 128 * 1024; + + pub DefaultSchedule: Schedule = { + let mut schedule = Schedule::::default(); + const MB: u32 = 16; // 64KiB * 16 + // Each concurrent query would create a VM instance to serve it. We couldn't + // allocate too much here. + schedule.limits.memory_pages = 4 * MB; + schedule.instruction_weights.fallback = 8000; + schedule + }; +} + +impl Config for PinkRuntime { + type Time = Timestamp; + type Randomness = Randomness; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type CallFilter = frame_support::traits::Nothing; + type CallStack = [Frame; 5]; + type WeightPrice = Pink; + type WeightInfo = weights::PinkWeights; + type ChainExtension = extension::PinkExtension; + type DeletionQueueDepth = DeletionQueueDepth; + type DeletionWeightLimit = DeletionWeightLimit; + type Schedule = DefaultSchedule; + type DepositPerByte = DepositPerStorageByte; + type DepositPerItem = DepositPerStorageItem; + type AddressGenerator = Pink; + type MaxCodeLen = MaxCodeLen; + type MaxStorageKeyLen = MaxStorageKeyLen; + type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = MaxDebugBufferLen; +} + +#[test] +fn detect_parameter_changes() { + insta::assert_debug_snapshot!(( + ::BlockWeights::get(), + ::Schedule::get(), + ::DeletionQueueDepth::get(), + ::DeletionWeightLimit::get(), + ::MaxCodeLen::get(), + ::MaxStorageKeyLen::get(), + )); +} diff --git a/crates/pink/src/runtime/extension.rs b/crates/pink/runtime/src/runtime/extension.rs similarity index 77% rename from crates/pink/src/runtime/extension.rs rename to crates/pink/runtime/src/runtime/extension.rs index 83d9d6c4cb..1afa1872ba 100644 --- a/crates/pink/src/runtime/extension.rs +++ b/crates/pink/runtime/src/runtime/extension.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, time::Duration}; +use std::borrow::Cow; use frame_support::log::error; use frame_support::traits::Currency; @@ -13,32 +13,13 @@ use pink_extension::{ }, dispatch_ext_call, CacheOp, EcdhPublicKey, EcdsaPublicKey, EcdsaSignature, Hash, PinkEvent, }; -use pink_extension_runtime::{local_cache, DefaultPinkExtension, PinkRuntimeEnv}; +use pink_extension_runtime::{DefaultPinkExtension, PinkRuntimeEnv}; use scale::{Decode, Encode}; -use sp_core::H256; use sp_runtime::{AccountId32, DispatchError}; -use crate::{ - runtime::{get_call_elapsed, get_call_mode_info, CallMode}, - types::AccountId, -}; - -#[derive(Default, Debug)] -pub struct ExecSideEffects { - pub pink_events: Vec<(AccountId, PinkEvent)>, - pub ink_events: Vec<(AccountId, Vec, Vec)>, - pub instantiated: Vec<(AccountId, AccountId)>, -} +use crate::{capi::OCallImpl, types::AccountId}; -impl ExecSideEffects { - pub fn into_query_only_effects(mut self) -> Self { - self.pink_events - .retain(|(_, event)| event.allowed_in_query()); - self.ink_events.clear(); - self.instantiated.clear(); - self - } -} +use pink_capi::{types::ExecSideEffects, v1::ocall::OCallsRo}; fn deposit_pink_event(contract: AccountId, event: PinkEvent) { let topics = [pink_extension::PinkEvent::event_topic().into()]; @@ -50,7 +31,9 @@ fn deposit_pink_event(contract: AccountId, event: PinkEvent) { } pub fn get_side_effects() -> ExecSideEffects { - let mut result = ExecSideEffects::default(); + let mut pink_events = Vec::default(); + let mut ink_events = Vec::default(); + let mut instantiated = Vec::default(); for event in super::System::events() { if let super::RuntimeEvent::Contracts(ink_event) = event.event { use pallet_contracts::Event as ContractEvent; @@ -58,7 +41,7 @@ pub fn get_side_effects() -> ExecSideEffects { ContractEvent::Instantiated { deployer, contract: address, - } => result.instantiated.push((deployer, address)), + } => instantiated.push((deployer, address)), ContractEvent::ContractEmitted { contract: address, data, @@ -68,21 +51,25 @@ pub fn get_side_effects() -> ExecSideEffects { { match pink_extension::PinkEvent::decode(&mut &data[..]) { Ok(event) => { - result.pink_events.push((address, event)); + pink_events.push((address, event)); } Err(_) => { error!("Contract emitted an invalid pink event"); } } } else { - result.ink_events.push((address, event.topics, data)); + ink_events.push((address, event.topics, data)); } } _ => (), } } } - result + ExecSideEffects::V1 { + pink_events, + ink_events, + instantiated, + } } /// Contract extension for `pink contracts` @@ -103,18 +90,15 @@ impl ChainExtension for PinkExtension { } let address = env.ext().address().clone(); - let call_info = get_call_mode_info().expect("BUG: call ext out of runtime context"); - let call_in_query = CallInQuery { - address, - worker_pubkey: call_info.worker_pubkey, - }; - let result = if matches!(call_info.mode, CallMode::Command) { + let call_in_query = CallInQuery { address }; + let mode = OCallImpl.exec_context().mode; + let result = if mode.is_query() { + dispatch_ext_call!(env.func_id(), call_in_query, env) + } else { let call = CallInCommand { as_in_query: call_in_query, }; dispatch_ext_call!(env.func_id(), call, env) - } else { - dispatch_ext_call!(env.func_id(), call_in_query, env) }; let (ret, output) = match result { Some(output) => output, @@ -139,7 +123,6 @@ impl ChainExtension for PinkExtension { struct CallInQuery { address: AccountId, - worker_pubkey: EcdhPublicKey, } impl PinkRuntimeEnv for CallInQuery { @@ -148,10 +131,6 @@ impl PinkRuntimeEnv for CallInQuery { fn address(&self) -> &Self::AccountId { &self.address } - - fn call_elapsed(&self) -> Option { - get_call_elapsed() - } } impl CallInQuery { @@ -162,12 +141,18 @@ impl CallInQuery { } Ok(()) } + fn address_bytes(&self) -> Vec { + let slice: &[u8] = self.address.as_ref(); + slice.to_vec() + } } impl PinkExtBackend for CallInQuery { type Error = DispatchError; fn http_request(&self, request: HttpRequest) -> Result { - DefaultPinkExtension::new(self).http_request(request) + OCallImpl + .http_request(self.address.clone(), request) + .map_err(|err| DispatchError::Other(err.display())) } fn sign( @@ -190,11 +175,11 @@ impl PinkExtBackend for CallInQuery { } fn derive_sr25519_key(&self, salt: Cow<[u8]>) -> Result, Self::Error> { - let seed = - crate::runtime::Pink::key_seed().ok_or(DispatchError::Other("Key seed missing"))?; - let seed_key = sp_core::sr25519::Pair::restore_from_secret_key(&seed); + let privkey = + crate::runtime::Pink::key().ok_or(DispatchError::Other("Key seed missing"))?; + let privkey = sp_core::sr25519::Pair::restore_from_secret_key(&privkey); let contract_address: &[u8] = self.address.as_ref(); - let derived_pair = seed_key + let derived_pair = privkey .derive_sr25519_pair(&[contract_address, &salt, b"keygen"]) .or(Err(DispatchError::Other("Failed to derive sr25519 pair")))?; let priviate_key = derived_pair.dump_secret_key(); @@ -211,24 +196,24 @@ impl PinkExtBackend for CallInQuery { key: Cow<[u8]>, value: Cow<[u8]>, ) -> Result, Self::Error> { - Ok(local_cache::set(self.address.as_ref(), &key, &value)) + Ok(OCallImpl.cache_set(self.address_bytes(), key.into_owned(), value.into_owned())) } fn cache_set_expiration(&self, key: Cow<[u8]>, expire: u64) -> Result<(), Self::Error> { - local_cache::set_expiration(self.address.as_ref(), &key, expire); + OCallImpl.cache_set_expiration(self.address_bytes(), key.into_owned(), expire); Ok(()) } fn cache_get(&self, key: Cow<'_, [u8]>) -> Result>, Self::Error> { - Ok(local_cache::get(self.address.as_ref(), &key)) + Ok(OCallImpl.cache_get(self.address_bytes(), key.into_owned())) } fn cache_remove(&self, key: Cow<'_, [u8]>) -> Result>, Self::Error> { - Ok(local_cache::remove(self.address.as_ref(), &key)) + Ok(OCallImpl.cache_remove(self.address_bytes(), key.into_owned())) } fn log(&self, level: u8, message: Cow) -> Result<(), Self::Error> { - super::emit_log(&self.address, level, message.as_ref().into()); + OCallImpl.log_to_server(self.address.clone(), level, message.as_ref().into()); DefaultPinkExtension::new(self).log(level, message) } @@ -279,7 +264,42 @@ impl PinkExtBackend for CallInQuery { } fn worker_pubkey(&self) -> Result { - Ok(self.worker_pubkey) + Ok(OCallImpl.worker_pubkey()) + } + + fn code_exists(&self, code_hash: Hash, sidevm: bool) -> Result { + if sidevm { + Ok(crate::runtime::Pink::sidevm_code_exists(&code_hash.into())) + } else { + Ok(crate::storage::external_backend::code_exists( + &code_hash.into(), + )) + } + } + + fn import_latest_system_code( + &self, + payer: ext::AccountId, + ) -> Result, Self::Error> { + self.ensure_system()?; + let system_code = OCallImpl.latest_system_code(); + if system_code.is_empty() { + return Ok(None); + } + let code_hash = sp_core::blake2_256(&system_code); + if !self.code_exists(code_hash, false)? { + crate::runtime::Contracts::bare_upload_code( + payer.convert_to(), + system_code, + None, + pallet_contracts::Determinism::Deterministic, + )?; + }; + Ok(Some(code_hash)) + } + + fn runtime_version(&self) -> Result<(u32, u32), Self::Error> { + Ok(crate::version()) } } @@ -419,4 +439,19 @@ impl PinkExtBackend for CallInCommand { fn worker_pubkey(&self) -> Result { Ok(Default::default()) } + + fn code_exists(&self, code_hash: Hash, sidevm: bool) -> Result { + self.as_in_query.code_exists(code_hash, sidevm) + } + + fn import_latest_system_code( + &self, + payer: ext::AccountId, + ) -> Result, Self::Error> { + self.as_in_query.import_latest_system_code(payer) + } + + fn runtime_version(&self) -> Result<(u32, u32), Self::Error> { + self.as_in_query.runtime_version() + } } diff --git a/crates/pink/src/runtime/pallet_pink.rs b/crates/pink/runtime/src/runtime/pallet_pink.rs similarity index 88% rename from crates/pink/src/runtime/pallet_pink.rs rename to crates/pink/runtime/src/runtime/pallet_pink.rs index 62e6ff7f3a..bcee546738 100644 --- a/crates/pink/src/runtime/pallet_pink.rs +++ b/crates/pink/runtime/src/runtime/pallet_pink.rs @@ -17,6 +17,8 @@ pub mod pallet { SaturatedConversion, Saturating, }; + use crate::types::Hash; + type CodeHash = ::Hash; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -33,7 +35,8 @@ pub mod pallet { } #[pallet::storage] - pub(crate) type ClusterId = StorageValue<_, Vec, ValueQuery>; + #[pallet::getter(fn cluster_id)] + pub(crate) type ClusterId = StorageValue<_, Hash, ValueQuery>; #[pallet::storage] #[pallet::getter(fn gas_price)] @@ -50,13 +53,10 @@ pub mod pallet { #[pallet::storage] pub(crate) type TreasuryAccount = StorageValue<_, T::AccountId>; - /// The seed used to derive custom keys in `ink!` contract. - /// - /// All contracts in a cluster shares the same seed. When deriving a key from the seed, the - /// contract address is appended to the seed to avoid collisions. + /// The priviate key of the cluster #[pallet::storage] - #[pallet::getter(fn key_seed)] - pub(crate) type KeySeed = StorageValue<_, Sr25519SecretKey>; + #[pallet::getter(fn key)] + pub(crate) type Key = StorageValue<_, Sr25519SecretKey>; /// Uploaded sidevm codes #[pallet::storage] @@ -87,7 +87,7 @@ pub mod pallet { let buf = phala_types::contract::contract_id_preimage( deploying_address.as_ref(), code_hash.as_ref(), - &cluster_id, + cluster_id.as_ref(), salt, ); UncheckedFrom::unchecked_from(::Hashing::hash(&buf)) @@ -100,12 +100,12 @@ pub mod pallet { } impl Pallet { - pub fn set_cluster_id(cluster_id: &[u8]) { - >::put(cluster_id.to_vec()); + pub fn set_cluster_id(cluster_id: Hash) { + >::put(cluster_id); } - pub fn set_key_seed(seed: Sr25519SecretKey) { - >::put(seed); + pub fn set_key(key: Sr25519SecretKey) { + >::put(key); } pub fn put_sidevm_code( @@ -122,7 +122,11 @@ pub mod pallet { Ok(hash) } - pub fn set_system_contract(address: T::AccountId) { + pub fn sidevm_code_exists(code_hash: &T::Hash) -> bool { + >::contains_key(code_hash) + } + + pub fn set_system_contract(address: &T::AccountId) { >::put(address); } diff --git a/crates/pink/src/runtime/weights.rs b/crates/pink/runtime/src/runtime/weights.rs similarity index 100% rename from crates/pink/src/runtime/weights.rs rename to crates/pink/runtime/src/runtime/weights.rs diff --git a/crates/pink/src/snapshots/pink__runtime__detect_parameter_changes.snap b/crates/pink/runtime/src/snapshots/pink__runtime__detect_parameter_changes.snap similarity index 100% rename from crates/pink/src/snapshots/pink__runtime__detect_parameter_changes.snap rename to crates/pink/runtime/src/snapshots/pink__runtime__detect_parameter_changes.snap diff --git a/crates/pink/runtime/src/storage/external_backend.rs b/crates/pink/runtime/src/storage/external_backend.rs new file mode 100644 index 0000000000..02c085e30c --- /dev/null +++ b/crates/pink/runtime/src/storage/external_backend.rs @@ -0,0 +1,68 @@ +use super::{CommitTransaction, Storage}; +use crate::{capi::OCallImpl, types::Hashing}; +use hash_db::Prefix; +pub use helper::code_exists; +use phala_trie_storage::MemoryDB; +use pink_capi::v1::ocall::OCalls; +use sp_core::Hasher; +use sp_state_machine::{ + DBValue, DefaultError, TrieBackend, TrieBackendBuilder, TrieBackendStorage, +}; + +type Hash = ::Out; + +pub struct ExternalDB; +pub type ExternalBackend = TrieBackend; +pub type ExternalStorage = Storage; + +impl TrieBackendStorage for ExternalDB { + type Overlay = MemoryDB; + + fn get(&self, key: &Hash, _prefix: Prefix) -> Result, DefaultError> { + Ok(OCallImpl.storage_get(key.as_ref().to_vec())) + } +} + +impl CommitTransaction for ExternalBackend { + fn commit_transaction(&mut self, root: Hash, mut transaction: Self::Transaction) { + let changes = transaction + .drain() + .into_iter() + .map(|(k, v)| (k.as_bytes().to_vec(), v)) + .collect(); + OCallImpl.storage_commit(root, changes) + } +} + +impl ExternalStorage { + pub fn instantiate() -> Self { + let root = OCallImpl + .storage_root() + .unwrap_or_else(sp_trie::empty_trie_root::>); + let backend = TrieBackendBuilder::new(ExternalDB, root).build(); + crate::storage::Storage::new(backend) + } +} + +pub mod helper { + use crate::types::Hash; + use subxt::{ + metadata::DecodeStaticType, + storage::{ + address::{StorageHasher, StorageMapKey}, + StaticStorageAddress, + }, + }; + + pub fn code_exists(code_hash: &Hash) -> bool { + let map_key = StorageMapKey::new(code_hash, StorageHasher::Identity); + let address = StaticStorageAddress::, (), (), ()>::new( + "Contracts", + "OwnerInfoOf", + vec![map_key], + [0; 32], + ); + let key = address.to_bytes(); + super::ExternalStorage::instantiate().get(&key).is_some() + } +} diff --git a/crates/pink/runtime/src/storage/in_memory_backend.rs b/crates/pink/runtime/src/storage/in_memory_backend.rs new file mode 100644 index 0000000000..451e9d8a55 --- /dev/null +++ b/crates/pink/runtime/src/storage/in_memory_backend.rs @@ -0,0 +1,29 @@ +use super::{CommitTransaction, Hash, Hashing, MemoryDB, Storage}; + +pub type InMemoryStorage = Storage; + +impl Default for InMemoryStorage { + fn default() -> Self { + Self::new(new_in_memory_backend()) + } +} + +pub type InMemoryBackend = phala_trie_storage::InMemoryBackend; + +pub fn new_in_memory_backend() -> InMemoryBackend { + let db = MemoryDB::default(); + // V1 is same as V0 for an empty trie. + sp_state_machine::TrieBackendBuilder::new( + db, + sp_trie::empty_trie_root::>(), + ) + .build() +} + +impl CommitTransaction for InMemoryBackend { + fn commit_transaction(&mut self, root: Hash, transaction: Self::Transaction) { + let mut storage = sp_std::mem::replace(self, new_in_memory_backend()).into_storage(); + storage.consolidate(transaction); + *self = sp_state_machine::TrieBackendBuilder::new(storage, root).build(); + } +} diff --git a/crates/pink/runtime/src/storage/mod.rs b/crates/pink/runtime/src/storage/mod.rs new file mode 100644 index 0000000000..fbc43c4dd0 --- /dev/null +++ b/crates/pink/runtime/src/storage/mod.rs @@ -0,0 +1,92 @@ +use crate::{ + runtime::{ExecSideEffects, System, Timestamp}, + types::{Hash, Hashing}, +}; +use pink_capi::v1::ocall::ExecContext; +use sp_state_machine::{ + backend::AsTrieBackend, Backend as StorageBackend, Ext, OverlayedChanges, + StorageTransactionCache, +}; + +pub use external_backend::ExternalStorage; + +pub trait CommitTransaction: StorageBackend { + fn commit_transaction(&mut self, root: Hash, transaction: Self::Transaction); +} + +pub struct Storage { + backend: Backend, +} + +impl Storage { + pub fn new(backend: Backend) -> Self { + Self { backend } + } +} + +impl Storage +where + Backend: StorageBackend + CommitTransaction + AsTrieBackend, +{ + pub fn execute_with( + &self, + exec_context: &ExecContext, + f: impl FnOnce() -> R, + ) -> (R, ExecSideEffects, OverlayedChanges) { + let backend = self.backend.as_trie_backend(); + + let mut overlay = OverlayedChanges::default(); + overlay.start_transaction(); + let mut cache = StorageTransactionCache::default(); + let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); + let (rv, effects) = sp_externalities::set_and_run_with_externalities(&mut ext, move || { + Timestamp::set_timestamp(exec_context.now_ms); + System::set_block_number(exec_context.block_number); + System::reset_events(); + (f(), crate::runtime::get_side_effects()) + }); + overlay + .commit_transaction() + .expect("BUG: mis-paired transaction"); + (rv, effects, overlay) + } + + pub fn execute_mut( + &mut self, + context: &ExecContext, + f: impl FnOnce() -> R, + ) -> (R, ExecSideEffects) { + let (rv, effects, overlay) = self.execute_with(context, f); + self.commit_changes(overlay); + (rv, effects) + } + + pub fn changes_transaction(&self, changes: OverlayedChanges) -> (Hash, Backend::Transaction) { + let delta = changes + .changes() + .map(|(k, v)| (&k[..], v.value().map(|v| &v[..]))); + let child_delta = changes.children().map(|(changes, info)| { + ( + info, + changes.map(|(k, v)| (&k[..], v.value().map(|v| &v[..]))), + ) + }); + + self.backend + .full_storage_root(delta, child_delta, sp_core::storage::StateVersion::V0) + } + + pub fn commit_changes(&mut self, changes: OverlayedChanges) { + let (root, transaction) = self.changes_transaction(changes); + self.backend.commit_transaction(root, transaction) + } + + pub fn get(&self, key: &[u8]) -> Option> { + self.backend + .as_trie_backend() + .storage(key) + .expect("Failed to get storage key") + } +} + +pub mod external_backend; diff --git a/crates/pink/src/types.rs b/crates/pink/runtime/src/types.rs similarity index 100% rename from crates/pink/src/types.rs rename to crates/pink/runtime/src/types.rs diff --git a/crates/pink/unittests/.gitignore b/crates/pink/runtime/unittests/.gitignore similarity index 100% rename from crates/pink/unittests/.gitignore rename to crates/pink/runtime/unittests/.gitignore diff --git a/crates/pink/unittests/Cargo.toml b/crates/pink/runtime/unittests/Cargo.toml similarity index 85% rename from crates/pink/unittests/Cargo.toml rename to crates/pink/runtime/unittests/Cargo.toml index b8ea7adc15..ae4b019b4c 100755 --- a/crates/pink/unittests/Cargo.toml +++ b/crates/pink/runtime/unittests/Cargo.toml @@ -9,10 +9,10 @@ ink = { version = "4", default-features = false } scale = { package = "parity-scale-codec", version = "3.3", default-features = false, features = ["derive"] } scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } -pink-extension = { default-features = false, path = "../pink-extension" } +pink-extension = { default-features = false, path = "../../pink-extension" } [dev-dependencies] -pink-extension-runtime = { default-features = false, path = "../pink-extension-runtime" } +pink-extension-runtime = { default-features = false, path = "../../pink-extension-runtime" } [lib] name = "unittests" diff --git a/crates/pink/unittests/lib.rs b/crates/pink/runtime/unittests/lib.rs similarity index 100% rename from crates/pink/unittests/lib.rs rename to crates/pink/runtime/unittests/lib.rs diff --git a/crates/pink/src/contract.rs b/crates/pink/src/contract.rs deleted file mode 100644 index 47262eccb1..0000000000 --- a/crates/pink/src/contract.rs +++ /dev/null @@ -1,447 +0,0 @@ -use frame_support::weights::Weight; -use pallet_contracts::Determinism; -use pallet_contracts_primitives::StorageDeposit; -use scale::{Decode, Encode}; -use sp_runtime::DispatchError; - -use crate::{ - runtime::{ - BoxedEventCallbacks, Contracts, ExecSideEffects, Pink as PalletPink, System, Timestamp, - }, - storage, - types::{AccountId, Balance, BlockNumber, Hash}, -}; - -type ContractExecResult = pallet_contracts_primitives::ContractExecResult; -type ContractInstantiateResult = - pallet_contracts_primitives::ContractInstantiateResult; - -type ContractResult = - pallet_contracts_primitives::ContractResult, Balance>; - -pub type Storage = storage::Storage; - -fn _compilation_hint_for_kvdb(db: Storage) { - // TODO.kevin: Don't forget to clean up the disk space on cluster destroying when we switch to - // a KVDB backend. - let _dont_forget_to_clean_up_disk: storage::Storage = db; -} - -macro_rules! define_mask_fn { - ($name: ident, $bits: expr, $typ: ty) => { - /// Mask given number's lowest bits. - /// - /// Given a number 0x1000beef, in binary representation: - /// 0b_10000_00000000_10111110_11101111 - /// We want to mask it to 0x100fffff. - /// Rough steps: - /// 0b_10000_00000000_10111110_11101111 - /// ^ - /// 1. we find the most left bit position here - /// 0b_10000_00000000_10111110_11101111 - /// ^^^^^^^^^^^^^^^^^^^^^^ - /// 2. than calculate these bits need to be mask - /// 0b_10000_00001111_11111111_11111111 - /// ^^^^^^^^^^^^^^^^^^^^^^ - /// 3. mask it - fn $name(v: $typ, min_mask_bits: u32) -> $typ { - // Given v = 0x1000_beef - // Suppose we have: - // bits = 64 - // v =0b010000_00000000_10111110_11101111 - let pos = $bits - v.leading_zeros(); - // 0b010000_00000000_10111110_11101111 - // ^ - // here, pos=30 - // shift right by 9 - let pos = pos.max(9) - 9; - // Now pos = 0b_10000_00000000_00000000 - // ^ - // now here, pos=21 - // If min_mask_bits = 16 - // 0b_10000000_00000000 - // ^ - // min_mask_bits here - let pos = pos.clamp(min_mask_bits, $bits - 1); - let cursor: $typ = 1 << pos; - // 0b_10000_00000000_00000000 - // ^ - // cursor here - let mask = cursor.saturating_sub(1); - // mask = 0b_00001111_11111111_11111111 - // v | mask = - // 0b10000_00001111_11111111_11111111 - // = 0x100fffff - v | mask - } - }; -} - -define_mask_fn!(mask_low_bits64, 64, u64); -define_mask_fn!(mask_low_bits128, 128, u128); - -fn mask_deposit(deposit: u128, deposit_per_byte: u128) -> u128 { - let min_mask_bits = 128 - (deposit_per_byte * 1024).leading_zeros(); - mask_low_bits128(deposit, min_mask_bits) -} - -fn mask_gas(weight: Weight) -> Weight { - Weight::from_ref_time(mask_low_bits64(weight.ref_time(), 28)) -} - -#[test] -fn mask_low_bits_works() { - let min_mask_bits = 24; - assert_eq!(mask_low_bits64(0, min_mask_bits), 0xffffff); - assert_eq!(mask_low_bits64(0x10, min_mask_bits), 0xffffff); - assert_eq!(mask_low_bits64(0x1000_0000, min_mask_bits), 0x10ff_ffff); - assert_eq!( - mask_low_bits64(0x10_0000_0000, min_mask_bits), - 0x10_0fff_ffff - ); - assert_eq!( - mask_low_bits64(0x10_0000_0000_0000, min_mask_bits), - 0x10_0fff_ffff_ffff - ); - assert_eq!( - mask_low_bits64(0xffff_ffff_0000_0000, min_mask_bits), - 0xffff_ffff_ffff_ffff - ); - - let price = 10; - assert_eq!(mask_deposit(0, price), 0x3fff); - assert_eq!(mask_deposit(0x10, price), 0x3fff); - assert_eq!(mask_deposit(0x10_0000, price), 0x10_3fff); - assert_eq!(mask_deposit(0x10_0000_0000, price), 0x10_0fff_ffff); - assert_eq!( - mask_deposit(0x10_0000_0000_0000, price), - 0x10_0fff_ffff_ffff - ); -} - -fn coarse_grained(mut result: ContractResult, deposit_per_byte: u128) -> ContractResult { - result.gas_consumed = mask_gas(result.gas_consumed); - result.gas_required = mask_gas(result.gas_required); - - match &mut result.storage_deposit { - StorageDeposit::Charge(v) => { - *v = mask_deposit(*v, deposit_per_byte); - } - StorageDeposit::Refund(v) => { - *v = mask_deposit(*v, deposit_per_byte); - } - } - result -} - -impl Default for Storage { - fn default() -> Self { - let mut me = Self::new(storage::new_in_memory_backend()); - me.execute_mut(false, None, || { - System::set_block_number(1); - }); - me - } -} - -#[derive(Debug, Default, Encode, Decode, Clone)] -struct HookSelectors { - on_block_end: Option<(u32, Weight)>, -} - -#[derive(Debug, Encode, Decode, Clone)] -pub struct Contract { - pub address: AccountId, - hooks: HookSelectors, -} - -pub struct TransactionArguments<'a> { - pub origin: AccountId, - pub now: u64, - pub block_number: BlockNumber, - pub storage: &'a mut Storage, - pub transfer: Balance, - pub gas_limit: Weight, - pub gas_free: bool, - pub storage_deposit_limit: Option, - pub callbacks: Option, -} - -impl Contract { - /// Create a new contract instance from existing address. - pub fn from_address(address: AccountId) -> Self { - Contract { - address, - hooks: Default::default(), - } - } - - /// Create a new contract instance. - /// - /// # Parameters - /// - /// * `origin`: The owner of the created contract instance. - /// * `code_hash`: The hash of contract code which has been uploaded. - /// * `input_data`: The input data to pass to the contract constructor. - /// * `salt`: Used for the address derivation. - pub fn new( - code_hash: Hash, - input_data: Vec, - salt: Vec, - in_query: bool, - args: TransactionArguments, - ) -> Result<(Self, ExecSideEffects), DispatchError> { - let (result, effects) = Self::instantiate(code_hash, input_data, salt, in_query, args); - let result = result.result?; - if result.result.did_revert() { - return Err(DispatchError::Other("Exec reverted")); - } - Ok((Self::from_address(result.account_id), effects)) - } - - pub fn instantiate( - code_hash: Hash, - input_data: Vec, - salt: Vec, - in_query: bool, - args: TransactionArguments, - ) -> (ContractInstantiateResult, ExecSideEffects) { - let TransactionArguments { - origin, - block_number, - now, - storage, - transfer, - gas_limit, - storage_deposit_limit, - callbacks, - gas_free, - } = args; - let gas_limit = gas_limit.set_proof_size(u64::MAX); - storage.execute_mut(in_query, callbacks, move || { - let result = contract_tx( - origin.clone(), - block_number, - now, - gas_limit, - gas_free, - move || { - Contracts::bare_instantiate( - origin, - transfer, - gas_limit, - storage_deposit_limit, - pallet_contracts_primitives::Code::Existing(code_hash), - input_data, - salt, - false, - ) - }, - ); - log::info!("Contract instantiation result: {:?}", &result.result); - if in_query { - coarse_grained(result, PalletPink::deposit_per_byte()) - } else { - result - } - }) - } - - pub fn new_with_selector( - code_hash: Hash, - selector: [u8; 4], - args: impl Encode, - salt: Vec, - tx_args: TransactionArguments, - ) -> Result<(Self, ExecSideEffects), DispatchError> { - let mut input_data = vec![]; - selector.encode_to(&mut input_data); - args.encode_to(&mut input_data); - Self::new(code_hash, input_data, salt, false, tx_args) - } - - /// Call a contract method - /// - /// # Parameters - /// * `input_data`: The SCALE encoded arguments including the 4-bytes selector as prefix. - /// # Return - /// Returns the SCALE encoded method return value. - pub fn bare_call( - &self, - input_data: Vec, - in_query: bool, - tx_args: TransactionArguments, - ) -> (ContractExecResult, ExecSideEffects) { - let TransactionArguments { - origin, - now, - block_number, - storage, - transfer, - gas_limit, - gas_free, - callbacks, - storage_deposit_limit, - } = tx_args; - let addr = self.address.clone(); - let gas_limit = gas_limit.set_proof_size(u64::MAX); - let determinism = if in_query { - Determinism::AllowIndeterminism - } else { - Determinism::Deterministic - }; - storage.execute_mut(in_query, callbacks, move || { - let result = contract_tx( - origin.clone(), - block_number, - now, - gas_limit, - gas_free, - move || { - Contracts::bare_call( - origin, - addr, - transfer, - gas_limit, - storage_deposit_limit, - input_data, - true, - determinism, - ) - }, - ); - if in_query { - coarse_grained(result, PalletPink::deposit_per_byte()) - } else { - result - } - }) - } - - /// Call a contract method given it's selector - pub fn call_with_selector( - &self, - selector: [u8; 4], - args: impl Encode, - in_query: bool, - tx_args: TransactionArguments, - ) -> (Result, ExecSideEffects) { - let mut input_data = vec![]; - selector.encode_to(&mut input_data); - args.encode_to(&mut input_data); - let (result, effects) = self.bare_call(input_data, in_query, tx_args); - let result = result.result.and_then(|ret| { - Decode::decode(&mut &ret.data[..]) - .map_err(|_| DispatchError::Other("Decode result failed")) - }); - - (result, effects) - } - - /// Called by on each block end by the runtime - pub fn on_block_end( - &self, - storage: &mut Storage, - block_number: BlockNumber, - now: u64, - callbacks: Option, - ) -> Result { - if let Some((selector, gas_limit)) = self.hooks.on_block_end { - let mut input_data = vec![]; - selector.to_be_bytes().encode_to(&mut input_data); - - let (result, effects) = self.bare_call( - input_data, - false, - TransactionArguments { - origin: self.address.clone(), - now, - block_number, - storage, - transfer: 0, - gas_limit, - gas_free: false, - storage_deposit_limit: None, - callbacks, - }, - ); - let _ = result.result?; - Ok(effects) - } else { - Ok(Default::default()) - } - } - - pub fn set_on_block_end_selector(&mut self, selector: u32, gas_limit: u64) { - self.hooks.on_block_end = Some((selector, Weight::from_ref_time(gas_limit))); - } - - pub fn code_hash(&self, storage: &Storage) -> Option { - storage.code_hash(&self.address) - } -} - -fn contract_tx( - origin: AccountId, - block_number: BlockNumber, - now: u64, - gas_limit: Weight, - gas_free: bool, - tx_fn: impl FnOnce() -> ContractResult, -) -> ContractResult { - System::set_block_number(block_number); - Timestamp::set_timestamp(now); - if !gas_free && PalletPink::pay_for_gas(&origin, gas_limit).is_err() { - return ContractResult { - gas_consumed: Weight::zero(), - gas_required: Weight::zero(), - storage_deposit: Default::default(), - debug_message: Default::default(), - result: Err(DispatchError::Other("InsufficientBalance")), - }; - } - let result = tx_fn(); - if !gas_free { - let refund = gas_limit - .checked_sub(&result.gas_consumed) - .expect("BUG: consumed gas more than the gas limit"); - PalletPink::refund_gas(&origin, refund).expect("BUG: failed to refund gas"); - } - result -} - -pub use contract_file::ContractFile; - -mod contract_file { - use impl_serde::serialize as bytes; - use serde::Deserialize; - #[derive(Debug, Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct ContractFile { - pub metadata_version: String, - pub source: Source, - pub contract: Contract, - } - - #[derive(Debug, Deserialize)] - pub struct Source { - #[serde(with = "bytes")] - pub wasm: Vec, - #[serde(with = "bytes")] - pub hash: Vec, - pub language: String, - pub compiler: String, - } - - #[derive(Debug, Deserialize)] - pub struct Contract { - pub name: String, - pub version: String, - } - - impl ContractFile { - pub fn load(json_contract: &[u8]) -> serde_json::Result { - serde_json::from_slice(json_contract) - } - } -} diff --git a/crates/pink/src/lib.rs b/crates/pink/src/lib.rs deleted file mode 100644 index 7d84787727..0000000000 --- a/crates/pink/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate alloc; - -mod contract; -mod export_fixtures; - -pub mod runtime; -pub mod storage; - -pub mod types; - -pub use contract::{Contract, ContractFile, Storage, TransactionArguments}; -pub use export_fixtures::load_test_wasm; -pub use pink_extension_runtime::local_cache; - -pub use frame_support::weights; diff --git a/crates/pink/src/runtime.rs b/crates/pink/src/runtime.rs deleted file mode 100644 index 6661df3ce8..0000000000 --- a/crates/pink/src/runtime.rs +++ /dev/null @@ -1,542 +0,0 @@ -mod extension; -mod pallet_pink; -mod weights; - -use std::{ - sync::RwLock, - time::{Duration, Instant}, -}; - -use crate::types::{AccountId, Balance, BlockNumber, Hash, Hashing, Index}; -use frame_support::{ - parameter_types, - traits::ConstBool, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, -}; -use pallet_contracts::{Config, Frame, Schedule}; -use sp_runtime::{generic::Header, traits::IdentityLookup, Perbill}; - -pub use extension::{get_side_effects, ExecSideEffects}; -pub use pink_extension::{EcdhPublicKey, HookPoint, Message, OspMessage, PinkEvent}; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime! { - pub enum PinkRuntime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - Randomness: pallet_insecure_randomness_collective_flip, - Contracts: pallet_contracts, - Pink: pallet_pink, - } -} - -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); - -parameter_types! { - pub const BlockHashCount: u32 = 250; - pub RuntimeBlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::with_sensible_defaults( - Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), - NORMAL_DISPATCH_RATIO, - ); - pub const ExistentialDeposit: Balance = 1; - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; -} - -impl pallet_pink::Config for PinkRuntime { - type Currency = Balances; -} - -impl pallet_balances::Config for PinkRuntime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = frame_system::Pallet; - type WeightInfo = pallet_balances::weights::SubstrateWeight; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; -} - -impl frame_system::Config for PinkRuntime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = RuntimeBlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = Index; - type BlockNumber = BlockNumber; - type Hash = Hash; - type RuntimeCall = RuntimeCall; - type Hashing = Hashing; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl pallet_insecure_randomness_collective_flip::Config for PinkRuntime {} - -parameter_types! { - pub const MinimumPeriod: u64 = 1; -} - -impl pallet_timestamp::Config for PinkRuntime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = (); -} - -// Workaround for the test failure in runtime_integrity_tests -// https://github.com/paritytech/substrate/pull/12993/files#diff-67684005af418e25ff88c2ae5b520f0c040371f1d817e03a3652e76b9485224aR1217 -#[cfg(test)] -const MAX_CODE_NAME: u32 = 64 * 1024; -#[cfg(not(test))] -const MAX_CODE_NAME: u32 = 2 * 1024 * 1024; - -parameter_types! { - pub DepositPerStorageByte: Balance = Pink::deposit_per_byte(); - pub DepositPerStorageItem: Balance = Pink::deposit_per_item(); - pub const DeletionQueueDepth: u32 = 1024; - pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000); - pub const CallStackSize: u32 = 5; - pub const MaxCodeLen: u32 = MAX_CODE_NAME; - pub const MaxStorageKeyLen: u32 = 128; - pub const MaxDebugBufferLen: u32 = 128 * 1024; - - pub DefaultSchedule: Schedule = { - let mut schedule = Schedule::::default(); - const MB: u32 = 16; // 64KiB * 16 - // Each concurrent query would create a VM instance to serve it. We couldn't - // allocate too much here. - schedule.limits.memory_pages = 4 * MB; - schedule.instruction_weights.fallback = 8000; - schedule - }; -} - -impl Config for PinkRuntime { - type Time = Timestamp; - type Randomness = Randomness; - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type CallFilter = frame_support::traits::Nothing; - type CallStack = [Frame; CallStackSize::get() as usize]; - type WeightPrice = Pink; - type WeightInfo = weights::PinkWeights; - type ChainExtension = extension::PinkExtension; - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; - type Schedule = DefaultSchedule; - type DepositPerByte = DepositPerStorageByte; - type DepositPerItem = DepositPerStorageItem; - type AddressGenerator = Pink; - type MaxCodeLen = MaxCodeLen; - type MaxStorageKeyLen = MaxStorageKeyLen; - type UnsafeUnstableInterface = ConstBool; - type MaxDebugBufferLen = MaxDebugBufferLen; -} - -#[test] -fn detect_parameter_changes() { - insta::assert_debug_snapshot!(( - ::BlockWeights::get(), - ::Schedule::get(), - ::DeletionQueueDepth::get(), - ::DeletionWeightLimit::get(), - ::MaxCodeLen::get(), - ::MaxStorageKeyLen::get(), - )); -} - -#[derive(Clone, Copy)] -pub enum CallMode { - Query, - Command, -} - -pub trait EventCallbacks { - fn emit_log(&self, contract: &AccountId, in_query: bool, level: u8, message: String); -} - -pub type BoxedEventCallbacks = Box; - -pub struct CallModeInfo { - pub mode: CallMode, - pub worker_pubkey: EcdhPublicKey, -} - -struct CallInfo { - mode: CallMode, - start_at: Instant, - callbacks: Option, -} - -environmental::environmental!(call_info: CallInfo); - -static WORKER_PUBKEY: RwLock = RwLock::new([0; 32]); - -pub fn set_worker_pubkey(key: EcdhPublicKey) { - *WORKER_PUBKEY.write().unwrap() = key; -} - -pub fn using_mode( - mode: CallMode, - callbacks: Option, - f: impl FnOnce() -> T, -) -> T { - let mut info = CallInfo { - mode, - start_at: Instant::now(), - callbacks, - }; - call_info::using(&mut info, f) -} - -pub fn get_call_mode_info() -> Option { - call_info::with(|info| CallModeInfo { - mode: info.mode, - worker_pubkey: *WORKER_PUBKEY.read().unwrap(), - }) -} - -pub fn get_call_elapsed() -> Option { - call_info::with(|info| info.start_at.elapsed()) -} - -pub fn emit_log(id: &AccountId, level: u8, msg: String) { - call_info::with(|info| { - if let Some(callbacks) = &info.callbacks { - callbacks.emit_log(id, matches!(info.mode, CallMode::Query), level, msg); - } - }); -} - -#[cfg(test)] -mod tests { - #![allow(clippy::type_complexity)] - use super::*; - - use frame_support::{assert_ok, traits::Currency}; - use pallet_contracts::Config; - use sp_runtime::{traits::Hash, AccountId32}; - - use crate::{ - runtime::{Contracts, PinkRuntime, RuntimeOrigin as Origin}, - types::Balance, - Contract, Storage, TransactionArguments, - }; - - pub use frame_support::weights::Weight; - - const ALICE: AccountId32 = AccountId32::new([1u8; 32]); - const TREASURY: AccountId32 = AccountId32::new([2u8; 32]); - const ENOUGH: Balance = Balance::MAX.saturating_div(32); - const FLIPPER: &[u8] = include_bytes!("../tests/fixtures/flip/flip.wasm"); - const CENT: u128 = 10_000_000_000; - - pub fn compile_wat(wat_bytes: &[u8]) -> wat::Result<(Vec, ::Output)> - where - T: frame_system::Config, - { - let wasm_binary = wat::parse_bytes(wat_bytes)?.into_owned(); - let code_hash = T::Hashing::hash(&wasm_binary); - Ok((wasm_binary, code_hash)) - } - - #[test] - pub fn contract_test() { - use scale::Encode; - - let (wasm, code_hash) = - compile_wat::(include_bytes!("../tests/fixtures/event_size.wat")).unwrap(); - - exec::execute_with(|| { - _ = Balances::deposit_creating(&ALICE, Balance::MAX.saturating_div(2)); - Contracts::instantiate_with_code( - Origin::signed(ALICE), - ENOUGH, - Weight::MAX, - None, - wasm, - vec![], - vec![], - ) - .unwrap(); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[], &[]); - - Contracts::call( - Origin::signed(ALICE), - addr, - 0, - Weight::MAX, - None, - ::Schedule::get() - .limits - .payload_len - .encode(), - ) - .unwrap(); - }); - log::info!("contract OK"); - } - - #[test] - pub fn crypto_hashes_test() { - pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); - pub const GAS_LIMIT: Weight = - Weight::from_ref_time(100_000_000_000).set_proof_size(256u64 * 1024 * 1024); - - let (wasm, code_hash) = - compile_wat::(include_bytes!("../tests/fixtures/crypto_hashes.wat")) - .unwrap(); - - exec::execute_with(|| { - _ = Balances::deposit_creating(&ALICE, Balance::MAX.saturating_div(2)); - // Instantiate the CRYPTO_HASHES contract. - assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), - 1_000_000_000_000_000, - GAS_LIMIT, - None, - wasm, - vec![], - vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[], &[]); - // Perform the call. - let input = b"_DEAD_BEEF"; - use sp_io::hashing::*; - // Wraps a hash function into a more dynamic form usable for testing. - macro_rules! dyn_hash_fn { - ($name:ident) => { - Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice()) - }; - } - // All hash functions and their associated output byte lengths. - let test_cases: &[(Box Box<[u8]>>, usize)] = &[ - (dyn_hash_fn!(sha2_256), 32), - (dyn_hash_fn!(keccak_256), 32), - (dyn_hash_fn!(blake2_256), 32), - (dyn_hash_fn!(blake2_128), 16), - ]; - // Test the given hash functions for the input: "_DEAD_BEEF" - for (n, (hash_fn, expected_size)) in test_cases.iter().enumerate() { - // We offset data in the contract tables by 1. - let mut params = vec![(n + 1) as u8]; - params.extend_from_slice(input); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - params, - false, - pallet_contracts::Determinism::Deterministic, - ) - .result - .unwrap(); - assert!(!result.did_revert()); - let expected = hash_fn(input.as_ref()); - assert_eq!(&result.data[..*expected_size], &*expected); - } - }) - } - - #[test] - pub fn gas_limit_works() { - let mut storage = crate::Storage::default(); - - let gas_price = 2; - let deposit_per_item = CENT * 8; - let deposit_per_byte = CENT * 2; - - storage.setup(gas_price, deposit_per_item, deposit_per_byte, &TREASURY); - - let upload_result = storage.upload_code(&ALICE, FLIPPER.to_vec(), true); - assert!(upload_result.is_err()); - let upload_result = storage.upload_sidevm_code(&ALICE, FLIPPER.to_vec()); - assert!(upload_result.is_err()); - - let total_issue = Balance::MAX.saturating_div(2); - - storage.execute_mut(false, None, || { - _ = Balances::deposit_creating(&ALICE, total_issue); - }); - - let upload_result = storage.upload_sidevm_code(&ALICE, FLIPPER.to_vec()); - assert_ok!(upload_result); - - let upload_result = storage.upload_code(&ALICE, FLIPPER.to_vec(), true); - assert_ok!(&upload_result); - let code_hash = upload_result.unwrap(); - - // Flipper::default() - let default_selector = 0xed4b9d1b_u32.to_be_bytes().to_vec(); - let result = Contract::new( - code_hash, - default_selector, - vec![], - false, - tx_args(&mut storage), - ); - assert_ok!(&result); - - let flipper = result.unwrap().0; - - let mut prev_free_balance = storage.free_balance(&ALICE); - - // The contract flipper instantiated - let fn_flip = 0x633aa551_u32.to_be_bytes().to_vec(); - let fn_get = 0x2f865bd9_u32.to_be_bytes(); - - let init_value: bool = { - let mut args = tx_args(&mut storage); - args.gas_free = true; - flipper - .call_with_selector(fn_get, (), true, args) - .0 - .unwrap() - }; - - // Estimate gas - let est_result = { - let mut args = tx_args(&mut storage); - args.gas_free = true; - let result = flipper.bare_call(fn_flip.clone(), true, args).0; - assert_ok!(&result.result); - assert_eq!(storage.free_balance(&ALICE), prev_free_balance); - result - }; - - { - // Zero gas limit should not work - let gas_limit = 0; - let mut args = tx_args(&mut storage); - args.gas_free = false; - args.gas_limit = Weight::from_ref_time(gas_limit); - let result = flipper.bare_call(fn_flip.clone(), false, args).0; - assert!(result.result.is_err()); - assert_eq!(prev_free_balance, storage.free_balance(&ALICE)); - - // Should NOT flipped - let value: bool = { - let mut args = tx_args(&mut storage); - args.gas_free = true; - flipper - .call_with_selector(fn_get, (), true, args) - .0 - .unwrap() - }; - assert_eq!(init_value, value); - } - - { - let gas_limit = est_result.gas_required / 2; - let mut args = tx_args(&mut storage); - args.gas_free = false; - args.gas_limit = gas_limit; - let result = flipper.bare_call(fn_flip.clone(), false, args).0; - assert!(result.result.is_err()); - assert_eq!( - prev_free_balance - result.gas_consumed.ref_time() as u128 * gas_price, - storage.free_balance(&ALICE) - ); - - prev_free_balance = storage.free_balance(&ALICE); - - // Should NOT flipped - let value: bool = { - let mut args = tx_args(&mut storage); - args.gas_free = true; - flipper - .call_with_selector(fn_get, (), true, args) - .0 - .unwrap() - }; - assert_eq!(init_value, value); - } - - { - let gas_limit = est_result.gas_required; - let mut args = tx_args(&mut storage); - args.gas_free = false; - args.gas_limit = gas_limit; - let result = flipper.bare_call(fn_flip, false, args).0; - assert_ok!(result.result); - let cost = prev_free_balance - storage.free_balance(&ALICE); - assert_eq!(cost, result.gas_consumed.ref_time() as u128 * gas_price); - - // Should flipped - let value: bool = { - let mut args = tx_args(&mut storage); - args.gas_free = true; - flipper - .call_with_selector(fn_get, (), true, args) - .0 - .unwrap() - }; - assert_eq!(!init_value, value); - } - } - - fn tx_args(storage: &mut Storage) -> TransactionArguments { - TransactionArguments { - origin: ALICE.clone(), - now: 1, - block_number: 1, - storage, - transfer: 0, - gas_limit: Weight::MAX, - gas_free: false, - storage_deposit_limit: None, - callbacks: None, - } - } - - pub mod exec { - use sp_runtime::traits::BlakeTwo256; - use sp_state_machine::{ - backend::AsTrieBackend, Ext, OverlayedChanges, StorageTransactionCache, - }; - - pub type InMemoryBackend = sp_state_machine::InMemoryBackend; - - pub fn execute_with(f: impl FnOnce() -> R) -> R { - let state = InMemoryBackend::default(); - let backend = state.as_trie_backend(); - - let mut overlay = OverlayedChanges::default(); - overlay.start_transaction(); - let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); - let r = sp_externalities::set_and_run_with_externalities(&mut ext, f); - overlay - .commit_transaction() - .expect("BUG: mis-paired transaction"); - r - } - } -} diff --git a/crates/pink/src/storage.rs b/crates/pink/src/storage.rs deleted file mode 100644 index 5035007bfb..0000000000 --- a/crates/pink/src/storage.rs +++ /dev/null @@ -1,264 +0,0 @@ -use crate::{ - runtime::{ - Balances, BoxedEventCallbacks, CallMode, Contracts, ExecSideEffects, Pink as PalletPink, - }, - types::{AccountId, Balance, Hash, Hashing}, -}; -use frame_support::traits::Currency; -use frame_system::RawOrigin; -use pallet_contracts::Determinism; -use phala_crypto::sr25519::Sr25519SecretKey; -use phala_trie_storage::{deserialize_trie_backend, serialize_trie_backend, MemoryDB}; -use serde::{Deserialize, Serialize}; -use sp_runtime::DispatchError; -use sp_state_machine::backend::AsTrieBackend; -use sp_state_machine::{Backend as StorageBackend, Ext, OverlayedChanges, StorageTransactionCache}; - -mod backend; - -pub type InMemoryBackend = phala_trie_storage::InMemoryBackend; - -pub fn new_in_memory_backend() -> InMemoryBackend { - let db = MemoryDB::default(); - // V1 is same as V0 for an empty trie. - sp_state_machine::TrieBackendBuilder::new( - db, - sp_trie::empty_trie_root::>(), - ) - .build() -} - -pub trait CommitTransaction: StorageBackend { - fn commit_transaction(&mut self, root: Hash, transaction: Self::Transaction); -} - -impl CommitTransaction for InMemoryBackend { - fn commit_transaction(&mut self, root: Hash, transaction: Self::Transaction) { - let mut storage = sp_std::mem::replace(self, new_in_memory_backend()).into_storage(); - storage.consolidate(transaction); - *self = sp_state_machine::TrieBackendBuilder::new(storage, root).build(); - } -} - -pub trait Snapshot { - fn snapshot(&self) -> Self; -} - -pub struct Storage { - backend: Backend, -} - -impl Storage { - pub fn new(backend: Backend) -> Self { - Self { backend } - } -} - -impl Storage -where - Backend: Snapshot, -{ - pub fn snapshot(&self) -> Self { - Self { - backend: self.backend.snapshot(), - } - } -} - -impl Storage -where - Backend: StorageBackend + CommitTransaction + AsTrieBackend, -{ - pub fn execute_with( - &self, - in_query: bool, - callbacks: Option, - f: impl FnOnce() -> R, - ) -> (R, ExecSideEffects, OverlayedChanges) { - let backend = self.backend.as_trie_backend(); - - let mut overlay = OverlayedChanges::default(); - overlay.start_transaction(); - let mut cache = StorageTransactionCache::default(); - let mut ext = Ext::new(&mut overlay, &mut cache, backend, None); - let (rv, effects) = sp_externalities::set_and_run_with_externalities(&mut ext, move || { - crate::runtime::System::reset_events(); - let mode = if in_query { - CallMode::Query - } else { - CallMode::Command - }; - let r = crate::runtime::using_mode(mode, callbacks, f); - (r, crate::runtime::get_side_effects()) - }); - overlay - .commit_transaction() - .expect("BUG: mis-paired transaction"); - (rv, effects, overlay) - } - - pub fn execute_mut( - &mut self, - in_query: bool, - callbacks: Option, - f: impl FnOnce() -> R, - ) -> (R, ExecSideEffects) { - let (rv, effects, overlay) = self.execute_with(in_query, callbacks, f); - if !in_query { - self.commit_changes(overlay); - } - (rv, effects) - } - - pub fn changes_transaction(&self, changes: OverlayedChanges) -> (Hash, Backend::Transaction) { - let delta = changes - .changes() - .map(|(k, v)| (&k[..], v.value().map(|v| &v[..]))); - let child_delta = changes.children().map(|(changes, info)| { - ( - info, - changes.map(|(k, v)| (&k[..], v.value().map(|v| &v[..]))), - ) - }); - - self.backend - .full_storage_root(delta, child_delta, sp_core::storage::StateVersion::V0) - } - - pub fn commit_changes(&mut self, changes: OverlayedChanges) { - let (root, transaction) = self.changes_transaction(changes); - self.backend.commit_transaction(root, transaction) - } - - pub fn set_cluster_id(&mut self, cluster_id: &[u8]) { - self.execute_mut(false, None, || { - PalletPink::set_cluster_id(cluster_id); - }); - } - pub fn setup( - &mut self, - gas_price: Balance, - deposit_per_item: Balance, - deposit_per_byte: Balance, - treasury_account: &AccountId, - ) { - self.execute_mut(false, None, || { - PalletPink::set_gas_price(gas_price); - PalletPink::set_deposit_per_item(deposit_per_item); - PalletPink::set_deposit_per_byte(deposit_per_byte); - PalletPink::set_treasury_account(treasury_account); - }); - } - - pub fn deposit(&mut self, who: &AccountId, value: Balance) { - self.execute_mut(false, None, || { - let _ = Balances::deposit_creating(who, value); - }); - } - - pub fn set_key_seed(&mut self, seed: Sr25519SecretKey) { - self.execute_mut(false, None, || { - PalletPink::set_key_seed(seed); - }); - } - - pub fn upload_code( - &mut self, - account: &AccountId, - code: Vec, - deterministic: bool, - ) -> Result { - self.execute_mut(false, None, || { - crate::runtime::Contracts::bare_upload_code( - account.clone(), - code, - None, - if deterministic { - Determinism::Deterministic - } else { - Determinism::AllowIndeterminism - }, - ) - }) - .0 - .map(|v| v.code_hash) - } - - pub fn upload_sidevm_code( - &mut self, - account: &AccountId, - code: Vec, - ) -> Result { - self.execute_mut(false, None, || { - PalletPink::put_sidevm_code(account.clone(), code) - }) - .0 - } - - pub fn get_sidevm_code(&self, hash: &Hash) -> Option> { - self.execute_with(true, None, || { - PalletPink::sidevm_codes(&hash).map(|v| v.code) - }) - .0 - } - - pub fn set_system_contract(&mut self, address: AccountId) { - self.execute_mut(false, None, move || { - PalletPink::set_system_contract(address); - }); - } - - pub fn system_contract(&self) -> Option { - self.execute_with(true, None, PalletPink::system_contract).0 - } - - pub fn get(&self, key: &[u8]) -> Option> { - self.backend.storage(key).ok().flatten() - } - - pub fn root(&self) -> Hash { - *self.backend.as_trie_backend().root() - } - - pub fn free_balance(&self, account: &AccountId) -> Balance { - self.execute_with(true, None, || Balances::free_balance(account)) - .0 - } - - pub fn total_balance(&self, account: &AccountId) -> Balance { - self.execute_with(true, None, || Balances::total_balance(account)) - .0 - } - - pub fn code_hash(&self, account: &AccountId) -> Option { - self.execute_with(true, None, || Contracts::code_hash(account)) - .0 - } - - pub fn set_system_contract_code(&mut self, code_hash: Hash) -> Result<(), DispatchError> { - let system_contract = self.system_contract().ok_or(DispatchError::CannotLookup)?; - self.execute_mut(false, None, || { - Contracts::set_code(RawOrigin::Root.into(), system_contract, code_hash) - }) - .0 - } -} - -impl Serialize for Storage { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let trie = self.backend.as_trie_backend(); - serialize_trie_backend(trie, serializer) - } -} - -impl<'de> Deserialize<'de> for Storage { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(Self::new(deserialize_trie_backend(deserializer)?)) - } -} diff --git a/crates/pink/src/storage/backend.rs b/crates/pink/src/storage/backend.rs deleted file mode 100644 index bc82e4c043..0000000000 --- a/crates/pink/src/storage/backend.rs +++ /dev/null @@ -1,14 +0,0 @@ -use phala_trie_storage::clone_trie_backend; - -use crate::Storage; - -use super::Snapshot; - -impl Snapshot for Storage { - fn snapshot(&self) -> Self { - Storage { - // TODO.kevin: This is a heavy deep copy. Replace with an optimized snapshot implementation. - backend: clone_trie_backend(&self.backend), - } - } -} diff --git a/crates/pink/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate.snap b/crates/pink/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate.snap deleted file mode 100644 index 3c2706908b..0000000000 --- a/crates/pink/tests/snapshots/test_pink_contract__ink_cross_contract_instanciate.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: crates/pink/tests/test_pink_contract.rs -expression: result - ---- -true diff --git a/crates/pink/tests/snapshots/test_pink_contract__mq_egress-2.snap b/crates/pink/tests/snapshots/test_pink_contract__mq_egress-2.snap deleted file mode 100644 index 8d56d47f91..0000000000 --- a/crates/pink/tests/snapshots/test_pink_contract__mq_egress-2.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: crates/pink/tests/test_pink_contract.rs -assertion_line: 190 -expression: effects ---- -ExecSideEffects { - pink_events: [ - ( - 039fee9d7ce83a75f3e236161a8f7cf0f7c4ba5e1aa4a8eea659c5d98b04f186 (5C9TWZop...), - Message( - Message { - payload: [ - 66, - 66, - ], - topic: [ - 36, - 36, - ], - }, - ), - ), - ], - ink_events: [], - instantiated: [], -} diff --git a/crates/pink/tests/snapshots/test_pink_contract__mq_egress-3.snap b/crates/pink/tests/snapshots/test_pink_contract__mq_egress-3.snap deleted file mode 100644 index 133956b4c3..0000000000 --- a/crates/pink/tests/snapshots/test_pink_contract__mq_egress-3.snap +++ /dev/null @@ -1,64 +0,0 @@ ---- -source: crates/pink/tests/test_pink_contract.rs -assertion_line: 203 -expression: effects ---- -ExecSideEffects { - pink_events: [ - ( - 039fee9d7ce83a75f3e236161a8f7cf0f7c4ba5e1aa4a8eea659c5d98b04f186 (5C9TWZop...), - OspMessage( - OspMessage { - message: Message { - payload: [ - 66, - 66, - ], - topic: [ - 36, - 36, - ], - }, - remote_pubkey: Some( - [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - ), - }, - ), - ), - ], - ink_events: [], - instantiated: [], -} diff --git a/crates/pink/tests/snapshots/test_pink_contract__mq_egress.snap b/crates/pink/tests/snapshots/test_pink_contract__mq_egress.snap deleted file mode 100644 index 6a4c0955f7..0000000000 --- a/crates/pink/tests/snapshots/test_pink_contract__mq_egress.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: crates/pink/tests/test_pink_contract.rs -assertion_line: 177 -expression: effects ---- -ExecSideEffects { - pink_events: [], - ink_events: [], - instantiated: [ - ( - 0101010101010101010101010101010101010101010101010101010101010101 (5C62Ck4U...), - 039fee9d7ce83a75f3e236161a8f7cf0f7c4ba5e1aa4a8eea659c5d98b04f186 (5C9TWZop...), - ), - ], -} diff --git a/crates/pink/tests/snapshots/test_pink_contract__on_block_end-3.snap b/crates/pink/tests/snapshots/test_pink_contract__on_block_end-3.snap deleted file mode 100644 index 63f3fb941e..0000000000 --- a/crates/pink/tests/snapshots/test_pink_contract__on_block_end-3.snap +++ /dev/null @@ -1,29 +0,0 @@ ---- -source: crates/pink/tests/test_pink_contract.rs -assertion_line: 252 -expression: effects ---- -ExecSideEffects { - pink_events: [ - ( - 2affb93501ca8833b6dd866cbe03fe08da1a71dbccf82db453457901173485b8 (5D35qL1j...), - Message( - Message { - payload: [ - 102, - 111, - 111, - ], - topic: [ - 47, - 98, - 97, - 114, - ], - }, - ), - ), - ], - ink_events: [], - instantiated: [], -} diff --git a/crates/pink/tests/snapshots/test_pink_contract__on_block_end.snap b/crates/pink/tests/snapshots/test_pink_contract__on_block_end.snap deleted file mode 100644 index 8ad14f36df..0000000000 --- a/crates/pink/tests/snapshots/test_pink_contract__on_block_end.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: crates/pink/tests/test_pink_contract.rs -assertion_line: 228 -expression: contract ---- -Contract { - address: 2affb93501ca8833b6dd866cbe03fe08da1a71dbccf82db453457901173485b8 (5D35qL1j...), - hooks: HookSelectors { - on_block_end: None, - }, -} diff --git a/crates/pink/tests/test_pink_contract.rs b/crates/pink/tests/test_pink_contract.rs deleted file mode 100644 index 577453d527..0000000000 --- a/crates/pink/tests/test_pink_contract.rs +++ /dev/null @@ -1,296 +0,0 @@ -#![allow(clippy::let_unit_value)] - -use frame_support::assert_ok; -use hex_literal::hex; -use pink::{ - local_cache, - types::{Balance, Weight}, - Contract, Storage, TransactionArguments, -}; -use sp_runtime::AccountId32; - -pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); -pub const ENOUGH: Balance = u128::MAX / 2; - -fn tx_args(storage: &mut Storage) -> TransactionArguments { - TransactionArguments { - origin: ALICE.clone(), - now: 1, - block_number: 1, - storage, - transfer: 0, - gas_limit: Weight::MAX, - gas_free: true, - storage_deposit_limit: None, - callbacks: None, - } -} - -#[test] -fn test_ink_flip() { - let mut storage = Storage::default(); - storage.deposit(&ALICE, ENOUGH); - - let code_hash = storage - .upload_code( - &ALICE, - include_bytes!("./fixtures/flip/flip.wasm").to_vec(), - true, - ) - .unwrap(); - let contract = Contract::new_with_selector( - code_hash, - hex!("9bae9d5e"), // init_value - true, - vec![], - tx_args(&mut storage), - ) - .unwrap() - .0; - - let result: bool = contract - .call_with_selector( - hex!("2f865bd9"), // get - (), - false, - tx_args(&mut storage), - ) - .0 - .unwrap(); - - assert!(result); // Should equal to the init value - - let _: () = contract - .call_with_selector( - hex!("633aa551"), // flip - (), - false, - tx_args(&mut storage), - ) - .0 - .unwrap(); - - let result: bool = contract - .call_with_selector( - hex!("2f865bd9"), // get - (), - false, - tx_args(&mut storage), - ) - .0 - .unwrap(); - - assert!(!result); // Should be flipped - - let result: (u32, u128) = contract - .call_with_selector( - hex!("f7dff04c"), // echo - (42u32, 24u128), - false, - tx_args(&mut storage), - ) - .0 - .unwrap(); - assert_eq!(result, (42, 24)); -} - -#[test] -fn test_load_contract_file() { - assert_ok!(pink::ContractFile::load(include_bytes!( - "./fixtures/flip/flip.contract" - ))); -} - -#[test] -fn test_ink_cross_contract_instanciate() { - let mut storage = Storage::default(); - storage.deposit(&ALICE, ENOUGH); - - let code_hash = storage - .upload_code( - &ALICE, - include_bytes!("./fixtures/flip/flip.wasm").to_vec(), - true, - ) - .unwrap(); - let _flip = Contract::new_with_selector( - code_hash, - hex!("9bae9d5e"), // init_value - true, - vec![], - tx_args(&mut storage), - ) - .unwrap(); - - let code_hash = storage - .upload_code( - &ALICE, - include_bytes!("./fixtures/cross/cross.wasm").to_vec(), - true, - ) - .unwrap(); - let mut args = tx_args(&mut storage); - args.transfer = ENOUGH / 100; - let contract = Contract::new_with_selector(code_hash, hex!("9bae9d5e"), (), vec![], args) - .unwrap() - .0; - - let result: bool = contract - .call_with_selector( - hex!("c3220014"), // get - (), - false, - tx_args(&mut storage), - ) - .0 - .unwrap(); - - insta::assert_debug_snapshot!(result); -} - -#[test] -fn test_mq_egress() { - let mut storage = Storage::default(); - storage.deposit(&ALICE, ENOUGH); - - let code_hash = storage - .upload_code( - &ALICE, - include_bytes!("./fixtures/mqproxy/mqproxy.wasm").to_vec(), - true, - ) - .unwrap(); - let (contract, effects) = Contract::new_with_selector( - code_hash, - hex!("ed4b9d1b"), // init_value - (), - vec![], - tx_args(&mut storage), - ) - .unwrap(); - - insta::assert_debug_snapshot!(effects); - - let effects = contract - .call_with_selector::<()>( - hex!("6495da7f"), // push_message - (b"\x42\x42".to_vec(), b"\x24\x24".to_vec()), - false, - tx_args(&mut storage), - ) - .1; - insta::assert_debug_snapshot!(effects); - - let effects = contract - .call_with_selector::<()>( - hex!("d09d68e0"), // push_osp_message - (b"\x42\x42".to_vec(), b"\x24\x24".to_vec(), Some([0u8; 32])), - false, - tx_args(&mut storage), - ) - .1; - insta::assert_debug_snapshot!(effects); -} - -fn test_with_wasm(wasm: &[u8], constructor: [u8; 4], message: [u8; 4]) { - let mut storage = Storage::default(); - storage.set_key_seed([1u8; 64]); - storage.deposit(&ALICE, ENOUGH); - let code_hash = storage.upload_code(&ALICE, wasm.to_vec(), true).unwrap(); - - let (contract, _) = - Contract::new_with_selector(code_hash, constructor, (), vec![], tx_args(&mut storage)) - .unwrap(); - - local_cache::apply_quotas([(contract.address.as_ref(), 1024)]); - - let () = contract - .call_with_selector(message, (), true, tx_args(&mut storage)) - .0 - .unwrap(); -} - -#[test] -fn test_signing() { - test_with_wasm( - include_bytes!("./fixtures/signing/signing.wasm"), - hex!("ed4b9d1b"), - hex!("928b2036"), - ); -} - -#[test] -fn test_logging() { - env_logger::init(); - test_with_wasm( - include_bytes!("./fixtures/logging.wasm"), - hex!("ed4b9d1b"), - hex!("928b2036"), - ); -} - -#[test] -fn test_use_cache() { - test_with_wasm( - include_bytes!("./fixtures/use_cache/use_cache.wasm"), - hex!("ed4b9d1b"), - hex!("928b2036"), - ); -} - -#[test] -#[ignore = "for dev"] -fn test_qjs() { - use scale::{Encode, Decode}; - - env_logger::init(); - - let mut storage = Storage::default(); - storage.set_key_seed([1u8; 64]); - storage.deposit(&ALICE, ENOUGH); - let checker = []; - let qjs = []; - // let checker = include_bytes!("../../../e2e/res/check_system/target/ink/check_system.wasm"); - // let qjs = include_bytes!("qjs.wasm"); - - #[derive(Debug, Encode, Decode)] - pub enum Output { - String(String), - Bytes(Vec), - Undefined, - } - - let checker_hash = storage.upload_code(&ALICE, checker.to_vec(), true).unwrap(); - let qjs_hash = storage.upload_code(&ALICE, qjs.to_vec(), false).unwrap(); - - let (contract, _) = Contract::new_with_selector( - checker_hash, - 0xed4b9d1b_u32.to_be_bytes(), - (), - vec![], - tx_args(&mut storage), - ) - .unwrap(); - - local_cache::apply_quotas([(contract.address.as_ref(), 1024)]); - - let js = r#" - (function(){ - console.log("Hello, World!"); - // return scriptArgs[1]; - return new Uint8Array([21, 31]); - })() - "#; - let t0 = std::time::Instant::now(); - let args: Vec = vec!["Hello".to_string(), "World".to_string()]; - let result: Result = contract - .call_with_selector( - 0xf32e54c5_u32.to_be_bytes(), - (qjs_hash, js, args), - true, - tx_args(&mut storage), - ) - .0 - .unwrap(); - println!("evaluate result={result:?}, dt={:?}", t0.elapsed()); -} diff --git a/crates/sidevm/env/src/messages.rs b/crates/sidevm/env/src/messages.rs index 92428bd6bc..c0279f7c85 100644 --- a/crates/sidevm/env/src/messages.rs +++ b/crates/sidevm/env/src/messages.rs @@ -16,7 +16,7 @@ pub enum SystemMessage { PinkLog { block_number: u32, contract: AccountId, - in_query: bool, + exec_mode: String, timestamp_ms: u64, level: u8, message: String, diff --git a/crates/sidevm/host-runtime/src/env.rs b/crates/sidevm/host-runtime/src/env.rs index d22b16c8f1..b8de9f8272 100644 --- a/crates/sidevm/host-runtime/src/env.rs +++ b/crates/sidevm/host-runtime/src/env.rs @@ -68,12 +68,12 @@ impl<'a, T> FnEnvMut<'a, T> { } } -pub struct ShortId<'a>(pub &'a [u8]); +pub struct ShortId(pub T); -impl fmt::Display for ShortId<'_> { +impl> fmt::Display for ShortId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let len = self.0.len(); - hex_fmt::HexFmt(&self.0[..len.min(6)]).fmt(f) + let len = self.0.as_ref().len(); + hex_fmt::HexFmt(&self.0.as_ref()[..len.min(6)]).fmt(f) } } diff --git a/crates/sidevm/host-runtime/src/service.rs b/crates/sidevm/host-runtime/src/service.rs index c288cbd877..5e6b46b4b2 100644 --- a/crates/sidevm/host-runtime/src/service.rs +++ b/crates/sidevm/host-runtime/src/service.rs @@ -63,6 +63,7 @@ pub struct ServiceRun { report_rx: Receiver, } +#[derive(Clone)] pub struct Spawner { runtime_handle: tokio::runtime::Handle, report_tx: Sender, diff --git a/e2e/contracts/indeterministic_functions/Cargo.toml b/e2e/contracts/indeterministic_functions/Cargo.toml index a401064b78..380bbee7ad 100755 --- a/e2e/contracts/indeterministic_functions/Cargo.toml +++ b/e2e/contracts/indeterministic_functions/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" authors = ["[your_name] <[your_email]>"] edition = "2021" +[profile.release.package.compiler_builtins] +debug-assertions = false +overflow-checks = false + [dependencies] ink = { version = "4", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } diff --git a/e2e/res/prebuilt/system-v0xffff.contract b/e2e/res/prebuilt/system-v0xffff.contract index 2c01f8a082..e6e071f182 100644 --- a/e2e/res/prebuilt/system-v0xffff.contract +++ b/e2e/res/prebuilt/system-v0xffff.contract @@ -1 +1 @@ -{"source":{"hash":"0xb84372ddea72a1d3075e7df91f0ddbcc23d46416a6090d103b48a72a9376e5a4","language":"ink! 4.0.0-rc","compiler":"rustc 1.66.0-nightly","wasm":"0x0061736d01000000015d0f60027f7f0060017f0060037f7f7f0060037f7f7f017f60000060047f7f7f7f017f60027f7f017f60057f7f7f7f7f017f60047f7f7f7f0060087f7f7e7f7f7f7f7f017f60017f017f6000017f60027e7e0060037e7e7f0060027e7f000284020d057365616c310b6765745f73746f726167650005057365616c301176616c75655f7472616e736665727265640000057365616c301463616c6c5f636861696e5f657874656e73696f6e0007057365616c3005696e7075740000057365616c300663616c6c65720000057365616c3007616464726573730000057365616c300d6465706f7369745f6576656e740008057365616c320b7365745f73746f726167650005057365616c3110636f6e7461696e735f73746f726167650006057365616c300b7365616c5f72657475726e0002057365616c300f686173685f626c616b65325f3235360002057365616c310463616c6c000903656e76066d656d6f72790201021003232203030a0000010000010b0204000c0100000d02040400000101060200010003000e000608017f01418080040b071102066465706c6f79001f0463616c6c00200ab162222b01017f037f2002200346047f200005200020036a200120036a2d00003a0000200341016a21030c010b0b0b3f01027f0340200245044041000f0b200241016b210220012d0000210320002d00002104200041016a2100200141016a210120032004460d000b200420036b0b5301017f230041106b22012400200142808001370204200141e88204360200419d92ac8d012001100f2000200110102001280208220020012802044b0440000b200128020020001008200141106a2400417f470b2601017f230041106b220224002002200036020c20012002410c6a4104101e200241106a24000b0a00200120004120101e0b08002000410110120b2d01017f2000280208220220002802044904402000200241016a360208200028020020026a20013a00000f0b000bb30101037f230041106b22022400200242808001370204200241e8820436020020012002101002402002280204220420022802082201490d00200228020021032002200420016b2204360200411020032001200120036a2201200210021a200420022802002203492003411049722003417071411046720d002000200129001037031020002001290000370300200041186a200141186a2900003703002000200141086a290000370308200241106a24000f0b000b6d01017f230041106b2201240020014180800136020c41e882042001410c6a1004200041e98204290000370001200041096a41f18204290000370000200041116a41f98204290000370000200041186a41808304290000370000200041e882042d00003a0000200141106a24000b5502027f027e230041206b22002400200041106a22014200370300200042003703082000411036021c200041086a2000411c6a10012001290300210220002903082103200041206a2400410541042002200384501b0b2c01017f230041106b220324002003200136020c2003410c6a2002102b200220002001101e200341106a24000b4501017f230041106b2200240041e8820441013a0000200041e8820436020020004280808180103702042000101120002802082200418180014f0440000b41012000101c000b4401027f41e8820441003a000041012103200141ff0171410247044041e9820441013a000041022103200121020b200341e882046a20023a00002000200341016a101c000b4901017f230041106b22022400200241e8820436020041e8820441003a00002002428080818010370204200020012002101d20022802082202418180014f0440000b41002002101c000b870101047f230041106b22012400200142808001370204200141e8820436020041002001100f02402001280204220420012802082202490d0020012802002103200141003602082001200420026b3602042001200220036a3602002000200110102001280208220020012802044b0d00200320022001280200200010071a200141106a24000f0b000b2601017f230041106b22022400200220003b010e20012002410e6a4102101e200241106a24000b0d00200041e8820420011009000b2a01017f230041106b220324002003200137030820032000370300200220034110101e200341106a24000b5101037f024002402000280208220420026a22032004490d00200320002802044b0d00200320046b220520034b0d0020022005470d01200028020020046a20012002100c1a200020033602080f0b000b000bb10101027f230041406a2200240002400240101541ff01714105470d0020004180800136022041e88204200041206a100320002802202201418180014f0d00200141044f044041e8820428020041ed97f5dc01460d020b1017000b000b20001014200041386a200041186a290300370300200041306a200041106a290300370300200041286a200041086a29030037030020002000290300370320200041206a101a41e8820441003b010041004102101c000be03c020d7f057e230041f0036b22002400024002400240024002400240101541ff01714105470d002000418080013602f80241e88204200041f8026a100320002802f8022204418180014f0d0020044104490d03200041ec8204360290012000200441046b22033602940141e88204280200220841187621022008411076210120084108762105027f0240024002400240024002400240024002400240024002400240200841ff0171220841e6006b0e020401000b0240024020084187016b0e040112120a000b20084127460d0320084135460d06200841c500460d07200841d200460d05200841da00460d08200841a201460d0b200841aa01460d02200841af01460d0a200841f00147200541ff017141ef004772200141ff01714105472002410a4772722003412049720d1120004190026a4183830429000037030020004198026a418b83042d00003a00002000418c8304360290012000200441246b36029401200041fb82042900003703880241f382042800002201410876210341f78204280000210641ef8204280000210241ed82042f0000210741ec82042d00002109410a0c0d0b200541ff017141c90147200141ff0171418a0147722002418d0147720d1041000c0c0b200541ff017141e10047200141ff017141204772200241e10047200341204972720d0f20004190026a4183830429000037030020004198026a418b83042d00003a0000200041fb82042900003703880241f382042800002201410876210341f78204280000210641ef8204280000210241ed82042f0000210741ec82042d0000210941010c0b0b200541ff0171411e47200141ff0171412047722002413047720d0e200041f8026a20004190016a102120002802f8022202450d0e2000280294014120490d0e200028028003210620002802fc0221012000280290012203290018210d2003280014210a20004190026a200341086a29000037030020004198026a200341106a28000036020020002003290000370388022001410876210341020c0a0b200541ff017141c00047200141ff017141cf0147722002410a47720d0d200041f8026a20004190016a102120002802f8022202450d0d20002f00fd0220002d00ff02411074722103200028028003210620002d00fc02210141030c090b200541ff0171412f47200141ff017141ca0047720d0c200241a401460d070c0c0b200541ff017141a00147200141ff017141fd014772200241ea0047200341204972720d0b20004190026a4183830429000037030020004198026a418b83042d00003a00002000418c830436029001200041fb82042900003703880241f382042800002201410876210341f78204280000210641ef8204280000210241ed82042f0000210741ec82042d0000210941050c070b200541ff0171412c47200141ff017141eb004772200345200241dc004772720d0a41ec82042d0000200441056b41204972200441256b410c49720d0a20004190026a41f9820429000037030020004198026a41818304280000360200200041998304360290012000200441316b36029401200041f1820429000037038802418d83042800002201410876210341898304350000210d41918304290000210e41ed8204280000210641858304280000210a41060c060b200541ff017141ec0147200141ff0171419b0147722002411847200341204972722004417c71412446720d0941f48204280200210641f08204280200210141ec8204280200210220004190026a4180830429020037030020004198026a41888304280200360200200041908304360290012000200441286b36029401200041f882042902003703880220014108762103418c8304280200210a41070c050b200541ff017141980147200141ff017141f20147722002412647200341204972720d0820004190026a4183830429000037030020004198026a418b83042d00003a00002000418c8304360290012000200441246b36029401200041fb82042900003703880241f382042800002201410876210341f78204280000210641ef8204280000210241ed82042f0000210741ec82042d0000210941080c040b200541ff0171410d47200141ff017141c0004772200241d70147200341204972720d0720004190026a4183830429000037030020004198026a418b83042d00003a00002000418c8304360290012000200441246b36029401200041fb82042900003703880241f382042800002201410876210341f78204280000210641ef8204280000210241ed82042f0000210741ec82042d0000210941090c030b200541ff017141e90047200141ff017141ca0147722002410347720d06410b0c020b200541ff017141cb0047200141ff017141cb014772200241c4004720034120497272200441246b411049720d0541888304280200210a41f08204280200210641ec8204280200210120004190026a41fc820429020037030020004198026a418483042802003602002000419c8304360290012000200441346b36029401200041f48204290200370388022001410876210341948304290200210e418c8304290200210d410c0c010b2003412049200441246b412049720d0441f78204280000210641f38204280000210141ef8204280000210241ed82042f0000210741ec82042d000021092000418b036a418e83042d00003a0000200041d8016a41ab83042d00003a000020004180036a41838304290000220f37030020004188036a2203418b83042d00003a0000200041ac8304360290012000418c83042f01003b008903200041a383042900003703d001200041fb820429000022103703f802419b8304290000210e41938304290000210d418f8304280000210a20004190026a200f37030020004198026a200328020036020020002010370388022001410876210341040b210b200041c8006a20004198026a280200360200200041406b20004190026a290300370300200041306a200041d8016a2903003703002000200029038802370338200020002903d0013703282000428080013702fc02200041e882043602f8024100200041f8026a100f20002802fc0222082000280280032204490d0020002802f80221052000200820046b220c3602f80220052004200420056a2205200041f8026a10002108200c20002802f8022204492008410c4f720d00200841027441b082046a2802002004412049720d00200141ff01712003410874722101200041d9006a200541096a290000370000200041e1006a200541116a290000370000200041e8006a200541186a29000037000020002005290001370051200020052d00003a0050024002400240027f02400240024002400240024002400240024002400240024002400240024002400240200b41016b0e0c000102030405060708090b0a130b200041f8026a200041d0006a102220002d00f8022203450d1120002d00f90221010c180b200041e0016a200041c8006a280200360200200041d8016a200041406b290300370300200020002903383703d0012000200d3703e8012000200a3602e401200041f8026a200041d0006a102220002d00f802044020004188026a102320002d0088020d0f0b02402006410a470d00200241848004410a100d0d0020004191036a200041e8016a29030037000020004189036a200041e0016a290300370000200041083a00f80220004181036a200041d8016a290300370000200020002903d0013700f902200041f8026a10240b2000428080013702fc02200041e882043602f80241edddf6b47e200041f8026a2201100f200220062001101620002802fc0222032000280280032201490d1320002802f80221024100210420004100360280032000200320016b3602fc022000200120026a3602f802200041d0016a200041f8026a1010200028028003220320002802fc024b0d132002200120002802f802200310071a20004190036a200041e8006a29030037030020004188036a200041e0006a29030037030020004180036a200041d8006a290300370300200020002903503703f802200041f8026a101a41020c0f0b2000200636028003200020013602fc02200020023602f80220004188026a2103230041206b22022400200041f8026a220128020821062001280200200242808001370204200241e8820436020041edddf6b47e2002100f200620021016024002402002280204220520022802082206490d00200228020021042002200520066b220536020020042006200420066a2206200210002104200520022802002207492004410c4f720d002003027f02400240200441027441b082046a2802000e0400030301030b20074120490d02200241086a200641096a290000370300200241106a200641116a290000370300200241176a200641186a290000370000200220062900013703004101210420062d00000c010b4100210441000b3a0001200320043a0000200320022903003700022003410a6a200241086a290300370000200341126a200241106a290300370000200341196a200241176a290000370000200241206a24000c010b000b200141017220034121100c1a200041003a00f802230041106b22002400200041808001360204200041e882043602000240024020012d000045044041e8820441003a000020012d0001450440410221012000410236020841e9820441003a00000c030b41e9820441013a000020004102360208200141026a200010100c010b41e8820441013a000020004101360208200010110b2000280208220141818001490d00000b41002001101c000b20004198026a200041c8006a220328020036020020004190026a200041406b22042903003703002000200029033837038802200041f8026a102320002d00f8022205450d0b20002d00f90221010c130b200041f8026a102320002d00f8022203450d0920002d00f90221010c140b200041f8026a102320002d00f8022203450d0720002d00f90221020c100b200041f8026a102320002d00f8022203450d0520002d00f90221010c120b2000418f036a200041406b29030037000020004197036a200041c8006a2d00003a00002000200636008303200020013600ff02200020023600fb02200020073b00f902200020093a00f8022000200029033837008703230041406a22012400200141386a200041f8026a220241186a290000370300200141306a200241106a290000370300200141286a200241086a290000370300200120022900003703202001200141206a10132001290300210d2000200141086a2903003703082000200d370300200141406b24002000290300200041086a2903001019000b2000418f036a200041406b29030037000020004197036a200041c8006a2d00003a00002000200636008303200020013600ff02200020023600fb02200020073b00f902200020093a00f8022000200029033837008703230041406a22012400200141386a200041f8026a220241186a290000370300200141306a200241106a290000370300200141286a200241086a290000370300200120022900003703202001200141206a10132001290310210d200041106a2202200141186a2903003703082002200d370300200141406b24002000290310200041186a2903001019000b2000418f036a200041406b29030037000020004197036a200041c8006a2d00003a00002000200636008303200020013600ff02200020023600fb02200020073b00f902200020093a00f8022000200029033837008703230041206b22012400200141186a200041f8026a220041186a290000370300200141106a200041106a290000370300200141086a200041086a290000370300200120002900003703002001100e2100200141206a2400230041106b22012400200141e8820436020041e8820441003a00002001428080818010370204200120003a000f20012001410f6a4101101e0c100b20004188026a220210142000418080013602d00141e88204200041d0016a10054100210520004181036a41f1820429000037000020004189036a41f9820429000037000020004190036a41808304290000370000200041e982042900003700f902200041e882042d00003a00f80202402002200041f8026a102545044041012102410121010c010b2000418080013602f802410f41e88204410041e88204200041f8026a10021a20002802f8022202418180014f2002411f4d720d0b200041a8016a220241808304290200370300200041a0016a220341f8820429020037030020004198016a220541f08204290200370300200041e8820429020037039001200041206a410f410010262000280224210720002802202204419e8204290000370000200441076a41a58204290000370000200041b8026a2002290300370300200041b0026a2003290300370300200041a8026a200529030037030020004190026a420037030020004198026a420037030020002000290390013703a0022000420037038802200041f8026a220320004188026a22024138100c1a200220034138100c1a200041d0016a220520024138100c1a200320054138100c1a200041b8036a428f808080f084d0e70a370300200041b4036a2007360200200020043602b003200041808080083602c00320002903f802210f20004280800137028c02200041e882043602880220004190036a20021010200028028c0222052000280290022203490d0b200028028802210220004100360290022000200520036b36028c022000200220036a3602880220002903800320004188036a29030020004188026a101d200028028c0222072000280290022205490d0b200028028802210320004100360290022000200720056b36028c022000200320056a36028802200041bc036a20004188026a220510272004410f20051016200028028c0222072000280290022204490d0b20002802880221052000200720046b22093602880241082002200f200320052004200420056a220520004188026a100b2107200028028802220420094b2007410b4b722004452007417d7172720d0b2000200441016b22093602d4022000200541016a22073602d00202400240024002400240024020052d00000e020001110b2009450d100240024020072d000022050e020100120b200441026b4120490d11200041e0026a200741016a2203410e6a290000370300200041e8026a200341166a290000370300200041f0026a2003411e6a2f00003b0100200020032900063703d80220032f00002102200328000221030b200041b8016a2204200041e0026a290300370300200041c0016a2207200041e8026a290300370300200041c8016a2209200041f0026a2f01003b0100200020002903d8023703b0012005450d0320004188016a20092f010022053b010020004180016a2007290300220f370300200041f8006a20042903002210370300200020002903b0012211370370200041b8036a200e37030020004188036a420037030020004180036a42003703002000419e036a2010370100200041a6036a200f370100200041ae036a20053b0100200041c4036a2006360200200041c0036a220620013602002000200d3703b003200042003703f8022000200336019203200020023b0190032000201137019603200041c8036a2000290338370300200041d0036a200041406b290300370300200041d8036a200041c8006a280200360200200041e0036a220441a297ada604360200200041dc036a200a360200200041808080083602e80320002903f802210f20004280800137028c02200041e882043602880220004190036a20004188026a1010200028028c0222032000280290022201490d10200028028802210220004100360290022000200320016b36028c022000200120026a3602880220002903800320004188036a29030020004188026a101d200028028c0222052000280290022201490d10200028028802210320004100360290022000200520016b36028c022000200120036a36028802200420004188026a22011027200620011010200d200e2001101d200028028c0222042000280290022201490d1020002802880221062000200420016b22053602880241082002200f200320062001200120066a220120004188026a100b210220052000280288022204492002410b4b722004452002417d7172720d102000200441016b22023602d4012000200141016a22053602d00120012d00000e020102100b200041d0026a10280c0f0b2002450d0e024020052d00000e0202000f0b20044102460d0e2000200441036b22033602d401410121012000200541016a220241016a22063602d0010240024020022d000022020e03000105100b20004188026a200041d0016a10212000280288022204450d0f200029028c02210d0c040b2003450d0e20062d0000220541024f0d0e0c020b200041d0016a10280c0d0b20004190036a200041e8006a29030037030020004188036a200041e0006a29030037030020004180036a200041d8006a290300370300200020002903503703f802200041f8026a101a41002101410321020b0b2000200d37038003200020043602fc02200020053a00f902200020023a00f802230041106b22022400200241808001360204200241e8820436020002402002027f02400240200041f8026a22002d00002203410447044041e8820441003a00002003410346044041e9820441003a000041020c040b41e9820441013a000002400240200341016b0e020401000b2002410336020841ea820441003a0000200041046a2802002000410c6a280200200210160c020b41ea820441023a000041030c030b41e8820441013a000020024101360208200210110b2002280208220041818001490d02000b41ea820441013a000041eb820420002d00013a000041040b22003602080b20012000101c000b200041f8026a200041d0006a102220002d00f8022202044020002d00f90221010c090b2000419f026a220120004191036a220329000037000020004198026a22062000418a036a220429010037030020004190026a20004182036a2205290100220d370300200020002901fa02220e3703880220002d00f90221072005200d3701002004200629030037010020032001290000370000200020073a00f9022000200e3701fa022000410a3a00f802200041f8026a1024410221010c080b20004185036a20002903383700002000418d036a200041406b29030037000020004195036a200041c8006a280200360000200041093a00f80220004181036a2006360000200020013600fd02200020023600f9022000200a36029c03200041f8026a1024410221010c0c0b20004195036a200d3e000020004191036a200a36000020004185036a200041406b2903003700002000418d036a200041c8006a280200360000200020063600f902200020002903383700fd022000200e3703a0032000200136029c0341022102200041023a00f802200041f8026a2201102420004190036a200041e8006a29030037030020004188036a200041e0006a29030037030020004180036a200041d8006a290300370300200020002903503703f8022001101a0c080b20004184036a200636020020004180036a200136020020004188036a200029033837030020004190036a200041406b29030037030020004198036a200041c8006a2d00003a0000200020023602fc02200020073b01fa02200020093a00f902200041073a00f802200041f8026a1024410221010c0a0b200041a8036a200e370300200041a0036a200d37030020004184036a200636020020004180036a200136020020004188036a20002903383703002000419c036a200a36020020004190036a200429030037030020004198036a20032d00003a00002000419b036a2000419b026a2d00003a0000200020023602fc02200020073b01fa02200020093a00f902200020002f0099023b009903200041b0036a2000290328370300200041b8036a200041306a2d00003a0000200041033a00f802200041f8026a1024410221010c070b4101210420002d0089020b2101200420011018000b20004187036a200636000020004183036a20013600002000418b036a200029033837000020004193036a200041406b2903003700002000419b036a200041c8006a2d00003a0000200020023600ff02200020073b00fd02200020093a00fc022000418080043602f80220004280800137028c02200041e8820436028802419d92ac8d0120004188026a2201100f200041f8026a410472200110102000280290022201200028028c024b0d0220002802880222022001200120026a410010071a20004190036a200041e8006a29030037030020004188036a200041e0006a29030037030020004180036a200041d8006a290300370300200020002903503703f802200041f8026a101a410221010c060b200041ffff033b01fc02200041003602f802230041106b22012400200141808001360204200141e882043602000240200041f8026a22002f01004504402001410136020841e8820441003a000020002f01022001101b200041046a2f01002001101b0c010b41e8820441013a000020014101360208200110110b0c060b200241004720011018000b000b200341004720021018000b200541004720011018000b1017000b200341004720011018000b20012802082201418180014f0440000b41002001101c000bfa0701097f230041306b22032400200341186a200110290240024020032d00184101710d00024020032d0019220241037122054103470440024002400240200541016b0e020102000b200241fc017141027621020c030b200320023a0025200341013a002420032001360220200341003b012c200341206a2003412c6a4102102a0d0320032f012c220241ff014d0d03200241027621020c020b200320023a0025200341013a0024200320013602202003410036022c200341206a2003412c6a4104102a0d02200328022c220241808004490d02200241027621020c010b200241044f0d01200341106a210520012802042202410449047f4101052001200241046b36020420012001280200220241046a3602002002280000210241000b2104200520023602042005200436020020032802100d0120032802142202418080808004490d010b200128020422042002490d00200341086a200241011026200328020c210a2003280208200128020022062002100c21052001200420026b3602042001200220066a360200024002402002450d00200241076b22014100200120024d1b2108200541036a417c7120056b210941002101034002400240024002400240200120056a2d00002206411874411875220741004e0440200920016b4103712009417f46720d020240200120084f0d000340200120056a2204280200200441046a28020072418081828478710d012001200141086a22014b0d0320012008490d000b0b200120024f0d050340200120056a2c00004100480d062002200141016a2201470d000b0c070b024002402006418e80046a2d000041026b0e03040100090b200141016a220420024f0d08200420056a2c000021040240024002400240200641f0016b0e050100000002000b2007410f6a41ff017141024b200441004e720d0b20044140490d020c0b0b200441f0006a41ff01714130490d010c0a0b2004418f7f4a0d090b200141026a220420024f0d08200420056a2c000041bf7f4a0d08200141036a220120024f0d08200120056a2c000041bf7f4c0d040c080b200141016a220420024f0d07200420056a2c00002104024002400240200641e001470440200641ed01460d012007411f6a41ff0171410c490d022007417e71416e47200441004e720d0b20044140490d030c0b0b200441607141a07f460d020c0a0b200441a07f480d010c090b200441bf7f4a0d080b200141026a220120024f0d07200120056a2c000041bf7f4c0d030c070b000b200141016a21010c020b200141016a220120024f0d04200120056a2c000041bf7f4a0d040b200141016a21010b20012002490d000b0b200020023602082000200a360204200020053602000c020b200041003602000c010b200041003602000b200341306a24000b7101017f230041206b22022400200210142000027f200220011025450440200041003a000141010c010b20002002290300370001200041196a200241186a290300370000200041116a200241106a290300370000200041096a200241086a29030037000041000b3a0000200241206a24000b6d01017f230041206b220124002001101402402001100e450440200041013b00000c010b20002001290300370001200041003a0000200041196a200141186a290300370000200041116a200141106a290300370000200041096a200141086a2903003700000b200141206a24000b9b0a010a7f23004190016b22012400200141086a200041c800100c1a20014101360250200142808001370274200141e88204360270200141d0006a200141f0006a102b024020012802782200418180014f0d002001410036027820014180800120006b22043602742001200041e882046a2205360270418e82044110200141f0006a10162001280278220220012802744b0d0020012802702103200141e8006a22064200370300200141e0006a4200370300200141d8006a22074200370300200142003703500240200241214f044020014188016a2208420037030020014180016a22094200370300200141f8006a220a42003703002001420037037020032002200141f0006a100a20062008290300370300200141e0006a20092903003703002007200a290300370300200120012903703703500c010b200141d0006a20032002100c1a0b200141003602782001200436027420012005360270200141d0006a200141f0006a10102000200020012802786a22004b2000418180014f720d0020014180800120006b3602742001200041e882046a220236027002400240024002400240024002400240024002400240024020012d0008220341016b0e0a0102030405060708090a000b200041808001460d0b200241003a000020014101360278200141086a410472200141f0006a102d0c0a0b200041808001460d0a200241013a000020014101360278200141086a410472200141f0006a102d200141246a2d00004504402001280278220220012802744f0d0b200128027020026a41003a00002001200241016a3602780c0a0b2001280278220220012802744f0d0a200128027020026a41013a00002001200241016a360278200141256a200141f0006a10100c090b200041808001460d09200041e882046a41023a0000200041ffff004f0d09200241003a000120014102360278200141086a410172200141f0006a22021010200128022c2002100f20012903302002102c0c080b200041808001460d08200241033a000020014101360278200141086a410172200141f0006a22021010200141296a200210100c070b200041808001460d07200241043a000020014101360278200128020c200141146a280200200141f0006a10160c060b200041808001460d06200241053a0000024002400240200128021041016b0e020102000b200041ffff004f0d08200241003a000120014102360278200141146a2802002001411c6a280200200141f0006a22021016200141206a280200200141286a280200200210160c070b200041ffff004f0d07200241013a000120014102360278200141146a2802002001411c6a280200200141f0006a22021016200141206a2903002002102c0c060b200041ffff004f0d06200241023a000120014102360278200141146a2802002001411c6a280200200141f0006a10160c050b200041808001460d05200241063a0000200141013602780c040b200041808001460d04200241073a000020014101360278200141086a410172200141f0006a10100c030b200041808001460d03200241083a000020014101360278200141086a410172200141f0006a10100c020b200041808001460d02200241093a000020014101360278200141086a410172200141f0006a22021010200128022c2002100f0c010b200041808001460d012002410a3a000020014101360278200141086a410172200141f0006a10100b2001280278220220012802744b0d0041e8820420002001280270200210062003410546044020012802101a0b20014190016a24000f0b000b0b00200020014120100d450b8b0301067f230041106b2206240002402001450440410121020c010b200141004e0440200641086a21082001417f73411f76220420016a41016b410020046b712204200149210541e08204280200210302400240027f200245044020050d0241002105200320046a22022003490d032003200241e482042802004d0d011a200441ffff036a22022004490d032002411076220740002202417f46200241ffff0371200247720d032002411074220320074110746a22022003490d0341e482042002360200200320046a22022003490d0320030c010b20050d0141002105200320046a22022003490d022003200241e482042802004d0d001a200441ffff036a22022004490d022002411076220740002202417f46200241ffff0371200247720d022002411074220320074110746a22022003490d0241e482042002360200200320046a22022003490d0220030b210541e0820420023602000c010b000b2008200136020420082005360200200628020822020d010b000b2000200136020420002002360200200641106a24000b0a00200120004104101e0b2901017f230041106b22012400200141086a2000102920012d00091a20012d00081a200141106a24000b3c01017f200020012802042202047f2001200241016b36020420012001280200220141016a36020020012d00000520010b3a000120002002453a00000b910101027f20002f01042103200041003a0004410121040240024020034101714504402000280200220028020422032002490d022001200028020022012002100c1a0c010b200120034108763a0000200028020022002802042203200241016b2202490d01200141016a200028020022012002100c1a0b2000200320026b3602042000200120026a360200410021040b20040b550020002802002200413f4d04402001200041027410120f0b200041ffff004d044020004102744101722001101b0f0b200041ffffffff034d044020004102744102722001100f0f0b20014103101220002001100f0b2601017f230041106b22022400200220003703082001200241086a4108101e200241106a24000b27002000280200200041086a280200200110162000410c6a280200200041146a280200200110160b0ba7020300418080040b8e011d09ab1150696e6b4c6f6767657201010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010041d081040b3302020202020202020202020202020202020202020202020202020202020203030303030303030303030303030303040404040400418e82040b4f7068616c612e70696e6b2e6576656e74436f6e74726163744465706f736974000000000000000100000002000000030000000400000005000000060000000700000008000000090000000c0000000b","build_info":{"build_mode":"Release","cargo_contract_version":"2.0.0-rc.1","rust_toolchain":"nightly-x86_64-unknown-linux-gnu","wasm_opt_settings":{"keep_debug_symbols":false,"optimization_passes":"Z"}}},"contract":{"name":"system","version":"0.1.0","authors":["[your_name] <[your_email]>"]},"spec":{"constructors":[{"args":[],"docs":[],"label":"default","payable":false,"returnType":{"displayName":["ink_primitives","ConstructorResult"],"type":4},"selector":"0xed4b9d1b"}],"docs":[],"events":[],"lang_error":{"displayName":["ink","LangError"],"type":5},"messages":[{"args":[],"docs":[],"label":"System::version","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":6},"selector":"0x87c98a8d"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::grant_admin","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x67612061"},{"args":[{"label":"name","type":{"displayName":["String"],"type":12}},{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::set_driver","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0xaa1e2030"},{"args":[{"label":"name","type":{"displayName":["String"],"type":12}}],"docs":[],"label":"System::get_driver","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":13},"selector":"0x2740cf0a"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}},{"label":"code_hash","type":{"displayName":["pink","Hash"],"type":1}}],"docs":[],"label":"System::deploy_sidevm_to","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x662f4aa4"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::stop_sidevm_at","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x52a0fd6a"},{"args":[{"label":"hook","type":{"displayName":["HookPoint"],"type":15}},{"label":"contract","type":{"displayName":["AccountId"],"type":0}},{"label":"selector","type":{"displayName":["u32"],"type":16}},{"label":"gas_limit","type":{"displayName":["u64"],"type":17}}],"docs":[],"label":"System::set_hook","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x352c6b5c"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}},{"label":"weight","type":{"displayName":["u32"],"type":16}}],"docs":[],"label":"System::set_contract_weight","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x45ec9b18"},{"args":[{"label":"account","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::total_balance_of","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":18},"selector":"0x5a98f226"},{"args":[{"label":"account","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::free_balance_of","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":18},"selector":"0x8a0d40d7"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::is_admin","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":20},"selector":"0xf06f050a"},{"args":[],"docs":[],"label":"System::upgrade_system_contract","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0xaf69ca03"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}},{"label":"deposit","type":{"displayName":["Balance"],"type":19}}],"docs":[],"label":"ContractDeposit::change_deposit","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":22},"selector":"0xa24bcb44"}]},"storage":{"root":{"layout":{"struct":{"fields":[{"layout":{"leaf":{"key":"0x00000000","ty":0}},"name":"owner"},{"layout":{"root":{"layout":{"leaf":{"key":"0x11ab091d","ty":3}},"root_key":"0x11ab091d"}},"name":"administrators"},{"layout":{"root":{"layout":{"leaf":{"key":"0xe69daeed","ty":0}},"root_key":"0xe69daeed"}},"name":"drivers"}],"name":"System"}},"root_key":"0x00000000"}},"types":[{"id":0,"type":{"def":{"composite":{"fields":[{"type":1,"typeName":"[u8; 32]"}]}},"path":["ink_primitives","types","AccountId"]}},{"id":1,"type":{"def":{"array":{"len":32,"type":2}}}},{"id":2,"type":{"def":{"primitive":"u8"}}},{"id":3,"type":{"def":{"tuple":[]}}},{"id":4,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":5}],"path":["Result"]}},{"id":5,"type":{"def":{"variant":{"variants":[{"index":1,"name":"CouldNotReadInput"}]}},"path":["ink_primitives","LangError"]}},{"id":6,"type":{"def":{"variant":{"variants":[{"fields":[{"type":7}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":7},{"name":"E","type":5}],"path":["Result"]}},{"id":7,"type":{"def":{"tuple":[8,8]}}},{"id":8,"type":{"def":{"primitive":"u16"}}},{"id":9,"type":{"def":{"variant":{"variants":[{"fields":[{"type":10}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":10},{"name":"E","type":5}],"path":["Result"]}},{"id":10,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":11}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":11}],"path":["Result"]}},{"id":11,"type":{"def":{"variant":{"variants":[{"index":0,"name":"PermisionDenied"},{"index":1,"name":"DriverNotFound"}]}},"path":["pink_extension","system","Error"]}},{"id":12,"type":{"def":{"primitive":"str"}}},{"id":13,"type":{"def":{"variant":{"variants":[{"fields":[{"type":14}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":14},{"name":"E","type":5}],"path":["Result"]}},{"id":14,"type":{"def":{"variant":{"variants":[{"index":0,"name":"None"},{"fields":[{"type":0}],"index":1,"name":"Some"}]}},"params":[{"name":"T","type":0}],"path":["Option"]}},{"id":15,"type":{"def":{"variant":{"variants":[{"index":0,"name":"OnBlockEnd"}]}},"path":["pink_extension","HookPoint"]}},{"id":16,"type":{"def":{"primitive":"u32"}}},{"id":17,"type":{"def":{"primitive":"u64"}}},{"id":18,"type":{"def":{"variant":{"variants":[{"fields":[{"type":19}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":19},{"name":"E","type":5}],"path":["Result"]}},{"id":19,"type":{"def":{"primitive":"u128"}}},{"id":20,"type":{"def":{"variant":{"variants":[{"fields":[{"type":21}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":21},{"name":"E","type":5}],"path":["Result"]}},{"id":21,"type":{"def":{"primitive":"bool"}}},{"id":22,"type":{"def":{"variant":{"variants":[{"fields":[{"type":23}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":23},{"name":"E","type":5}],"path":["Result"]}},{"id":23,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":24}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":24}],"path":["Result"]}},{"id":24,"type":{"def":{"variant":{"variants":[{"fields":[{"type":12,"typeName":"String"}],"index":0,"name":"Other"},{"fields":[{"type":11,"typeName":"Error"}],"index":1,"name":"SystemError"},{"index":2,"name":"BadOrigin"}]}},"path":["pink_extension","system","DriverError"]}}],"version":"4"} \ No newline at end of file +{"source":{"hash":"0x9860ff9f430f6e4a2f8986f6faf364a10bc8647ce9d678fbdc0a5705bc107f2e","language":"ink! 4.0.0","compiler":"rustc 1.69.0-nightly","wasm":"0x0061736d0100000001731260037f7f7f017f60027f7f0060027f7f017f60037f7f7f0060017f0060047f7f7f7f0060057f7f7f7f7f0060017f017f60047f7f7f7f017f60000060017f017e60057f7f7f7f7f017f60087f7f7e7f7f7f7f7f017f6000017f60027e7e0060037e7e7f0060027e7f0060067f7f7f7f7f7f0002c20210057365616c310b6765745f73746f726167650008057365616c301176616c75655f7472616e736665727265640001057365616c301463616c6c5f636861696e5f657874656e73696f6e000b057365616c3005696e7075740001057365616c300663616c6c65720001057365616c3007616464726573730001057365616c300d64656275675f6d6573736167650002057365616c300d7365745f636f64655f686173680007057365616c300d6465706f7369745f6576656e740005057365616c320b7365745f73746f726167650008057365616c3110636f6e7461696e735f73746f726167650002057365616c300b7365616c5f72657475726e0003057365616c3009636f64655f686173680000057365616c300f686173685f626c616b65325f3235360003057365616c310463616c6c000c03656e76066d656d6f727902010210036e6d00000503070101030401010103060101040106040d03010207040201000109010e04010f03030909010101010408040401040101070607020701020302000003020200040903010104020a06050202020608050806020203060000060505020202020505000101050110021105040501700112120608017f01418080040b071102066465706c6f7900350463616c6c00360917010041010b1165642629466d705c586e57794d4f50596f0a82d6016d2b01017f037f2002200346047f200005200020036a200120036a2d00003a0000200341016a21030c010b0b0b3f01027f0340200245044041000f0b200241016b210220012d0000210320002d00002104200041016a2100200141016a210120032004460d000b200420036b0b1400200020012002200341a4a90441808004107a0b5001017f230041206b220324002003410c6a4101360200200341146a4100360200200341bcab04360210200341003602002003200136021c200320003602182003200341186a360208200320021025000b6c01027f230041306b22012400200141003602182001428080013702242001419ab204360220419d92ac8d01200141206a2202101420002002101520012001290320370310200141086a200141106a200128022810162001280208200128020c100a200141306a2400417f470b2601017f230041106b220224002002200036020c20012002410c6a41041033200241106a24000b0a0020012000412010330b4501017f2002200128020422034b044041eca404412341f0a5041012000b2001200320026b36020420012001280200220120026a36020020002002360204200020013602000b08002000410110180ba10101027f20002802082202200028020422034904402000200241016a360208200028020020026a20013a00000f0b230041306b220024002000200336020420002002360200200041146a41023602002000411c6a41023602002000412c6a4108360200200041f48d0436021020004100360208200041083602242000200041206a360218200020003602282000200041046a360220200041086a41d0a5041025000bb90202057f037e230041f0006b220224002002410036025020024280800137025c2002419ab2043602582001200241d8006a2205101520022002290358370348200241406b200241c8006a200228026010162002280244210320022802402106200228024821012002200228024c22043602584110200620032001200510021a02402002280258220320044d0440200241386a410020032001101120022002290338370358200241206a200241d8006a101a2002290320a70d01200241306a290300210720022903282108200241086a200241d8006a101a2002290308a70d01200241186a2903002109200020022903103703102000200737030820002008370300200041186a2009370300200241f0006a24000f0b200320044194af04101b000b41abac0441c900200241e8006a41bcab0441f4ac04101c000b6402027f037e230041106b22022400200241086a22034200370300200242003703000240200120024110102b45044020032903002105200229030021060c010b420121040b2000200637030820002004370300200041106a2005370300200241106a24000b0e0020002001200241f09404107b0b860101017f230041406a220524002005200136020c200520003602082005200336021420052002360210200541246a41023602002005412c6a41023602002005413c6a4101360200200541d48e0436022020054100360218200541023602342005200541306a3602282005200541106a3602382005200541086a360230200541186a20041025000b6201037f230041106b22022400200241086a2001101e41012103024020022802080d00200228020c210420022001101e20022802000d002002280204210120002004360204200041086a2001360200410021030b20002003360200200241106a24000b4801027f230041106b220224002002410036020c024020012002410c6a4104102b450440200228020c21010c010b410121030b2000200136020420002003360200200241106a24000bb50101027f230041e0006b22012400200141808001360230419ab204200141306a2202100520014180800136025c2001419ab2043602582002200141d8006a10202001027f20012d0030450440200141216a200141c9006a290000370000200141196a200141c1006a290000370000200141116a200141396a2900003700002001200129003137000941000c010b200141003a000941010b3a00082000200141086a41fc8104413741b482041021200141e0006a24000b8a0101047f230041206b22022400200241186a22034200370300200241106a22044200370300200241086a22054200370300200242003703002000027f200120024120102b45044020002002290300370001200041196a2003290300370000200041116a2004290300370000200041096a200529030037000041000c010b41010b3a0000200241206a24000b7401017f230041106b2205240020012d000045044020002001290001370000200041186a200141196a290000370000200041106a200141116a290000370000200041086a200141096a290000370000200541106a24000f0b200520012d00013a000f200220032005410f6a41dc81042004101c000bb60101027f230041e0006b22012400200141808001360230419ab204200141306a2202100420014180800136025c2001419ab2043602582002200141d8006a10202001027f20012d0030450440200141216a200141c9006a290000370000200141196a200141c1006a290000370000200141116a200141396a2900003700002001200129003137000941000c010b200141003a000941010b3a00082000200141086a41c4820441c100418883041021200141e0006a24000b5502027f027e230041206b22002400200041106a22014200370300200042003703082000411036021c200041086a2000411c6a10012001290300210220002903082103200041206a2400410541042002200384501b0b2c01017f230041106b220324002003200136020c2003410c6a200210772002200020011033200341106a24000bcb0101017f230041206b22022400200241013a00182002200136021420022000360210200241a08e0436020c200241bcab04360208230041406a220024002000200241086a36020c2000410736022420002000410c6a3602202000410136023c2000410236023420004190a5043602302000200041206a36023820004100360228200041106a200041286a105602404198b2042d00004504404199b2042d00004101710d010b20002802142000280218100641094704404198b20441013a00000b4199b20441013a00000b000b980401047f230041106b22022400024002400240024002400240024002400240024002400240024020002d000041016b0e0b0102030405060708090a0b000b41012100200128020022034192a70441062001280204220528020c22041100000d0b024020012d0018410471450440200341ec8e04410120041100000d0d200341f4a70441052004110000450d010c0d0b200341ea8e04410220041100000d0c2002200536020420022003360200200241013a000f20022002410f6a360208200241f4a704410510690d0c200241e88e04410210690d0c0b200341c18d044101200411000021000c0b0b20012802004185a704410d200128020428020c11000021000c0a0b200128020041f7a604410e200128020428020c11000021000c090b200128020041eca604410b200128020428020c11000021000c080b200128020041d2a604411a200128020428020c11000021000c070b200128020041c4a604410e200128020428020c11000021000c060b200128020041b4a6044110200128020428020c11000021000c050b200128020041d3b004410c200128020428020c11000021000c040b200128020041a9a604410b200128020428020c11000021000c030b200128020041a2a6044107200128020428020c11000021000c020b20012802004193a604410f200128020428020c11000021000c010b20012802004180a6044113200128020428020c11000021000b200241106a240020000b1b002000418180014f044020004180800141988304101b000b20000b5201017f230041206b220124002001410c6a4101360200200141146a4101360200200141acb004360208200141003602002001410436021c200120003602182001200141186a360210200141ac84041025000b910101017f230041306b22022400200241146a41013602002002411c6a4101360200200241acb0043602102002410036020820024102360224200220002d00004102742200418cb1046a28020036022c2002200041a0b1046a280200360228200141046a28020021002002200241206a3602182002200241286a36022020012802002000200241086a1068200241306a24000b4701017f230041106b220224002002410036020c024020012002410c6a4104102b4504402000200228020c360001200041003a00000c010b200041013a00000b200241106a24000b6001047f230041106b22032400200028020422042002492205450440200341086a41002002200028020022061072200120022003280208200328020c41e4a704106720032002200420061072200020032903003702000b200341106a240020050b8f0101047f230041206b22022400200241186a22034200370300200241106a22044200370300200241086a22054200370300200242003703000240200120024120102b45044020002002290300370001200041003a0000200041196a2003290300370000200041116a2004290300370000200041096a20052903003700000c010b200041013a00000b200241206a24000b3501017f230041106b220024002000428080013702042000419ab204360200200041011018200010174101200028020810271031000b4c01017f230041106b220224002002428080013702042002419ab2043602002002410010182002200141ff0171410447047f20024101101820010541000b10182000200228020810271031000b3901017f230041106b220224002002428080013702042002419ab20436020020024100101820002001200210324100200228020810271031000ba20102057f017e230041306b22012400200141003602182001428080013702242001419ab2043602204100200141206a2202101420012001290320370310200141086a200141106a220320012802281016200128020c2104200128020820012903102106200141003602282001200637032020002002101520012001290320370310200120032001280228101620042001280200200128020410091a200141306a24000b0d002000419ab2042001100b000b2a01017f230041106b2203240020032001370308200320003703002002200341101033200341106a24000b7901047f230041106b2203240002402000280208220520026a220420054f04402004200028020422064b0d01200341086a20052004200028020010712003280208200328020c2001200241c0a504106720002004360208200341106a24000f0b41d0a404411c41a0a5041012000b2004200641b0a504101b000b0e002000200210742001200210740b990201027f230041d0006b2200240002400240102341ff01714105460440200041808001360230419ab204200041306a100320002802302201418180014f0d01200041086a41002001419ab204101120002000290308370330200041106a200041306a102a20002d0010450440200028001141ed97f5dc01460d030b102d000b200041043a0030200041306a1028000b2001418080014194af04101b000b200041106a1022200041c8006a200041286a290300370300200041406b200041206a290300370300200041386a200041186a29030037030020002000290310370330200041306a1030230041106b220024002000428080013702042000419ab2043602002000410010182000410010184100200028020810271031000bd15c02117f047e230041e0066b2200240002400240024002400240024002400240027f02402000027f0240024002400240024002400240102341ff0171220141054604402000418080013602b005419ab204200041b0056a100320002802b0052201418180014f0d01200041f8026a41002001419ab2041011200020002903f8023703a803200041b0056a200041a8036a102a20002d00b0050d0e20002800b105220941187621012009411076210520094108762108027f0240024002400240024002400240024002400240200941ff0171220941316b0e050619191901000b024002400240024002400240200941e6006b0e020401000b0240024020094187016b0e04011f1f0a000b20094127460d03200941c500460d07200941d200460d05200941da00460d08200941a201460d0c200941aa01460d02200941af01460d0a200941f00147200841ff017141ef004772200541ff01714105472001410a4772720d1e200041b0056a200041a8036a102020002d00b0050d1e20004190056a200041c8056a29030037030020004198056a200041d0056a2d00003a00002000200041c0056a2903003703880520002802b405220441107621032004410876210a200041bc056a2802002107200041b8056a280200210620002f01b205210220002d00b105210b410a0c0f0b200841ff017141c90147200541ff0171418a0147722001418d0147720d1d41000c0e0b200841ff017141e10047200541ff017141204772200141e10047720d1c200041b0056a200041a8036a102020002d00b0050d1c20004190056a200041c8056a29030037030020004198056a200041d0056a2d00003a00002000200041c0056a2903003703880520002802b405220441107621032004410876210a200041bc056a2802002107200041b8056a280200210620002f01b205210220002d00b105210b41010c0d0b200841ff0171411e47200541ff0171412047722001413047720d1b200041a8066a200041a8036a103720002802ac062206450d1b20002802b006210720002802a8062104200041b0056a200041a8036a102020002d00b0050d1b20004198056a200041c1056a28000036020020004190056a200041b9056a290000370300200020002900b105370388052004410876210a20044110762103200041c5056a280000210c200041c9056a280000210d200041cd056a280000210e41020c0c0b200841ff017141c00047200541ff017141cf0147722001410a47720d1a200041b0056a200041a8036a103720002802b4052206450d1a20002802b805210720002f01b205210320002d00b105210a20002d00b005210441030c0b0b200841ff01712202412f460d09200541ff0171200241fe004772200141c10047720d19200041c0026a200041a8036a103820002f01c0020d1920002f01c2022102200041b8026a200041a8036a103820002f01b8020d1920002f01ba0222044180fe0371410876210a410c0c0a0b200841ff017141a00147200541ff017141fd014772200141ea0047720d18200041b0056a200041a8036a102020002d00b0050d1820004190056a200041c8056a29030037030020004198056a200041d0056a2d00003a00002000200041c0056a2903003703880520002802b405220441107621032004410876210a200041bc056a2802002107200041b8056a280200210620002f01b205210220002d00b105210b41050c090b200841ff0171412c47200541ff017141eb004772200141dc0047720d17200041d0026a200041a8036a103920002d00d10220002d00d002410171720d17200041b0056a200041a8036a102020002d00b0050d17200041c8026a200041a8036a101e20002802c8020d1720002802cc02210d200042003703a806200041a8036a200041a8066a4108102b0d1720004190056a200041c1056a29000037030020004198056a200041c9056a2800003602002000200041b9056a2900003703880520002903a8062111200041cd056a280000210c20002800b105210620002800b505210741060c080b200841ff017141ec0147200541ff0171419b0147722001411847720d16200041b0056a200041a8036a102020002d00b0050d16200041d8026a200041a8036a101e20002802d8020d1620002802dc02210c20004190056a200041c5056a29000037030020004198056a200041cd056a2800003602002000200041bd056a2900003703880520002800b105220441107621032004410876210a200041b9056a280000210720002800b505210641070c070b200841ff017141980147200541ff017141f20147722001412647720d15200041b0056a200041a8036a102020002d00b0050d1520004190056a200041c8056a29030037030020004198056a200041d0056a2d00003a00002000200041c0056a2903003703880520002802b405220441107621032004410876210a200041bc056a2802002107200041b8056a280200210620002f01b205210220002d00b105210b41080c060b200841ff0171410d47200541ff017141c0004772200141d70147720d14200041b0056a200041a8036a102020002d00b0050d1420004190056a200041c8056a29030037030020004198056a200041d0056a2d00003a00002000200041c0056a2903003703880520002802b405220441107621032004410876210a200041bc056a2802002107200041b8056a280200210620002f01b205210220002d00b105210b41090c050b200841ff017141e90047200541ff017141ca0147722001410347720d13410b0c040b200841ff017141ff0047200541ff017141eb0047720d12200141f301460d010c120b200841ff017141cb0047200541ff017141cb014772200141c40047720d11200041b0056a200041a8036a102020002d00b0050d11200041e0026a200041a8036a101a20002903e002a70d11200041f0026a290300211120002903e802211220004190056a200041c1056a29000037030020004198056a200041c9056a2800003602002000200041b9056a290000370388052012422088a7210e200041cd056a280000210c20002800b505210720002800b10521062012a7210d410e0c020b200041b0056a200041a8036a101d20002802b0050d1020002802b405220441107621032004410876210a200041b8056a2802002106410d0c010b200541ff017141ca0047200141a40147720d0f200041a8066a200041a8036a102020002d00a8060d0f200041b0056a200041a8036a102c20002d00b0050d0f200041bb046a20002d00b3053a000020004190046a200041d0056a2d00003a0000200041b0046a2201200041c0066a290300370300200041b8046a2203200041c8066a2d00003a0000200020002f00b1053b00b9042000200041c8056a290300370388042000200041b8066a2903003703a804200041c0056a2903002111200041b0066a2802002106200041b4066a2802002107200041b8056a290300211220002802b405210c20002d00a906210b20002f01aa06210220002802ac06210420004198056a200328020036020020004190056a2001290300370300200020002903a80437038805200441107621032004410876210a2012422088a7210e2012a7210d41040b210f200041a0036a20004198056a28020036020020004198036a20004190056a29030037030020004188036a20004190046a290300370300200020002903880537039003200020002903880437038003200041003602b0062000428080013702b4052000419ab2043602b0054100200041b0056a22081014200020002903b0053703a806200041b0026a200041a8066a20002802b805101620002802b402210920002802b00220002802a8062105200020002802ac0622013602b00520092005200810002108200120002802b0052209490d02200041a8026a410020092005101102400240024002402008410c4f0d00200841027441c0b1046a2802000e0401000002000b200041bc056a4101360200200041c4056a4100360200200041c483043602b805200041bcab043602c005200041003602b005200041b0056a41cc83041025000b20002802ac022105200020002802a8023602a804200020053602ac04200041b0056a200041a8046a102020002d00b005450d01200041bc056a4101360200200041c4056a4100360200200041e484043602b8050c110b200041bc056a4101360200200041c4056a41003602002000418485043602b8050c100b200441ff0171200a41ff0171410874722105200041b1036a200041ba056a290100370000200041b9036a200041c2056a290100370000200041c0036a200041c9056a290000370000200020002901b2053700a903200020002d00b1053a00a80302400240027f024002400240024002400240024002400240024002400240024002400240024002400240024002400240200f41016b0e0e000102030405060708090f0a0c0b170b200041b0056a200041a8036a103a20002d00b0052201450d1520002d00b10521020c240b200041b8046a200041a0036a280200360200200041b0046a20004198036a29030037030020002000290390033703a8042000200e3602c4042000200d3602c0042000200c3602bc04200041b0056a200041a8036a103a20002d00b0050440200041a8066a103b20002d00a8060d130b20062007418c8504410a103c0440200041c9056a200041c0046a290300370000200041c1056a200041b8046a290300370000200041b9056a200041b0046a290300370000200020002903a8043700b105200041063a00b005200041b0056a103d0b41002102200041003602b0062000428080013702b4052000419ab2043602b00541edddf6b47e200041b0056a220110142006200720011024200020002903b0053703a806200041206a200041a8066a220320002802b805101620002802242104200028022020002903a8062111200041003602b805200020113703b005200041a8046a20011015200020002903b0053703a806200041186a200320002802b805101620042000280218200028021c10091a200041c8056a200041c0036a290300370300200041c0056a200041b8036a290300370300200041b8056a200041b0036a290300370300200020002903a8033703b0052001103041040c130b200020073602b805200020063602b405200020034110742005723602b005200041a8066a2104230041f0006b22012400200041b0056a220228020821062002280204200141003602382001428080013702442001419ab20436024041edddf6b47e200141406b2203101420062003102420012001290340370330200141086a200141306a20012802481016200128020c210520012802082001280230210620012001280234220736024020052006200310002103024002402001280240220520074d044020014100200520061011027f0240024002402003410c4f0d00200341027441c0b1046a2802000e0402000001000b200141cc006a4101360200200141d4006a4100360200200141c48304360248200141bcab0436025020014100360240200141406b41cc83041025000b4100210341000c010b200128020021032001200128020436026c20012003360268200141406b200141e8006a102020012d00400d02200141186a200141ca006a290100370300200141206a200141d2006a290100370300200141276a200141d9006a2900003700002001200129014237031020012d0041210341010b2106200420033a0001200420063a0000200420012903103700022004410a6a200141186a290300370000200441126a200141206a290300370000200441196a200141276a290000370000200141f0006a24000c020b200520074194af04101b000b200141003a0030200141cc006a4101360200200141d4006a4101360200200141c4800436024820014100360240200141033602142001200141106a3602502001200141306a360210200141406b41ac81041025000b200241017220044121100f1a200041003a00b005230041106b220124002001428080013702042001419ab204360200024020022d000045044020014100101820022d00014504402001410010180c020b200141011018200241026a200110150c010b200141011018200110170b4100200128020810271031000b200041b8066a200041a0036a2201280200360200200041b0066a20004198036a220429030037030020002000290390033703a806200041b0056a103b20002d00b0052208450d0f20002d00b10521010c200b200041b0056a103b20002d00b0052204450d0d20002d00b10521010c1e0b200041b0056a103b20002d00b0052202450d0b20002d00b10521010c230b200041b0056a103b20002d00b0052202450d0920002d00b10521010c220b200041c7056a20004198036a290300370000200041cf056a200041a0036a2d00003a0000200020073600bb05200020063600b705200020023b00b1052000200b3a00b00520002000290390033700bf05200020034110742005723600b305230041406a22022400200241386a200041b0056a220141186a290000370300200241306a200141106a290000370300200241286a200141086a290000370300200220012900003703202002200241206a101920022903002111200041286a2201200241086a29030037030820012011370300200241406b24002000290328200041306a290300102f000b200041c7056a20004198036a290300370000200041cf056a200041a0036a2d00003a0000200020073600bb05200020063600b705200020023b00b1052000200b3a00b00520002000290390033700bf05200020034110742005723600b305230041406a22022400200241386a200041b0056a220141186a290000370300200241306a200141106a290000370300200241286a200141086a290000370300200220012900003703202002200241206a101920022903102111200041386a2201200241186a29030037030820012011370300200241406b24002000290338200041406b290300102f000b200041c7056a20004198036a290300370000200041cf056a200041a0036a2d00003a0000200020073600bb05200020063600b705200020023b00b1052000200b3a00b00520002000290390033700bf05200020034110742005723600b305230041206b22022400200241186a200041b0056a220141186a290000370300200241106a200141106a290000370300200241086a200141086a29000037030020022001290000370300200210132103200241206a2400230041106b220224002002428080013702042002419ab204360200230041106b22012400200241001018200120033a000f20022001410f6a41011033200141106a24000c200b200041b0056a103e20002d00b0050d022000419ab2043602a8062000428080013702ac06200041b0016a200041a8066a4100101620002802b401210420002802b001210620002802a8062101200020002802ac0622033602b0054115200620042001200041b0056a10021a200320002802b0052204490d10200041a8016a4100200420011011200020002903a8013703a804200041b0056a200041a8046a101d20002802b0050d1d410321044101210120002802b405450d034104210402400240200222010e020500010b41002101200541ffff03470d040b41012101200041bc056a4101360200200041c4056a4100360200200041e487043602b805200041bcab043602c005200041003602b0054101200041b0056a103f410321040c030b200041b0056a103e024020002d00b005450440200041a8046a1040200041a0026a410f10414100210420002802a002210320002802a402220241fcb004290000370000200241076a4183b104290000370000200041c8056a200041c0046a290300370300200041c0056a2205200041b8046a290300370300200041b8056a200041b0046a290300370300200041d8056a4200370300200041e0056a22084200370300200020002903a8043703b005200042003703d005200041a8066a220a200041b0056a4138100f1a20002802c80421012005200a4138100f2000410f3602bc05200020023602b805200020033602b405200041a780bdd6003602b005200020013602f805200041003602f804200041f0056a290300211220004280800137028c052000419ab2043602880520004188056a2203101520002000290388053703f00420004198026a200041f0046a22052000280290051016200028029802210a20002903f0042113200041003602900520002013370388052008290300200041e8056a2903002003103220002000290388053703f00420004190026a20052000280290051016200028029002210841bcab042103200141ffff037145044020002903f004211320004100360290052000201337038805200041b0056a20004188056a220310422002410f2003102420002000290388053703f00420004188026a200041f0046a2000280290051016200028028c02210420002802880221030b20002802f0042105200020002802f404220b3602880520011043200a2012200820032004200520004188056a100e210220004180026a2000280288052005200b4194af041044410c2101024002402000027f02402002410c49047f2002417d71450d01200241027441c0b1046a28020005410c0b41b3b1046a2d00000c010b20002802800221022000200028028402360284052000200236028005200041f8016a20004180056a1039024020002d00f8014101710d000240024020002d00f9010e020001020b200041f0016a20004180056a103920002d00f0014101710d010240024020002d00f10122020e020100030b20004188056a20004180056a102020002d0088050d02200041f0036a20004197056a290000370300200041f8036a2000419f056a29000037030020004180046a200041a7056a2f00003b01002000200029008f053703e803200028008b05210420002f00890521010b200041d8046a2203200041f0036a290300370300200041e0046a2205200041f8036a290300370300200041e8046a220820004180046a2f01003b0100200020002903e8033703d00420020d040c1c0b20004180056a10450d020b41000b3a00e80320004194056a41013602002000419c056a4101360200200041a4ad043602900520004100360288052000410336028c04200020004188046a360298052000200041e8036a3602880420004188056a41a0ae041025000b200041013602e80320004194056a41013602002000419c056a4101360200200041a4ad043602900520004100360288052000410536028c04200020004188046a360298052000200041e8036a3602880420004188056a4190ae041025000b200041e0036a20082f010022023b0100200041d8036a20052903002212370300200041d0036a20032903002213370300200020002903d00422143703c803200041be056a2013370100200041c6056a2012370100200041ce056a20023b0100200041d8056a4200370300200041e0056a4200370300200041ec056a200736020020004184066a200c36020020004198066a220341a297ada60436020020004188066a200dad200ead42208684221237030020004190066a2011370300200020043601b205200020013b01b005200020143701b605200042003703d005200020063602e805200041f0056a200029039003370300200041f8056a20004198036a29030037030020004180066a200041a0036a280200360200200041808080083602a006200041003602b0042000428080013702ac062000419ab2043602a806200041b0056a200041a8066a22021015200020002903a8063703a804200041e8016a200041a8046a220120002802b006101620002802e801210420002903a8042113200041003602b006200020133703a8064200420020021032200020002903a8063703a804200041e0016a200120002802b006101620002802e001210620002903a8042113200041003602b006200020133703a806200320021042200041e8056a200210152012201120021032200020002903a8063703a804200041d8016a200120002802b006101620002802dc01210120002802d801210720002802a8042103200020002802ac0422053602a80641082004420020062007200120032002100e2101200041d0016a20002802a806200320054194af04104402402000027f02402001410c49047f2001417d71450d01200141027441c0b1046a28020005410c0b41b3b1046a2d00000c010b20002802d4012102200020002802d001360288052000200236028c05200041c8016a20004188056a1039024020002d00c8014101710d000240024020002d00c9010e020001020b200041c0016a20004188056a103920002d00c0014101710d01024020002d00c1010e021c00020b200041b8016a20004188056a103920002d00b8014101710d010240024020002d00b90122040e03000107030b200041a8066a20004188056a103720002802ac06450d0220002902ac06211120002802a80621010c060b20004188056a104741ff017122024104460d010c050b20004188056a10450d020b41000b3a008805200041b4066a4101360200200041bc066a4101360200200041a4ad043602b006200041003602a806200041033602ac042000200041a8046a3602b806200020004188056a3602a804200041a8066a41a0ae041025000b2000410136028805200041b4066a4101360200200041bc066a4101360200200041a4ad043602b006200041003602a806200041053602ac042000200041a8046a3602b806200020004188056a3602a804200041a8066a4190ae041025000b20002d00b1052102410121040b41010c160b200041bc056a4101360200200041c4056a41003602002000419088043602b805200041bcab043602c005200041003602b0054103200041b0056a103f230041d0006b22022400200241083a0008200241106a20063602002002200341107420057236020c200241086a103d200241d0006a240041004104102e000b20002d00b1052104410121010b20012004102e000b200041b0056a200041a8036a103a0240027f0240027f20002d00b005450440200041f0036a2201200041ba056a290100370300200041f8036a2203200041c2056a290100370300200041ff036a2204200041c9056a290000370000200020002901b2053703e80320002d00b1052106200041bc056a4101360200200041c4056a4100360200200041b485043602b805200041bcab043602c005200041003602b0054103200041b0056a2202103f200041b1066a2001290300370000200041b9066a2003290300370000200041c0066a2004290000370000200020063a00a806200020002903e8033700a906200041003602b0042000428080013702b4052000419ab2043602b005200041a8066a20021015200020002903b0053703a804200041a0016a200041a8046a20002802b805101620002802a401210420002802a001210620002802a8042101200020002802ac0422033602b0054114200620042001200210021a200320002802b0052202490d1120004198016a410020022001101120002000290398013703880520004190016a20004188056a103920002d0090014101710d1d02400240024020002d0091010e020100200b200041b0056a20004188056a102c20002d00b0050d1f200041a0046a200041c9056a29000037030020004198046a200041c1056a29000037030020004190046a200041b9056a290000370300200020002900b10537038804200041a8066a101f2000419ab2043602a8042000428080013702ac0420004188016a200041a8046a4120101620002802b004220220002802ac0422014b0d14200028028c012103200028028801210420004180016a2002200120002802a80422011011200041003602b80520002000290380013703b005200041a8066a200041b0056a10152002200220002802b8056a22064b0d15200020013602a804200020063602b004200041f8006a200041a8046a104820002802782102200020033602b0052000027f024020022004200041b0056a100c2202410c49047f2002450d01200241027441c0b1046a28020005410c0b41b3b1046a2d00000c010b200020033602d404200020043602d004200041b0056a200041d0046a102c20002d00b005450d0241000b3a00b00541ec8504411d200041b0056a41dc8104418c8604101c000b200041bc056a4101360200200041c4056a4100360200200041e485043602b805200041bcab043602c005200041003602b0054101200041b0056a103f41020c020b20004191056a200041ba056a29010037000020004199056a200041c2056a290100370000200041a0056a200041c9056a290000370000200020002901b20537008905200020002d00b1053a008805200041c8056a200041a0046a290300370300200041c0056a20004198046a290300370300200041b8056a20004190046a29030037030020002000290388043703b00520004188056a200041b0056a10490d020240200020004188046a10072202410b4d047f2002450d01200241027441c0b1046a28020005410c0b41b3b1046a2d00003a00b005419c8604411e200041b0056a41dc810441bc8604101c000b200041a8046a1040200041c8056a200041c0046a290300370300200041c0056a200041b8046a290300370300200041b8056a200041b0046a290300370300200041d8056a22034200370300200041e0056a4200370300200020002903a8043703b005200042003703d005200041a8066a2204200041b0056a22014138100f1a20002802c8042102200120044138100f1a200042e6fc81889480403703e805200020023602f00541002104200041003602d00320002903e00521112000428080013702d4042000419ab2043602d0042001200041d0046a22011015200020002903d0043703c803200041f0006a200041c8036a220620002802d80410162000280270210720002903c8032112200041003602d804200020123703d00420002903d005200329030020011032200020002903d0043703c803200041e8006a200620002802d80410162000280268210641bcab042103200241ffff037145044020002903c8032112200041003602d804200020123703d004200041e8056a200041d0046a22011042410141ffff0320011034200020002903d0043703c803200041e0006a200041c8036a20002802d804101620002802642104200028026021030b20002802c8032101200020002802cc0322053602d00420021043200720112006200320042001200041d0046a100e2102200041d8006a20002802d004200120054194af04104402402002410c49047f2002417d71450d01200241027441c0b1046a28020005410c0b41b3b1046a2d00000c160b200028025c2102200020002802583602d004200020023602d404200041d0006a200041d0046a103920002d00504101710d14024002400240024020002d00510e020001180b200041c8006a200041d0046a103920002d00484101710d17024020002d00490e020300180b200041d0046a104741ff017122024104470d010c170b200041d0046a1045450d16200041013602f004200041dc046a4101360200200041e4046a4101360200200041a4ad043602d804200041003602d004200041053602cc032000200041c8036a3602e0042000200041f0046a3602c803200041d0046a4190ae041025000b200020023a00b00541cc86044130200041b0056a41ec810441fc8604101c000b200041bc056a4101360200200041c4056a4100360200200041b487043602b805200041bcab043602c005200041003602b0054103200041b0056a103f41000c030b20002d00b1050b2101410121020c020b200041bc056a4101360200200041c4056a4100360200200041e485043602b805200041bcab043602c005200041003602b0054103200041b0056a103f41000b2102410421010b20022001102e000b200041c0056a2007360200200041bc056a2006360200200041c4056a200029039003370200200041cc056a20004198036a290300370200200041d4056a200041a0036a2802003602002000200c3602b405200041073a00b005200020034110742005723602b805200041b0056a103d410421010c180b200041c4056a2007360200200041c8056a2201200029039003370300200041dc056a200c360200200041d0056a20004198036a290300370300200041d8056a200041a0036a280200360200200020063602c005200020113703b8052000200d3602b405200041003a00b005200041b0056a2203103d2001200041c0036a290300370300200041c0056a200041b8036a290300370300200041b8056a200041b0036a290300370300200020002903a8033703b00520031030410421010c170b200041bc056a2007360200200041b8056a2006360200200041c0056a200029039003370300200041c8056a20004198036a290300370300200041d0056a200041a0036a2d00003a0000200020023b01b2052000200b3a00b105200041053a00b005200020034110742005723602b405200041b0056a103d410421010c100b200041e0056a2011370300200041bc056a2007360200200041b8056a2006360200200041c0056a200029039003370300200041d4056a200c360200200041c8056a2004290300370300200041d0056a20012d00003a0000200041d3056a200041bb066a2d00003a0000200041d8056a200dad200ead42208684370300200020023b01b2052000200b3a00b105200020002f00b9063b00d105200020034110742005723602b405200041e8056a200029038003370300200041f0056a20004188036a2d00003a0000200041013a00b005200041b0056a103d410421010c100b4101210220002d00a9060b210120022001102e000b200041bf056a2007360000200041bb056a2006360000200041c3056a200029039003370000200041cb056a20004198036a290300370000200041d3056a200041a0036a2d00003a0000200020023b00b5052000200b3a00b405200041bc81043602b005200020034110742005723600b705200041003602b0042000428080013702ac062000419ab2043602a806419d92ac8d01200041a8066a2203101441042102200041b0056a220441047220031015200020002903a8063703a804200041106a200041a8046a220320002802b0061016200028021421062000280210200041086a20034100101620062000280208200028020c10091a200041c8056a200041c0036a290300370300200041c0056a200041b8036a290300370300200041b8056a200041b0036a290300370300200020002903a8033703b005200410300c0e0b200041ffff033b01b4052000418080043602b005230041106b220224002002428080013702042002419ab2043602000240200041b0056a22012f0100450440200241001018200141026a2f0100200141046a2f0100200210340c010b200241011018200210170b0c120b200020013a00b005200041b0056a1028000b2001418080014194af04101b000b200920014194af04101b000b200420034194af04101b000b200220034194af04101b000b20022001418cb004104a000b41c08104411c419cb0041012000b41000b3a00f004200041dc046a4101360200200041e4046a4101360200200041a4ad043602d804200041003602d004200041033602cc032000200041c8036a3602e0042000200041f0046a3602c803200041d0046a41a0ae041025000b200041c8056a200041c0036a290300370300200041c0056a200041b8036a290300370300200041b8056a200041b0036a290300370300200020002903a8033703b005200041b0056a10304103210441000b200020113703b805200020013602b405200020023a00b105200020043a00b005230041106b220224002002428080013702042002419ab2043602000240200041b0056a22012d000022004104470440200241001018200041034604402002410010180c020b200241011018024002400240200041016b0e020102000b200241001018200141086a2802002001410c6a280200200210240c030b200241011018200220012d000110180c020b2002410210180c010b200241011018200210170b200228020810271031000b20044100472001102e000b20084100472001102e000b20014100472002102e000b102d000b200041bcab043602c005200041003602b005200041b0056a41ac84041025000b41abac0441c900200041d0046a41bcab0441f4ac04101c000b20024100472001102e000b4100200228020810271031000bad07010a7f230041306b22032400200341186a200110390240024020032d00184101710d00024020032d0019220241037122044103470440024002400240200441016b0e020102000b200241fc017141027621020c030b200320023a0025200341013a002420032001360220200341003b012c200341206a2003412c6a410210730d0320032f012c220241ff014d0d03200241027621020c020b200320023a0025200341013a0024200320013602202003410036022c200341206a2003412c6a410410730d02200328022c220241808004490d02200241027621020c010b200241044f0d01200341106a2001101e20032802100d0120032802142202418080808004490d010b20012802042002490d00200341086a20021055200328020821092001200328020c22042002102b0d00024002402002450d00200241076b22014100200120024d1b2108200441036a417c7120046b220a417f46210b41002101034002400240024002400240200120046a2d00002206411874411875220741004e0440200b200a20016b410371720d020240200120084f0d000340200120046a220641046a280200200628020072418081828478710d012001200141086a22014b0d0320012008490d000b0b200120024f0d0720012002200120024b1b21060340200120046a2c00004100480d062006200141016a2201470d000b0c070b02400240200641909d046a2d000041026b0e03040100090b200141016a220520024f0d08200420056a2c000021050240024002400240200641f0016b0e050100000002000b2007410f6a41ff017141024b0d0b20054140480d020c0b0b200541f0006a41ff01714130490d010c0a0b2005418f7f4a0d090b200141026a220620024f0d08200420066a2c000041bf7f4a0d08200141036a220120024f0d08200120046a2c000041bf7f4c0d040c080b200141016a220520024f0d07200420056a2c00002105024002400240200641e001470440200641ed01460d012007411f6a41ff0171410c490d022007417e71416e470d0b20054140480d030c0b0b200541607141a07f460d020c0a0b200541a07f480d010c090b200541bf7f4a0d080b200141026a220120024f0d07200120046a2c000041bf7f4c0d030c070b41808d04411c41809d041012000b200141016a21010c020b200141016a220120024f0d04200120046a2c000041bf7f4a0d040b200141016a21010b20012002490d000b0b2000200236020820002004360204200020093602000c020b200041003602040c010b200041003602040b200341306a24000b4801027f230041106b22022400200241003b010e024020012002410e6a4102102b45044020022f010e21010c010b410121030b200020013b0102200020033b0100200241106a24000b3f01027f230041106b22022400200241003a000f200020012002410f6a4101102b2201047f41000520022d000f0b3a0001200020013a0000200241106a24000b7101017f230041206b22022400200210222000027f200220011049450440200041003a000141010c010b20002002290300370001200041196a200241186a290300370000200041116a200241106a290300370000200041096a200241086a29030037000041000b3a0000200241206a24000b6d01017f230041206b2201240020011022024020011013450440200041013b00000c010b20002001290300370001200041003a0000200041196a200141186a290300370000200041116a200141106a290300370000200041096a200141086a2903003700000b200141206a24000b1801017f2001200346047f20002002200110100541010b450b810902097f017e230041d0016b22012400200141386a200041c800100f1a2001410136029001200141306a41001075200141003602b801200120012903303703b00120014190016a200141b0016a1077024020012802b801220041818001490440200141286a200041808001419ab204107120014100360288012001290328210a200141003602b8012001200a3703b00141b4b0044110200141b0016a1024200120012903b00137038001200141206a20014180016a20012802b80110162001280220210420012802242103200141a8016a22024200370300200141a0016a2205420037030020014198016a2206420037030020014200370390010240200341214f0440200141c8016a22074200370300200141c0016a22084200370300200141b8016a22094200370300200142003703b00120042003200141b0016a100d200220072903003703002005200829030037030020062009290300370300200120012903b001370390010c010b200141186a200320014190016a4120419caa0410442001280218200128021c2004200341acaa0410670b200141106a20001075200141003602b801200120012903103703b00120014190016a200141b0016a10152000200020012802b8016a22004b0d01200141b8016a220320003602002001418080013602b4012001419ab2043602b001200141086a200141b0016a104820014198016a20032802002200360200200120012903b001220a37039001200128020c2103200128020820014188016a20003602002001200a37038001200141003602b8012001200a3703b001024002400240024002400240024002400240024020012d0038220041016b0e080102030405060708000b200141b0016a220241021018200241001018200141c8006a20021015200128023c200210142001290340200210780c080b200141b0016a220241031018200141386a41017220021015200141d9006a200210150c070b200141b0016a220241041018200141406b280200200141c4006a280200200210240c060b200141b0016a41051018024002400240200128024041016b0e020102000b200141b0016a220241001018200141c8006a280200200141cc006a28020020021024200141d4006a280200200141d8006a280200200210240c070b200141b0016a220241011018200141c8006a280200200141cc006a28020020021024200141d0006a290300200210780c060b200141b0016a220241021018200141c8006a280200200141cc006a280200200210240c050b200141b0016a410610180c040b200141b0016a220241071018200141386a410172200210150c030b200141b0016a220241081018200141386a410172200210150c020b200141b0016a220241091018200141406b20021015200128023c200210140c010b200141b0016a2202410a1018200128023c20021014200141406b280200200210140b200120012903b00137038001200120014180016a20012802b801101620032001280200200128020410082000410346044020012802401a0b200141d0016a24000f0b20004180800141e0a504104a000b41a0ab04411c419cb0041012000b7a01027f230041406a2201240020011022200141206a2202101f2000027f200120021049450440200041003a000141010c010b20002001290300370001200041196a200141186a290300370000200041116a200141106a290300370000200041096a200141086a29030037000041000b3a0000200141406b24000bdb0201057f23004190016b22022400200241386a22032000360200200241346a4100360200200241023602482002410236023c200241bcab043602302002410036022820022001290210370320200220012902083703182002200129020037031020024106360284012002200241e4006a2204360280012002200241106a3602642002410136027c20024101360274200241acb00436027020024100360268200220024180016a2206360278200241d8006a200241e8006a2205105620032802002100200228025c2002280260200241003602880120024280800137026c2002419ab204360268200220003a00642005200441011033200510242002200229036837038001200241086a200620022802701016200228020c210120022802082103200228028001210020022002280284012204360268410a200320012000200510021a20022002280268200020044194af04104420024190016a24000bf60101057f230041e0006b220124002001419ab20436021820014280800137021c200141106a200141186a410010162001280214210220012802102104200128021821032001200128021c2205360230410f200420022003200141306a220210021a200141086a2001280230200320054194af041044200120012903083703282002200141286a102020012d0030044041abac0441c900200141d8006a41bcab0441f4ac04101c000b20002001290031370000200041186a200141c9006a290000370000200041106a200141c1006a290000370000200041086a200141396a29000037000020004180808008360020200141e0006a24000b3501017f230041106b22022400200241086a20011055200228020c21012000200228020836020020002001360204200241106a24000b0a0020012000410410330b220020004115764108712000410e76410471200041077641027120004101717272720b4b01017f230041106b22052400200120034d0440200541086a4100200120021076200528020c21012000200528020836020020002001360204200541106a24000f0b200120032004101b000b3301027f230041106b22012400200141086a2000103920012d0009210020012d0008200141106a2400410171452000410146710b180020012802004198a7044111200128020428020c1100000b3d01027f230041106b22012400200141086a2000103920012d0009210020012d00082102200141106a2400410441042000200041044f1b20024101711b0b4501027f230041106b220224002001280208210320014100360208200241086a200120031016200228020c21012000200228020836020020002001360204200241106a24000b0b002000200141201010450b0e0020002001200241d09404107b0b5501017f230041206b2202240020022000360204200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241046a41988804200241086a104c200241206a24000bee0301057f230041406a22032400200341033a003820034280808080800437033020034100360228200341003602202003200136021c20032000360218027f0240024020022802002201450440200241146a28020022004103742105200041ffffffff017121072002280210210441002101034020012005460d02200228020820016a220041046a28020022060440200328021820002802002006200328021c28020c1100000d040b200141086a2101200428020020042802042106200441086a2104200341186a2006110200450d000b0c020b200228020422074105742100200741ffffff3f71210703402000450d01200228020820046a220541046a28020022060440200328021820052802002006200328021c28020c1100000d030b20032001411c6a2d00003a00382003200141146a290200370330200341106a200228021022052001410c6a106620032003290310370320200341086a2005200141046a106620032003290308370328200441086a2104200041206b210020012802002106200141206a2101200520064103746a2205280200200341186a2005280204110200450d000b0c010b2002410c6a28020020074b04402003280218200228020820074103746a22002802002000280204200328021c28020c1100000d010b41000c010b41010b200341406b24000b0f00200028020020012002104e41000b5801017f20022000280200200028020822036b4b044020002003200210511052200028020821030b200028020420036a20012002100f1a2003200220036a22014b044041b08804411c41f08c041012000b200020013602080bbe0201027f230041106b220224000240024002400240200028020022002002410c6a027f0240024020014180014f04402002410036020c2001418010490d012001418080044f0d0220022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d41030c030b200028020822032000280200460d030c040b20022001413f71418001723a000d2002200141067641c001723a000c41020c010b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c41040b104e0c020b20002003410110511052200028020821030b200028020420036a20013a0000200341016a2201450d01200020013602080b200241106a240041000f0b41b08804411c41e08c041012000b4a01017f230041206b220224002000280200200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241086a104b200241206a24000b9d0401067f230041206b220324000240027f41002001200120026a22014b0d001a2000280200220220026a22052002490d0141082005200120012005491b2201200141084d1b2201417f73411f7621040240200204402003410136021820032002360214200320002802043602100c010b200341003602180b200341106a2106230041106b220524002003027f0240027f0240200404400240200141004e044020062802080d0120052001410110542005280204210220052802000c040b0c040b20062802042208450440200541086a200141011054200528020c210220052802080c030b2001210241004190b204280200220420016a22072004490d021a200628020021064194b2042802002007490440200141ffff036a220741107640002202417f46200241ffff0371200247720d022002411074220420074180807c716a22022004490d024194b2042002360200200121024100200120046a22072004490d031a0b4190b204200736020041002004450d021a200420062008100f0c020b200320013602040c020b2001210241000b2204044020032004360204200341086a200236020041000c020b20032001360204200341086a410136020041010c010b200341086a410036020041010b360200200541106a240020032802004504402003280204210220002001360200200020023602044181808080780c010b200341086a2802000b200341206a24000f0b41d08804412141ec89041012000b1b00024020004181808080784704402000450d01000b0f0b1053000b4601017f230041206b22002400200041146a41013602002000411c6a4100360200200041908a04360210200041bcab0436021820004100360208200041086a41988a041025000bc40101037f024002402001200120026a41016b410020026b7122054d04404190b204280200220220056a22042002490d024194b2042802002004490440200541ffff036a22032005490d02200341107640002202417f46200241ffff0371200247720d022002411074220220034180807c716a22042002490d02410021034194b2042004360200200220056a22042002490d030b4190b2042004360200200221030c020b4180a404411c41eca3041012000b410021030b20002001360204200020033602000b5701027f230041106b2202240002402001450440410121030c010b200141004e0440200241086a20012001417f73411f761054200228020822030d01000b1053000b2000200336020420002001360200200241106a24000b9f0202077f017e230041206b22032400024002400240024002402001410c6a280200220604402001280208220841046a2105200641037421070340200220052802006a22042002490d05200541086a210520042102200741086b22070d000b200141146a2802000d010c030b200141146a2802000d010c020b2006452004410f4b720d00410021022008280204450d010b200420046a22024100200220044f1b21020b200320021041200329030021092000410036020820002009370200200341186a200141106a290200370300200341106a200141086a290200370300200320012902003703082000200341086a104b0d01200341206a24000f0b41b08804411c41d4a1041012000b41a88a044133200341086a41bcab0441d48b04101c000b0300010b0e0020002802001a03400c000b000b0c0042b39dc5e7bb8fa8d9410b4a01017f230041106b2205240020022003490440200320022004104a000b200541086a200320022001105b200528020c21012000200528020836020020002001360204200541106a24000b1400200020012002200341aca70441a08d04107a0bd806020b7f027e230041406a2203240020002802002202ad210d0240024002400240024002400240024020024190ce004f044041272100200d210e0240034020004104490d01200341196a20006a220241046b200e200e4290ce0080220d4290ce007e7da7220441ffff037141e4006e220641017441e78f046a2f00003b0000200241026b2004200641e4006c6b41ffff037141017441e78f046a2f00003b0000200041046b2100200e42ffc1d72f56200d210e0d000b200da7220241e3004d0d0320004102490d090c020b0c080b41272100200241e3004b0d002002410a490d040c020b200041026b2200200341196a6a200da72202200241ffff037141e4006e220241e4006c6b41ffff037141017441e78f046a2f00003b00000b2002410a490d01200041024f0d000c050b200041026b2200200341196a6a200241017441e78f046a2f00003b00000c020b2000450d030b200041016b2200200341196a6a200241306a3a00000b200041274b0d01412820006b412720006b22062001280218220541017122071b2102410021042005410471044041bcab042104200241bcab0441bcab04105d20026a22024b0d010b412b418080c40020071b2107200341196a20006a2108024020012802084504404101210020012802002202200141046a28020022012007200410600d01200220082006200128020c11000021000c010b024020022001410c6a28020022094904402005410871450d01200128021c210b2001413036021c20012d0020210c41012100200141013a002020012802002205200141046a280200220a2007200410600d02200341106a2001200920026b4101106120032802142202418080c400460d022003280210200520082006200a28020c1100000d0220022005200a10620d022001200c3a00202001200b36021c410021000c020b4101210020012802002202200141046a28020022012007200410600d01200220082006200128020c11000021000c010b41012100200341086a2001200920026b41011061200328020c2205418080c400460d00200328020820012802002202200141046a28020022012007200410600d00200220082006200128020c1100000d00200520022001106221000b200341406b240020000f0b41808d04411c41ac92041012000b41a08d04412141e4a1041012000ba704010a7f230041106b2203240002400240200020016b22024110490d002002200141036a417c7120016b220049200041044b720d00200220006b22044104490d0020012000105e2206200020016a22082004417c716a2004410371105e6a220220064f0440200441027621050240024003402005450d0520032008200541c0012005200541c0014f1b41809604105f200328020c21052003280208210820032003280200200328020422002000417c7141809904105f200328020c210920032802082107024020032802042200450440410021010c010b2003280200220420004102746a210a4100210103402004220641106a2104410021000240034020012001200020066a280200220b417f73410776200b410676724181828408716a22014d0440200041046a22004110470d010c020b0b41808d04411c419099041012000b2004200a470d000b0b20022002200141087641ff81fc0771200141ff81fc07716a418180046c4110766a22024b0d012009450d000b200941027421004100210103402001200120072802002204417f734107762004410676724181828408716a22014b0d02200741046a2107200041046b22000d000b20022002200141087641ff81fc0771200141ff81fc07716a418180046c4110766a22024d0d0441808d04411c41c099041012000b41808d04411c41a099041012000b41808d04411c41b099041012000b41808d04411c41f098041012000b20012002105e21020b200341106a240020020b4601017f200145044041000f0b024003402002200220002c000041bf7f4a6a22024b0d01200041016a2100200141016b22010d000b20020f0b41808d04411c41d4a1041012000b3e00200220034f044020002003360204200020013602002000410c6a200220036b3602002000200120034102746a3602080f0b41eca404412320041012000b39000240027f2002418080c40047044041012000200220012802101102000d011a0b20030d0141000b0f0b200020034100200128020c1100000bae0101027f20022104024002400240200320012d0020220320034103461b41ff0171220341016b0e03010001020b200241016a2203044020034101762104200241017621030c020b41808d04411c41bc92041012000b41002104200221030b200341016a2102200128021c2103200128020421052001280200210102400340200241016b2202450d01200120032005280210110200450d000b418080c40021030b20002003360204200020043602000b3201017f027f0340200020002004460d011a200441016a2104200220012003280210110200450d000b200441016b0b2000490b4b01017f230041106b22052400200120034d0440200541086a410020012002105b200528020c21012000200528020836020020002001360204200541106a24000f0b200120032004101b000bea04010b7f230041106b2209240020002802042104200028020021030240024002402001280208220b410147200128021022024101477145044020024101470d02200320046a210c200141146a28020041016a210a410021022003210003402000200c460d03027f024020002c0000220641004e0440200041016a2105200641ff017121070c010b20002d0001413f7121052006411f7121072006415f4d044020074106742005722107200041026a21050c010b20002d0002413f7120054106747221082006417049044020082007410c74722107200041036a21050c010b200041046a210520022106418080c4002007411274418080f0007120002d0003413f71200841067472722207418080c400460d011a0b2002200520006b6a22062002490d0320070b2108200a41016b220a044020052100200621022008418080c400470d010c040b0b2008418080c400460d02024002402002450d00200220044f04404100210020022004460d010c020b41002100200220036a2c00004140480d010b200321000b2002200420001b21042000200320001b21030c020b200128020020032004200128020428020c11000021000c020b41808d04411c41cc9a041012000b200b450440200128020020032004200128020428020c11000021000c010b2001410c6a2802002200200320046a2003105d22024b0440200941086a2001200020026b4100106141012100200928020c2202418080c400460d0120092802082001280200220520032004200141046a280200220128020c1100000d01200220052001106221000c010b200128020020032004200128020428020c11000021000b200941106a240020000b140020002802002001200028020428020c1102000b5501027f0240027f02400240200228020041016b0e020103000b200241046a0c010b200120022802044103746a22012802044109470d0120012802000b2802002104410121030b20002004360204200020033602000b85010020012003460440200020022001100f1a0f0b230041306b220024002000200336020420002001360200200041146a41033602002000411c6a41023602002000412c6a4108360200200041dc970436021020004100360208200041083602242000200041206a360218200020003602282000200041046a360220200041086a20041025000b4901017f230041206b22032400200341186a200241106a290200370300200341106a200241086a2902003703002003200229020037030820002001200341086a104c200341206a24000bda08010b7f23004190016b22032400200341003b0184012003410a3602800120034281808080a00137037820032002360274200341003602702003200236026c200320013602682003200236026420034100360260200028020421062000280200210720002802082108200341fc006a2109027f0340024002400240024020032d008501450440200341d8006a2003280268220c200328026c20032802702003280274106a0240024020032802582201450d00200328025c2100034002400240024002400240027f0240024002400240200328027822020440200220096a41016b2d00002104200041084f04402001200141036a417c712202460440200041086b210a410021020c040b200341d0006a200220016b22022000200020024b1b22022001200041cc93041063200341c8006a200420032802502003280254106b20032802484101470d02200328024c21010c050b200341306a200420012000106b2003280234210120032802300c050b41a08d0441214190a0041012000b2002200041086b220a4b0d010b200441818284086c210b0340200241046a22052002490d04200120026a280200200b73220d417f73200d41818284086b71200120056a280200200b732205417f73200541818284086b7172418081828478710d012002200241086a22024b0d072002200a4d0d000b0b200341406b20012000200241fc9304105a200341386a200420032802402003280244106b410020032802384101470d011a2002200328023c6a220120024f0d0041808d04411c418c94041012000b41010b4101460440200141016a2200450d022000200328027022006a22022000490d0320032002360270200220032802782200490d05200341286a2003280268200328026c200220006b2002106a20032802282202450d05200328022c2100200341206a20032802782009410441c0a00410632002200020032802202003280224103c450d05200341186a200328026020032802702200200c106c20032000360260200328021c2102200328021821000c080b200320032802743602700c060b41808d04411c41dc93041012000b41808d04411c41a0a0041012000b41808d04411c41b0a0041012000b41808d04411c41ec93041012000b200341106a2003280268200328026c20032802702003280274106a20032802142100200328021022010d000b0b4100210020032d0085010d00200341013a008501024020032d008401044020032802642101200328026021040c010b2003280264220120032802602204490d0420012004460d010b200341086a200420012003280268106c200328020c2102200328020821000b20000d010b41000c050b20082d0000450d01200741e48e044104200628020c110000450d010c020b41a08d04412141dc9a041012000b2003410a36028c0120082002047f200320002002200241016b418c9704105a2003418c016a410120032802002003280204103c0541000b3a0000200720002002200628020c110000450d010b0b41010b20034190016a24000b4c01037f230041106b220524002002200449200320044b72450440200541086a200320042001105b200528020c2107200528020821060b2000200736020420002006360200200541106a24000b5701027f024002402003450440410021030c010b200141ff017121054101210103402005200220046a2d0000460440200421030c030b2003200441016a2204470d000b0b410021010b20002003360204200020013602000b1400200020012002200341ec9b0441a08d04107a0b5801027f230041206b22022400200128020421032001280200200241186a2000280200220041106a290200370300200241106a200041086a290200370300200220002902003703082003200241086a104c200241206a24000b0b002000280200200110640b1800200128020041f4a7044105200128020428020c1100000b990301037f230041406a22022400200028020021034101210002402001280200220441b08e04410c200141046a280200220128020c1100000d0002402003280208220004402002200036020c200241346a4102360200410121002002413c6a4101360200200241c08e0436023020024100360228200241063602142002200241106a36023820022002410c6a36021020042001200241286a1068450d010c020b20032802002200200328020428020c110a0042c8b5e0cfca86dbd3897f520d002002200036020c200241346a4102360200410121002002413c6a4101360200200241c08e04360230200241003602282002410a3602142002200241106a36023820022002410c6a36021020042001200241286a10680d010b200328020c21002002411c6a4103360200200241246a41033602002002413c6a4108360200200241346a4108360200200241888e043602182002410036021020022000410c6a3602382002200041086a3602302002410236022c200220003602282002200241286a36022020042001200241106a106821000b200241406b240020000b1400200020012002200341a4a90441a0a404107a0b1400200020012002200341aca70441c0a704107a0b4201017f20002f01042103200041003a00042003410171450440200028020020012002102b0f0b200120034108763a00002000280200200141016a200241016b102b0b2601017f230041106b22022400200220003b010e20012002410e6a41021033200241106a24000b3d01017f230041106b22022400200241086a200141808001419ab2041076200228020c21012000200228020836020020002001360204200241106a24000b1400200020012002200341a4a9044180a904107a0b550020002802002200413f4d04402001200041027410180f0b200041ffff004d04402000410274410172200110740f0b200041ffffffff034d04402000410274410272200110140f0b2001410310182000200110140b2601017f230041106b22022400200220003703082001200241086a41081033200241106a24000b2e00200128020020002d000041027422004180b2046a280200200041f0b1046a280200200128020428020c1100000b2800200120024d04402000200220016b3602042000200120036a3602000f0b2005412120041012000b7301017f230041306b220424002004200136020420042000360200200441146a41023602002004411c6a41023602002004412c6a41083602002004200336021020044100360208200441083602242004200441206a3602182004200441046a36022820042004360220200441086a20021025000b0bd2310500418080040b901e617474656d707420746f2073756274726163742077697468206f766572666c6f774661696c656420746f206765742076616c756520696e204d617070696e673a2000000021000100200000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f73746f726167652d342e302e302f7372632f6c617a792f6d617070696e672e72734c0001006000000098000000250000001d09ab11617474656d707420746f206164642077697468206f766572666c6f770b0000000100000001000000030000000b00000001000000010000000c0000004120636f6e7472616374206265696e67206578656375746564206d757374206861766520612076616c6964206163636f756e742069642e00b4140100650000007a0100000e00000054686520657865637574656420636f6e7472616374206d757374206861766520612063616c6c6572207769746820612076616c6964206163636f756e742069642e000000b414010065000000690100000e000000b4140100650000002201000023000000656e636f756e746572656420756e6578706563746564206572726f72a80101001c000000b414010065000000eb000000170000002f686f6d652f6b76696e2f636f6465732f636861696e2f7068616c612f7068616c612d626c6f636b636861696e2f6372617465732f70696e6b2d647269766572732f73797374656d2f6c69622e727300dc0101004f0000001100000005000000636f756c64206e6f742070726f7065726c79206465636f64652073746f7261676520656e747279003c0201002700000073746f7261676520656e7472792077617320656d707479006c0201001700000050696e6b4c6f67676572557067726164696e672073797374656d20636f6e74726163742e2e2e0000960201001c0000004e6f206e65772076657273696f6e206f662073797374656d20636f6e747261637420666f756e642ebc02010028000000436f646520686173682073686f756c642065786973747320686572652e000000dc0101004f000000ae0000001200000053797374656d20636f64652073686f756c642065786973747320686572650000dc0101004f000000b5000000120000004661696c656420746f2063616c6c20646f5f75706772616465206f6e20746865206e65772073797374656d20636f6465dc0101004f000000ba0000001200000053797374656d20636f6e7472616374207570677261646564207375636365737366756c6c792e00008c030100260000005468652073797374656d20636f6e747261637420697320616c72656164792075706772616465642ebc03010028000000557067726164696e672070696e6b20636f6e74726163742072756e74696d652e2e2e0000ec030100220000000b00000004000000040000000d0000000e0000000f000000617474656d707420746f206164642077697468206f766572666c6f7700000000617474656d707420746f206d756c7469706c792077697468206f766572666c6f772f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e7273710401007b0000008a0100001c0000006361706163697479206f766572666c6f77000000fc04010011000000710401007b00000006020000050000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f722f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f666d742e727300005b0501007700000064020000200000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7665632f6d6f642e727300e40501007b000000350700000d000000e40501007b000000a307000009000000617474656d707420746f206164642077697468206f766572666c6f7700000000617474656d707420746f2073756274726163742077697468206f766572666c6f7729696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e64657820697320c206010020000000e2060100120000003a000000bc15010000000000040701000100000004070100010000000b00000000000000010000001000000070616e69636b65642061742027272c203c070100010000003d070100030000003a200000bc150100000000005007010002000000202020202c0a280a282f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6e756d2e727330303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839392f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6d6f642e7273000000af0801007a000000750500000d000000af0801007a00000005060000380000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d656d6368722e7273004c0901007f0000004e0000002f0000004c0901007f0000005a0000001f0000004c0901007f00000063000000090000004c0901007f00000068000000270000004c0901007f000000680000003e00000072616e676520737461727420696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e677468201c0a0100120000002e0a01002200000072616e676520656e6420696e64657820600a0100100000002e0a0100220000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f697465722e7273000000800a01007d000000be050000250000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d6f642e7273100b01007c000000040900001e000000736f7572636520736c696365206c656e67746820282920646f6573206e6f74206d617463682064657374696e6174696f6e20736c696365206c656e67746820289c0b010015000000b10b01002b000000c1060100010000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f636f756e742e7273f40b01007c0000004700000015000000f40b01007c0000004f00000032000000f40b01007c0000005400000011000000f40b01007c0000005a00000009000000f40b01007c0000006400000011000000f40b01007c000000660000000d0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f697465722e727300d00c01007b0000009100000011000000d00c01007b0000004f0200002d0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7472616974732e72730000006c0d01007d000000ca000000130000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f76616c69646174696f6e732e72730000fc0d010082000000e50000001500000001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010041d29e040b330202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030304040404040041909f040bb1052f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e72730000900f01007e000000a101000047000000900f01007e000000b401000020000000900f01007e000000b401000011000000900f01007e000000b8010000260000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f697465722f7472616974732f616363756d2e7273501001008400000095000000010000006d0701007a000000cd010000050000007061696420616e20756e70617961626c65206d657373616765636f756c64206e6f74207265616420696e707574756e61626c6520746f206465636f646520696e707574656e636f756e746572656420756e6b6e6f776e2073656c6563746f72756e61626c6520746f206465636f64652073656c6563746f722f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f616c6c6f632f6c61796f75742e7273006c1101007f0000002f0100001800000000000000617474656d707420746f206164642077697468206f766572666c6f7700000000617474656d707420746f2073756274726163742077697468206f766572666c6f770041d0a4040ba704617474656d707420746f206164642077697468206f766572666c6f77617373657274696f6e206661696c65643a206d6964203c3d2073656c662e6c656e28290abc150100000000008f12010001000000a4170100660000005a0000001c000000a4170100660000005a00000009000000a4170100660000005a00000031000000a4170100660000006500000009000000a417010066000000830000001a000000a4170100660000008d0000002100000045636473615265636f766572794661696c65644c6f6767696e6744697361626c6564556e6b6e6f776e4e6f7443616c6c61626c655f456e646f776d656e74546f6f4c6f775472616e736665724661696c65645f42656c6f7753756273697374656e63655468726573686f6c644b65794e6f74466f756e6443616c6c6565526576657274656443616c6c6565547261707065644465636f6465436f756c644e6f7452656164496e707574000000f91301007e000000820100004700000000000000617474656d707420746f2073756274726163742077697468206f766572666c6f770000003c150100600000007a0000000e0000004572726f722f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032332d30322d30332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f696e6465782e7273004180a9040b8f09617474656d707420746f2073756274726163742077697468206f766572666c6f77000000f91301007e000000900100004f0000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d342e302e302f7372632f656e67696e652f6f6e5f636861696e2f696d706c732e7273000000b4140100650000009c00000011000000b4140100650000009c000000300000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f7061726974792d7363616c652d636f6465632d332e322e322f7372632f636f6465632e727300000000617474656d707420746f206164642077697468206f766572666c6f770b0000000000000001000000110000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d342e302e302f7372632f636861696e5f657874656e73696f6e2e7273656e636f756e7465726564206572726f72207768696c65206465636f64696e6720636861696e20657874656e73696f6e206d6574686f642063616c6c2072657475726e2076616c7565cc1501005f000000b80100001a00000043726f73732d636f6e74726163742063616c6c206661696c656420776974682084160100200000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d342e302e302f7372632f63616c6c2f63616c6c5f6275696c6465722e7273000000ac160100610000007b00000011000000ac1601006100000078000000110000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d342e302e302f7372632f656e67696e652f6f6e5f636861696e2f6578742e7273003017010063000000aa010000140000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d342e302e302f7372632f656e67696e652f6f6e5f636861696e2f6275666665722e72730000a417010066000000c100000037000000a417010066000000c400000009000000bc150100000000007068616c612e70696e6b2e6576656e74436f6e646974696f6e4e6f744d6574436f64654e6f74466f756e644472697665724e6f74466f756e645065726d6973696f6e44656e696564436f6e74726163744465706f73697400190000001c0000001600000014000000190000005311010037110100211101000d110100f410010001020304050607080a010b09000000000100000002000000030000000400000005000000060000000700000008000000090000000c0000000b0000000f0000000e0000000c0000000f0000006d1801005f18010053180100441801","build_info":{"build_mode":"Debug","cargo_contract_version":"2.0.0","rust_toolchain":"nightly-x86_64-unknown-linux-gnu","wasm_opt_settings":{"keep_debug_symbols":false,"optimization_passes":"Z"}}},"contract":{"name":"system","version":"0.1.0","authors":["[your_name] <[your_email]>"]},"spec":{"constructors":[{"args":[],"docs":[],"label":"default","payable":false,"returnType":{"displayName":["ink_primitives","ConstructorResult"],"type":4},"selector":"0xed4b9d1b"}],"docs":[],"events":[],"lang_error":{"displayName":["ink","LangError"],"type":5},"messages":[{"args":[],"docs":[],"label":"System::version","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":6},"selector":"0x87c98a8d"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::grant_admin","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x67612061"},{"args":[{"label":"name","type":{"displayName":["String"],"type":12}},{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::set_driver","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0xaa1e2030"},{"args":[{"label":"name","type":{"displayName":["String"],"type":12}}],"docs":[],"label":"System::get_driver","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":13},"selector":"0x2740cf0a"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}},{"label":"code_hash","type":{"displayName":["pink","Hash"],"type":1}}],"docs":[],"label":"System::deploy_sidevm_to","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x662f4aa4"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::stop_sidevm_at","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x52a0fd6a"},{"args":[{"label":"hook","type":{"displayName":["HookPoint"],"type":15}},{"label":"contract","type":{"displayName":["AccountId"],"type":0}},{"label":"selector","type":{"displayName":["u32"],"type":16}},{"label":"gas_limit","type":{"displayName":["u64"],"type":17}}],"docs":[],"label":"System::set_hook","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x352c6b5c"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}},{"label":"weight","type":{"displayName":["u32"],"type":16}}],"docs":[],"label":"System::set_contract_weight","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x45ec9b18"},{"args":[{"label":"account","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::total_balance_of","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":18},"selector":"0x5a98f226"},{"args":[{"label":"account","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::free_balance_of","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":18},"selector":"0x8a0d40d7"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}}],"docs":[],"label":"System::is_admin","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":20},"selector":"0xf06f050a"},{"args":[],"docs":[],"label":"System::upgrade_system_contract","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0xaf69ca03"},{"args":[{"label":"from_version","type":{"displayName":[],"type":7}}],"docs":[],"label":"System::do_upgrade","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x667e0041"},{"args":[{"label":"version","type":{"displayName":[],"type":22}}],"docs":[" Upgrade the contract runtime",""," Be careful when using this function, it would panic the worker if the"," runtime version is not supported."],"label":"System::upgrade_runtime","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":9},"selector":"0x317f6bf3"},{"args":[{"label":"contract_id","type":{"displayName":["AccountId"],"type":0}},{"label":"deposit","type":{"displayName":["Balance"],"type":19}}],"docs":[],"label":"ContractDeposit::change_deposit","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":23},"selector":"0xa24bcb44"}]},"storage":{"root":{"layout":{"struct":{"fields":[{"layout":{"leaf":{"key":"0x00000000","ty":0}},"name":"owner"},{"layout":{"root":{"layout":{"leaf":{"key":"0x11ab091d","ty":3}},"root_key":"0x11ab091d"}},"name":"administrators"},{"layout":{"root":{"layout":{"leaf":{"key":"0xe69daeed","ty":0}},"root_key":"0xe69daeed"}},"name":"drivers"}],"name":"System"}},"root_key":"0x00000000"}},"types":[{"id":0,"type":{"def":{"composite":{"fields":[{"type":1,"typeName":"[u8; 32]"}]}},"path":["ink_primitives","types","AccountId"]}},{"id":1,"type":{"def":{"array":{"len":32,"type":2}}}},{"id":2,"type":{"def":{"primitive":"u8"}}},{"id":3,"type":{"def":{"tuple":[]}}},{"id":4,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":5}],"path":["Result"]}},{"id":5,"type":{"def":{"variant":{"variants":[{"index":1,"name":"CouldNotReadInput"}]}},"path":["ink_primitives","LangError"]}},{"id":6,"type":{"def":{"variant":{"variants":[{"fields":[{"type":7}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":7},{"name":"E","type":5}],"path":["Result"]}},{"id":7,"type":{"def":{"tuple":[8,8]}}},{"id":8,"type":{"def":{"primitive":"u16"}}},{"id":9,"type":{"def":{"variant":{"variants":[{"fields":[{"type":10}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":10},{"name":"E","type":5}],"path":["Result"]}},{"id":10,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":11}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":11}],"path":["Result"]}},{"id":11,"type":{"def":{"variant":{"variants":[{"index":0,"name":"PermisionDenied"},{"index":1,"name":"DriverNotFound"},{"index":2,"name":"CodeNotFound"},{"index":3,"name":"ConditionNotMet"}]}},"path":["pink_extension","system","Error"]}},{"id":12,"type":{"def":{"primitive":"str"}}},{"id":13,"type":{"def":{"variant":{"variants":[{"fields":[{"type":14}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":14},{"name":"E","type":5}],"path":["Result"]}},{"id":14,"type":{"def":{"variant":{"variants":[{"index":0,"name":"None"},{"fields":[{"type":0}],"index":1,"name":"Some"}]}},"params":[{"name":"T","type":0}],"path":["Option"]}},{"id":15,"type":{"def":{"variant":{"variants":[{"index":0,"name":"OnBlockEnd"}]}},"path":["pink_extension","HookPoint"]}},{"id":16,"type":{"def":{"primitive":"u32"}}},{"id":17,"type":{"def":{"primitive":"u64"}}},{"id":18,"type":{"def":{"variant":{"variants":[{"fields":[{"type":19}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":19},{"name":"E","type":5}],"path":["Result"]}},{"id":19,"type":{"def":{"primitive":"u128"}}},{"id":20,"type":{"def":{"variant":{"variants":[{"fields":[{"type":21}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":21},{"name":"E","type":5}],"path":["Result"]}},{"id":21,"type":{"def":{"primitive":"bool"}}},{"id":22,"type":{"def":{"tuple":[16,16]}}},{"id":23,"type":{"def":{"variant":{"variants":[{"fields":[{"type":24}],"index":0,"name":"Ok"},{"fields":[{"type":5}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":24},{"name":"E","type":5}],"path":["Result"]}},{"id":24,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":25}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":25}],"path":["Result"]}},{"id":25,"type":{"def":{"variant":{"variants":[{"fields":[{"type":12,"typeName":"String"}],"index":0,"name":"Other"},{"fields":[{"type":11,"typeName":"Error"}],"index":1,"name":"SystemError"},{"index":2,"name":"BadOrigin"}]}},"path":["pink_extension","system","DriverError"]}}],"version":"4"} \ No newline at end of file diff --git a/e2e/src/fullstack.js b/e2e/src/fullstack.js index 040ed0b79b..0d8cfe0139 100644 --- a/e2e/src/fullstack.js +++ b/e2e/src/fullstack.js @@ -28,6 +28,8 @@ const sgxLoader = "gramine-sgx"; const CENTS = 10_000_000_000; +console.log(`Testing in ${inSgx?"SGX Hardware":"Software"} mode`); + // TODO: Switch to [instant-seal-consensus](https://substrate.dev/recipes/kitchen-node.html) for faster test describe('A full stack', function () { @@ -750,7 +752,7 @@ describe('A full stack', function () { ); assert.isTrue(await checkUntil(async () => { const { output } = await ContractSystem.query['system::version'](certAlice, {}); - return output?.eq({ Ok: [0, 0xffff] }) + return output?.eq({ Ok: [1, 0xffff] }) }, 4 * 6000), 'Upgrade system failed'); }); @@ -1216,16 +1218,10 @@ function newPRuntime(teePort, tmpPath, name = 'app') { const workDir = path.resolve(`${tmpPath}/${name}`); const sealDir = path.resolve(`${workDir}/data`); if (!fs.existsSync(workDir)) { + fs.cpSync(pRuntimeDir, workDir, { recursive: true }) if (inSgx) { - fs.cpSync(pRuntimeDir, workDir, { recursive: true }) fs.mkdirSync(path.resolve(`${sealDir}/protected_files/`), { recursive: true }); fs.mkdirSync(path.resolve(`${sealDir}/storage_files/`), { recursive: true }); - } else { - fs.mkdirSync(sealDir, { recursive: true }); - const filesMustCopy = ['Rocket.toml', pRuntimeBin]; - filesMustCopy.forEach(f => - fs.copyFileSync(`${pRuntimeDir}/${f}`, `${workDir}/${f}`) - ); } } const args = [ diff --git a/frontend/packages/sdk/src/create.ts b/frontend/packages/sdk/src/create.ts index bff219a6da..15bc351dae 100644 --- a/frontend/packages/sdk/src/create.ts +++ b/frontend/packages/sdk/src/create.ts @@ -350,7 +350,12 @@ export async function create({ id: dest, }, data: { - InkMessage: inputData, + InkMessage: { + payload: inputData, + deposit: 0, + transfer: value, + estimating: false, + }, }, }) .toHex(), diff --git a/frontend/packages/sdk/src/lib/types.ts b/frontend/packages/sdk/src/lib/types.ts index 67a86b7cda..64a9a97689 100644 --- a/frontend/packages/sdk/src/lib/types.ts +++ b/frontend/packages/sdk/src/lib/types.ts @@ -31,6 +31,7 @@ export const types: RegistryTypes = { payload: "Vec", deposit: "u128", transfer: "u128", + estimating: "bool", }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/pallets/phala/src/fat.rs b/pallets/phala/src/fat.rs index 3dcc5f1ff0..7fc1ae0724 100644 --- a/pallets/phala/src/fat.rs +++ b/pallets/phala/src/fat.rs @@ -106,6 +106,10 @@ pub mod pallet { /// The blake2_256 hash of the pink-system contract code. #[pallet::storage] pub type PinkSystemCodeHash = StorageValue<_, H256, OptionQuery>; + /// The pink-runtime version used to deploy new clusters. + /// See also: `phactory::storage::pink_runtime_version`. + #[pallet::storage] + pub type PinkRuntimeVersion = StorageValue<_, (u32, u32)>; /// The next pink-system contract code to be applied from the next block #[pallet::storage] @@ -444,6 +448,17 @@ pub mod pallet { NextPinkSystemCode::::put(code); Ok(()) } + + #[pallet::call_index(7)] + #[pallet::weight(0)] + pub fn set_pink_runtime_version( + origin: OriginFor, + version: (u32, u32), + ) -> DispatchResult { + T::GovernanceOrigin::ensure_origin(origin)?; + PinkRuntimeVersion::::put(version); + Ok(()) + } } impl Pallet @@ -547,15 +562,15 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_now: BlockNumberFor) -> Weight { - // TODO.kevin: use `let else` to early return once the next rustc released - if let Some(next_code) = NextPinkSystemCode::::take() { - let hash: H256 = crate::hashing::blake2_256(&next_code).into(); - PinkSystemCodeHash::::put(hash); - PinkSystemCode::::mutate(|(ver, code)| { - *ver += 1; - *code = next_code; - }); - } + let Some(next_code) = NextPinkSystemCode::::take() else { + return Weight::zero(); + }; + let hash: H256 = crate::hashing::blake2_256(&next_code).into(); + PinkSystemCodeHash::::put(hash); + PinkSystemCode::::mutate(|(ver, code)| { + *ver += 1; + *code = next_code; + }); Weight::zero() } } diff --git a/standalone/crate-version/Cargo.toml b/standalone/crate-version/Cargo.toml new file mode 100644 index 0000000000..e20d8e1632 --- /dev/null +++ b/standalone/crate-version/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "crate-version" +version = "0.1.0" +edition = "2021" + +[dependencies] +toml = "0.7.2" +clap = { version = "4", features = ["derive"] } +serde = { version = "1", features = ["derive"] } diff --git a/standalone/crate-version/src/main.rs b/standalone/crate-version/src/main.rs new file mode 100644 index 0000000000..6eb5e2062d --- /dev/null +++ b/standalone/crate-version/src/main.rs @@ -0,0 +1,32 @@ +use clap::Parser; +use serde::Deserialize; + +#[derive(Parser)] +struct Opts { + #[clap(short = 'n', long, default_value = "2")] + n_parts: usize, + tomlfile: String, +} + +#[derive(Deserialize)] +struct Crate { + package: Package, +} + +#[derive(Deserialize)] +struct Package { + version: String, +} + +fn main() { + let opts = Opts::parse(); + let toml = std::fs::read_to_string(opts.tomlfile).expect("Failed to read Cargo.toml"); + let config: Crate = toml::from_str(&toml).expect("Failed to parse Cargo.toml"); + let ver_parts: Vec<_> = config + .package + .version + .split('.') + .take(opts.n_parts) + .collect(); + println!("{}", ver_parts.join(".")); +} diff --git a/standalone/pruntime/Cargo.lock b/standalone/pruntime/Cargo.lock index 68afebd034..f6b1d87009 100644 --- a/standalone/pruntime/Cargo.lock +++ b/standalone/pruntime/Cargo.lock @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "approx" @@ -390,6 +390,28 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2 1.0.43", + "quote 1.0.21", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.99", + "which", +] + [[package]] name = "bitcoin" version = "0.29.2" @@ -585,30 +607,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" [[package]] -name = "call-trace" -version = "0.4.0" +name = "cc" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2d0c484747681e3e08221fbf222dea7cee8bb9420b20c0d984e4cfda191318" -dependencies = [ - "call-trace-macro", -] +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] -name = "call-trace-macro" -version = "0.4.0" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c8f536dc0324844b15b53b4eb0c6fcb4fd569881ea3488306389d0bcebbef" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "quote 0.6.13", - "syn 0.15.44", + "nom", ] -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - [[package]] name = "cfg-expr" version = "0.10.3" @@ -671,6 +683,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.0.22" @@ -1395,19 +1418,6 @@ dependencies = [ "syn 1.0.99", ] -[[package]] -name = "env_logger" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" @@ -2411,17 +2421,11 @@ dependencies = [ "serde", ] -[[package]] -name = "indexmap-nostd" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" - [[package]] name = "ink" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b4fc39f3bcab7e042becf5c9dbbebc179fff64924025753a5fafa016e8576d" +checksum = "0c0b81ae699fab87b67c4312430e234c1e5b99533aa830dab16cddc9da65cd7a" dependencies = [ "derive_more", "ink_env", @@ -2435,23 +2439,23 @@ dependencies = [ [[package]] name = "ink_allocator" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a54dbbaffb0f97bcae062e628dcdc9da4d3c9044f5a53fb2715a328b07221631" +checksum = "121758652007d56209c7f79af5cc8562b7e869df7ebb72456da79f2a9e72aeea" dependencies = [ "cfg-if", ] [[package]] name = "ink_codegen" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283b022679ef75898db5c28b89388412d93f91cea4f0b1443426901cb391b079" +checksum = "0da21ea8189beef99f92fcea3f07018e3278a0e084b86705d3b5e58c3ee38645" dependencies = [ "blake2", "derive_more", "either", - "env_logger 0.10.0", + "env_logger", "heck 0.4.0", "impl-serde", "ink_ir", @@ -2468,24 +2472,24 @@ dependencies = [ [[package]] name = "ink_engine" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daed9b710cba6f50f1fa0372a7e8a47a35624d84af4ef2c3a8d34d4e96202d1c" +checksum = "d4ec97173506ba6f3cf966a42c0d5f776c2ef843da15854fa1f57d23d2be4ee4" dependencies = [ "blake2", "derive_more", "ink_primitives", "parity-scale-codec", - "secp256k1 0.26.0", + "secp256k1 0.27.0", "sha2 0.10.2", "sha3", ] [[package]] name = "ink_env" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41c6a3f4e740e27449f805ed47f536a35fb254ebcd03d2480014589331cda3e" +checksum = "639a8172a9911fc6f7384623d25ff6f0834d48b16f5c21e4b0eb656b3de1f877" dependencies = [ "arrayref", "blake2", @@ -2502,7 +2506,7 @@ dependencies = [ "paste", "rlibc", "scale-info", - "secp256k1 0.26.0", + "secp256k1 0.27.0", "sha2 0.10.2", "sha3", "static_assertions", @@ -2510,9 +2514,9 @@ dependencies = [ [[package]] name = "ink_ir" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946b940d26e69ded558daafead0979f25f2e9d7e2cf86027f250c3942aa4d0f1" +checksum = "8aeb30e90744ebf9cce7300a1d013ab91e1b84ebc9887ddabd9b7688c6ac20c1" dependencies = [ "blake2", "either", @@ -2524,9 +2528,9 @@ dependencies = [ [[package]] name = "ink_macro" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6642450e6169cfaf81717b1d62b2abae48a6b41d3f70f885b6aeff7bb14ea96b" +checksum = "968f443cf4f177c2cc9d147e33336de19700c8f7e01a6ad5942d9a324e9d3a6c" dependencies = [ "ink_codegen", "ink_ir", @@ -2540,9 +2544,9 @@ dependencies = [ [[package]] name = "ink_metadata" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfcfa666ada5729c7e4d3d986cd196365a2c469459fced4fa31dc6ad87c4d8f" +checksum = "8a8bb193f81ddda8329568ae05786e12a901ea1684c444f780440ecac2bd57b1" dependencies = [ "derive_more", "impl-serde", @@ -2554,18 +2558,18 @@ dependencies = [ [[package]] name = "ink_prelude" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8080235e5ae921975c2c7772fe9959e1b3c92b4d5a1afcfe104f93fb79aa268" +checksum = "050dcae91877df7def5fe4426df22c35d116bb24560e3e40d5650b09c7854061" dependencies = [ "cfg-if", ] [[package]] name = "ink_primitives" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b3f711d857d2de7c08158369cc32a762833ac211a00aac7931992094e25741" +checksum = "55850e661a97f3158fad3309e0188d6f2dcd5fc7de4c19b969c4c66988886f21" dependencies = [ "derive_more", "ink_prelude", @@ -2576,9 +2580,9 @@ dependencies = [ [[package]] name = "ink_storage" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2872a5ea4559433381b2d82b08b6acd33ce934b07a22ce951c6f00483680c950" +checksum = "f376d6fd2137ea2a42a9f08a83b29e309862a020a0841c0cb9a78c40f1e2e6e5" dependencies = [ "array-init", "cfg-if", @@ -2594,16 +2598,15 @@ dependencies = [ [[package]] name = "ink_storage_traits" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c90e11b60233ae5ab877854739da2c380a337cb31b3900cb50328821c0381b6" +checksum = "3a1ff58a3db0bb76b92981236172a3c4d02823996354006f07032e0d3b091024" dependencies = [ "ink_metadata", "ink_prelude", "ink_primitives", "parity-scale-codec", "scale-info", - "syn 1.0.99", ] [[package]] @@ -2724,6 +2727,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "leb128" version = "0.2.5" @@ -2736,6 +2745,16 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libm" version = "0.2.5" @@ -2969,6 +2988,12 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.5.3" @@ -3071,6 +3096,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -3376,57 +3411,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-contracts" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" -dependencies = [ - "bitflags", - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-contracts-primitives", - "pallet-contracts-proc-macro", - "parity-scale-codec", - "rand 0.8.5", - "scale-info", - "serde", - "smallvec", - "sp-api", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "wasm-instrument 0.4.0", - "wasmi 0.20.0", - "wasmparser-nostd", -] - -[[package]] -name = "pallet-contracts-primitives" -version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" -dependencies = [ - "bitflags", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std", - "sp-weights", -] - -[[package]] -name = "pallet-contracts-proc-macro" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#1837f423b494254e1d27834b1c9da34b2c0c2375" -dependencies = [ - "proc-macro2 1.0.43", - "quote 1.0.21", - "syn 1.0.99", -] - [[package]] name = "pallet-democracy" version = "4.0.0-dev" @@ -4177,6 +4161,12 @@ dependencies = [ "syn 1.0.99", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -4252,6 +4242,7 @@ dependencies = [ "bitflags", "chrono", "derive_more", + "environmental", "finality-grandpa", "fixed", "fixed-macro", @@ -4279,7 +4270,8 @@ dependencies = [ "phala-serde-more", "phala-trie-storage", "phala-types", - "pink", + "pink-extension-runtime", + "pink-runner", "prpc", "rand 0.8.5", "regex", @@ -4317,6 +4309,7 @@ dependencies = [ "log", "parity-scale-codec", "phala-crypto", + "phala-git-revision", "phala-mq", "phala-node-runtime", "phala-trie-storage", @@ -4372,6 +4365,10 @@ dependencies = [ "typenum", ] +[[package]] +name = "phala-git-revision" +version = "0.1.0" + [[package]] name = "phala-mq" version = "0.1.0" @@ -4518,6 +4515,14 @@ dependencies = [ "rocket", ] +[[package]] +name = "phala-sanitized-logger" +version = "0.1.0" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "phala-scheduler" version = "0.1.0" @@ -4638,46 +4643,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pink" +name = "pink-capi" version = "0.1.0" dependencies = [ - "call-trace", - "environmental", - "frame-support", - "frame-system", - "hex", - "impl-serde", - "log", - "pallet-balances", - "pallet-contracts", - "pallet-contracts-primitives", - "pallet-contracts-proc-macro", - "pallet-insecure-randomness-collective-flip", - "pallet-timestamp", + "bindgen", "parity-scale-codec", - "parity-wasm", - "paste", - "phala-crypto", - "phala-serde-more", - "phala-trie-storage", - "phala-types", "pink-extension", - "pink-extension-runtime", - "reqwest", - "reqwest-env-proxy", - "scale-info", - "serde", - "serde_json", - "sha2 0.10.2", + "pink-macro", "sp-core", - "sp-externalities", - "sp-io", "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-trie", - "wasmi-validation", - "wat", ] [[package]] @@ -4720,6 +4694,32 @@ dependencies = [ "sp-runtime-interface", ] +[[package]] +name = "pink-macro" +version = "0.1.1" +dependencies = [ + "heck 0.4.0", + "proc-macro-crate", + "proc-macro2 1.0.43", + "syn 1.0.99", +] + +[[package]] +name = "pink-runner" +version = "0.1.0" +dependencies = [ + "environmental", + "im", + "libc", + "log", + "once_cell", + "phala-crypto", + "pink-capi", + "pink-extension-runtime", + "serde", + "sp-weights", +] + [[package]] name = "pkcs8" version = "0.9.0" @@ -4991,7 +4991,6 @@ dependencies = [ "base64", "clap", "colored", - "env_logger 0.9.0", "hex_fmt", "lazy_static", "libc", @@ -5003,6 +5002,7 @@ dependencies = [ "phactory-pal", "phala-allocator", "phala-rocket-middleware", + "phala-sanitized-logger", "phala-types", "reqwest", "reqwest-env-proxy", @@ -5777,11 +5777,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "secp256k1-sys 0.8.0", + "secp256k1-sys 0.8.1", ] [[package]] @@ -5795,9 +5795,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642a62736682fdd8c71da0eb273e453c8ac74e33b9fb310e22ba5b03ec7651ff" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" dependencies = [ "cc", ] @@ -5985,6 +5985,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "sidevm-env" version = "0.1.7" @@ -6025,7 +6031,7 @@ dependencies = [ "tokio", "tokio-proxy", "tokio-rustls", - "wasm-instrument 0.3.0", + "wasm-instrument", "wasmer", "wasmer-compiler-singlepass", "wasmer-middlewares", @@ -6701,7 +6707,7 @@ dependencies = [ "log", "parity-scale-codec", "sp-std", - "wasmi 0.13.2", + "wasmi", "wasmtime", ] @@ -7718,15 +7724,6 @@ dependencies = [ "parity-wasm", ] -[[package]] -name = "wasm-instrument" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a47ecb37b9734d1085eaa5ae1a81e60801fd8c28d4cabdd8aedb982021918bc" -dependencies = [ - "parity-wasm", -] - [[package]] name = "wasmer" version = "3.0.0" @@ -7975,19 +7972,7 @@ checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" dependencies = [ "parity-wasm", "wasmi-validation", - "wasmi_core 0.2.1", -] - -[[package]] -name = "wasmi" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" -dependencies = [ - "spin 0.9.4", - "wasmi_arena", - "wasmi_core 0.5.0", - "wasmparser-nostd", + "wasmi_core", ] [[package]] @@ -7999,12 +7984,6 @@ dependencies = [ "parity-wasm", ] -[[package]] -name = "wasmi_arena" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ea379cbb0b41f3a9f0bf7b47036d036aae7f43383d8cc487d4deccf40dee0a" - [[package]] name = "wasmi_core" version = "0.2.1" @@ -8018,17 +7997,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "wasmi_core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5bf998ab792be85e20e771fe14182b4295571ad1d4f89d3da521c1bef5f597a" -dependencies = [ - "downcast-rs", - "libm", - "num-traits", -] - [[package]] name = "wasmparser" version = "0.83.0" @@ -8045,15 +8013,6 @@ dependencies = [ "url", ] -[[package]] -name = "wasmparser-nostd" -version = "0.91.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c37f310b5a62bfd5ae7c0f1d8e6f98af16a5d6d84ba764e9c36439ec14e318b" -dependencies = [ - "indexmap-nostd", -] - [[package]] name = "wasmtime" version = "6.0.1" diff --git a/standalone/pruntime/Cargo.toml b/standalone/pruntime/Cargo.toml index a3b538031b..55ef069519 100644 --- a/standalone/pruntime/Cargo.toml +++ b/standalone/pruntime/Cargo.toml @@ -27,7 +27,7 @@ serde_json = "1.0" base64 = "0.13.0" -env_logger = { version = "0.9.0", features = ["termcolor"] } +phala-sanitized-logger = { path = "../../crates/phala-sanitized-logger" } lazy_static = { version = "1.4.0", default-features = false } parity-scale-codec = { version = "3.3", default-features = false } serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/standalone/pruntime/Makefile b/standalone/pruntime/Makefile index 1520620dbb..972bb54f61 100644 --- a/standalone/pruntime/Makefile +++ b/standalone/pruntime/Makefile @@ -1,8 +1,22 @@ SGX_MODE ?= SW -.PHONY: all clean -ifeq ($(SGX_MODE),SW) -all: bin/Rocket.toml bin/app +include config.mk + +.PHONY: all clean run + +all: bin/Rocket.toml bin/app ${PINK_RUNTIME_DIST} + +run: + ./bin/app -c 0 + +${PINK_RUNTIME_DIST}: ${PINK_RUNTIME} + cp $? $@ + cp $@ target/release/ + strip --strip-all --keep-symbol=__pink_runtime_init $@ + +.PHONY: ${PINK_RUNTIME} +${PINK_RUNTIME}: + cd ${PINK_RUNTIME_DIR} && cargo build --release bin/app: bin/pruntime cd bin && ln -sf pruntime app @@ -20,12 +34,6 @@ target/release/pruntime: clean: rm -rf bin/* cargo clean -else -all: - make -C gramine-build -clean: - make clean -C gramine-build -endif .PHONY: clippy clippy: diff --git a/standalone/pruntime/config.mk b/standalone/pruntime/config.mk new file mode 100644 index 0000000000..015b8ca049 --- /dev/null +++ b/standalone/pruntime/config.mk @@ -0,0 +1,9 @@ +BUILD_DIR := $(dir $(lastword $(MAKEFILE_LIST))) + +PINK_RUNTIME_DIR = ${BUILD_DIR}/../../crates/pink/runtime +PINK_RUNTIME_VERSION = $(shell ${BUILD_DIR}/crate-version -n 2 ${PINK_RUNTIME_DIR}/Cargo.toml) +PINK_RUNTIME = ${BUILD_DIR}/../../target/release/libpink.so +PINK_RUNTIME_DIST = ${BUILD_DIR}/bin/libpink.so.${PINK_RUNTIME_VERSION} + +$(info PINK_RUNTIME_VERSION: ${PINK_RUNTIME_VERSION}) +$(info PINK_RUNTIME_DIST: ${PINK_RUNTIME_DIST}) diff --git a/standalone/pruntime/crate-version b/standalone/pruntime/crate-version new file mode 100755 index 0000000000..d6ddf53e64 Binary files /dev/null and b/standalone/pruntime/crate-version differ diff --git a/standalone/pruntime/gramine-build/Makefile b/standalone/pruntime/gramine-build/Makefile index 79b7be0f8c..44825c9fd5 100644 --- a/standalone/pruntime/gramine-build/Makefile +++ b/standalone/pruntime/gramine-build/Makefile @@ -1,6 +1,8 @@ SGX_SIGNER_KEY ?= ./private.dev.pem SGX ?= 1 +include ../config.mk + ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine) CFLAGS = -Wall -Wextra @@ -22,6 +24,7 @@ GRAMINE_RUNTIME_DIR ?= $(shell ./gramine-dir runtime) RUNTIME_DIR = cruntime LIBOS_BASENAME ?= $(shell basename ${GRAMINE_LIBOS}) LIBOS ?= ${RUNTIME_DIR}/${LIBOS_BASENAME} +PINK_RUNTIME_DIST_DIR = ${RUNTIME_DIR}/pink-runtime ifeq ($(USE_MUSL),1) BIN_FILE = ../target/x86_64-unknown-linux-musl/release/${BIN_NAME} @@ -50,10 +53,12 @@ endif .PHONY: ${BIN_FILE} ${BIN_FILE}: - cargo build --release ${CARGO_ARGS} + make -C .. ${BIN_NAME}: ${BIN_FILE} cp ${BIN_FILE} ${BIN_NAME} + mkdir -p ${PINK_RUNTIME_DIST_DIR} + cp ${PINK_RUNTIME_DIST} ${PINK_RUNTIME_DIST_DIR} ${BIN_NAME}.manifest: ${BIN_NAME}.manifest.template gramine-manifest \ @@ -63,6 +68,7 @@ ${BIN_NAME}.manifest: ${BIN_NAME}.manifest.template -Dseal_dir=${PRUNTIME_SEAL_DIR} \ -Dstorage_dir=${PRUNTIME_STORAGE_DIR} \ -Dlibdir=${RUNTIME_DIR}/lib/ \ + -Dpink_runtime_dir=${PINK_RUNTIME_DIST_DIR}/ \ -Dlibos=${LIBOS} \ -Dra_method=${RA_METHOD} \ $< $@ diff --git a/standalone/pruntime/gramine-build/pruntime.manifest.template b/standalone/pruntime/gramine-build/pruntime.manifest.template index 9cefbff4c8..18009c3404 100644 --- a/standalone/pruntime/gramine-build/pruntime.manifest.template +++ b/standalone/pruntime/gramine-build/pruntime.manifest.template @@ -1,3 +1,5 @@ +{% set pink_runtime_mount_dir = "/pink-runtime" %} + [libos] entrypoint = "pruntime" @@ -14,6 +16,7 @@ insecure__allow_eventfd = true LD_LIBRARY_PATH = "/lib:/lib/x86_64-linux-gnu" MALLOC_ARENA_MAX = "1" ROCKET_WORKERS = "8" +PINK_RUNTIME_PATH = "{{ pink_runtime_mount_dir }}" RUST_LOG = { passthrough = true } all_proxy = { passthrough = true } i2p_proxy = { passthrough = true } @@ -39,6 +42,10 @@ type = "chroot" path = "/etc" uri = "file:/etc" +[[fs.mounts]] +type = "chroot" +path = "{{ pink_runtime_mount_dir }}" +uri = "file:{{ pink_runtime_dir }}" [sgx] debug = false @@ -56,6 +63,7 @@ trusted_files = [ "file:{{ libos }}", "file:pruntime", "file:{{ libdir }}", + "file:{{ pink_runtime_dir }}", ] allowed_files = [ diff --git a/standalone/pruntime/src/main.rs b/standalone/pruntime/src/main.rs index 7379d1877b..5186c5a387 100644 --- a/standalone/pruntime/src/main.rs +++ b/standalone/pruntime/src/main.rs @@ -11,7 +11,7 @@ use log::{error, info}; use phactory_api::ecall_args::{git_revision, InitArgs}; mod handover; -mod logger; +use phala_sanitized_logger as logger; #[derive(Parser, Debug, Clone)] #[clap(about = "The Phala TEE worker app.", version, author)] @@ -137,7 +137,7 @@ async fn main() -> Result<(), rocket::Error> { storage_path: storage_path.into(), init_bench: args.init_bench, version: env!("CARGO_PKG_VERSION").into(), - git_revision: git_revision(), + git_revision: git_revision().to_string(), enable_checkpoint: !args.disable_checkpoint, checkpoint_interval: args.checkpoint_interval, remove_corrupted_checkpoint: args.remove_corrupted_checkpoint,