diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9637dff..6d98b6e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: push: branches: [ main, staging, trying ] pull_request: - branches: [ main, 'testnet_*' ] + branches: [ main, 'next_breaking_update' ] merge_group: branches: [ main ] diff --git a/Cargo.lock b/Cargo.lock index edd292b2..7ab393ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.7.7" @@ -67,7 +73,7 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "as-ffi-bindings" version = "0.2.5" -source = "git+https://github.com/massalabs/as-ffi-bindings.git?tag=v0.5.5#a1c338eedc68502e85995123a384261a90cbb409" +source = "git+https://github.com/massalabs/as-ffi-bindings.git?branch=feature/update_wasmer_4_3_4#c0afa48488418a66d872a8c51bc7fa30fe4f8a11" dependencies = [ "anyhow", "wasmer", @@ -89,7 +95,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.1", "object 0.32.1", "rustc-demangle", ] @@ -100,6 +106,34 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bindgen" +version = "0.63.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which 4.4.2", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -182,6 +216,18 @@ name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +dependencies = [ + "serde", +] [[package]] name = "cc" @@ -192,6 +238,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -210,6 +265,17 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -383,14 +449,38 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -403,7 +493,18 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", ] [[package]] @@ -412,9 +513,9 @@ version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -430,6 +531,20 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "dashmap" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "derivative" version = "2.2.0" @@ -441,6 +556,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -459,9 +605,24 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] +[[package]] +name = "document-features" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +dependencies = [ + "litrs", +] + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "dynasm" version = "1.2.3" @@ -494,6 +655,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "enum-iterator" version = "0.7.0" @@ -529,10 +699,10 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -563,12 +733,34 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "filetime" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "fixedbitset" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + [[package]] name = "fnv" version = "1.0.7" @@ -703,13 +895,15 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -736,13 +930,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "hashbrown" -version = "0.11.2" +name = "half" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -765,6 +956,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "home" version = "0.5.5" @@ -785,7 +982,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.51.1", ] [[package]] @@ -821,16 +1018,18 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] name = "indexmap" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] @@ -872,6 +1071,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" @@ -880,9 +1085,30 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.48.5", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.5.3", +] [[package]] name = "linux-raw-sys" @@ -890,6 +1116,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.11" @@ -927,10 +1159,10 @@ dependencies = [ ] [[package]] -name = "mach" -version = "0.3.2" +name = "mach2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] @@ -953,7 +1185,7 @@ version = "0.10.0" dependencies = [ "anyhow", "as-ffi-bindings", - "base64", + "base64 0.21.5", "bs58", "chrono", "displaydoc", @@ -961,6 +1193,7 @@ dependencies = [ "loupe", "massa-proto-rs", "more-asserts 0.3.1", + "num-format", "num_enum", "parking_lot", "prost", @@ -973,6 +1206,7 @@ dependencies = [ "serial_test", "sha2", "sha3", + "sysinfo", "thiserror", "tracing", "wasmer", @@ -1016,6 +1250,12 @@ dependencies = [ "autocfg", ] +[[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.7.1" @@ -1025,6 +1265,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "more-asserts" version = "0.2.2" @@ -1043,6 +1292,51 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[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 = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "cfg-if", + "encoding_rs", + "itoa", + "lazy_static", + "libc", + "num-format-windows", + "widestring", + "winapi", +] + +[[package]] +name = "num-format-windows" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1e07f67225c1eb911d16c2f72492669c1fb08212dbfaa1f6cfbeb119152cfa" +dependencies = [ + "bindgen", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1070,17 +1364,17 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] name = "object" -version = "0.28.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown 0.11.2", + "hashbrown 0.12.3", "indexmap 1.9.3", "memchr", ] @@ -1118,11 +1412,17 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] +[[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.3.1" @@ -1136,7 +1436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.4.0", ] [[package]] @@ -1164,17 +1464,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "toml_datetime", - "toml_edit", + "toml_edit 0.20.2", ] [[package]] @@ -1203,9 +1502,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1237,7 +1536,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.40", + "syn 2.0.75", "tempfile", "which 4.4.2", ] @@ -1252,7 +1551,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -1286,9 +1585,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1358,6 +1657,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.4.1", +] + [[package]] name = "regalloc2" version = "0.5.1" @@ -1401,14 +1709,14 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "region" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" dependencies = [ "bitflags 1.3.2", "libc", - "mach", - "winapi", + "mach2", + "windows-sys 0.52.0", ] [[package]] @@ -1465,11 +1773,17 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.4.1", "errno", @@ -1490,6 +1804,31 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.75", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1508,11 +1847,20 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + [[package]] name = "serde" -version = "1.0.193" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] @@ -1528,15 +1876,36 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", ] [[package]] @@ -1550,13 +1919,35 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.4.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serial_test" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" dependencies = [ - "dashmap", + "dashmap 5.5.3", "futures", "lazy_static", "log", @@ -1572,7 +1963,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -1598,14 +1989,20 @@ dependencies = [ [[package]] name = "shared-buffer" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf61602ee61e2f83dd016b3e6387245291cf728ea071c378b35088125b4d995" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" dependencies = [ "bytes", "memmap2 0.6.2", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "simdutf8" version = "0.1.4" @@ -1639,6 +2036,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.109" @@ -1652,21 +2055,46 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.40" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sysinfo" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" +dependencies = [ + "core-foundation-sys", + "libc", + "memchr", + "ntapi", + "rayon", + "windows", +] + [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.12" @@ -1681,7 +2109,7 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.4.1", "rustix", "windows-sys 0.48.0", ] @@ -1703,7 +2131,7 @@ checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -1721,11 +2149,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.20", +] + [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -1733,9 +2176,22 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.4.0", + "toml_datetime", + "winnow 0.5.28", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap 2.4.0", + "serde", + "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.18", ] [[package]] @@ -1748,7 +2204,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -1770,7 +2226,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", ] [[package]] @@ -1815,6 +2271,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.0" @@ -1824,6 +2286,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1865,7 +2328,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", "wasm-bindgen-shared", ] @@ -1887,7 +2350,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1909,9 +2372,9 @@ dependencies = [ [[package]] name = "wasmer" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce45cc009177ca345a6d041f9062305ad467d15e7d41494f5b81ab46d62d7a58" +checksum = "3be5fa49d7d97f83e095f090dcc178d923f2970f588443283cd7a94974ab8cbe" dependencies = [ "bytes", "cfg-if", @@ -1925,6 +2388,7 @@ dependencies = [ "shared-buffer", "target-lexicon", "thiserror", + "tracing", "wasm-bindgen", "wasmer-compiler", "wasmer-compiler-cranelift", @@ -1932,14 +2396,14 @@ dependencies = [ "wasmer-types", "wasmer-vm", "wat", - "winapi", + "windows-sys 0.59.0", ] [[package]] name = "wasmer-compiler" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e044f6140c844602b920deb4526aea3cc9c0d7cf23f00730bb9b2034669f522a" +checksum = "9696a040f935903db440078cd287c0288ab152394122de442fdd21b3eaa8cd2c" dependencies = [ "backtrace", "bytes", @@ -1948,6 +2412,7 @@ dependencies = [ "enumset", "lazy_static", "leb128", + "libc", "memmap2 0.5.10", "more-asserts 0.2.2", "region", @@ -1960,14 +2425,15 @@ dependencies = [ "wasmer-types", "wasmer-vm", "wasmparser", - "winapi", + "windows-sys 0.59.0", + "xxhash-rust", ] [[package]] name = "wasmer-compiler-cranelift" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ce02358eb44a149d791c1d6648fb7f8b2f99cd55e3c4eef0474653ec8cc889" +checksum = "c5959da148d41a5870d1b18a880e19353add47c0ca95e510061275ea467b6b44" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1984,9 +2450,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-singlepass" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45dc438250a91d6c0a57912714f8b3b899a0f5bb3a5f1eae5bc97858b7a006a9" +checksum = "5fcaa0fa11a5680268d85b17dc032ec90b63138caa66c8484b8f8f6923d7619f" dependencies = [ "byteorder", "dynasm", @@ -2001,11 +2467,33 @@ dependencies = [ "wasmer-types", ] +[[package]] +name = "wasmer-config" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4a632496950fde9ad821e195ef1a301440076f7c7d80de55239a140359bcbd" +dependencies = [ + "anyhow", + "bytesize", + "derive_builder", + "hex", + "indexmap 2.4.0", + "schemars", + "semver", + "serde", + "serde_cbor", + "serde_json", + "serde_yaml", + "thiserror", + "toml", + "url", +] + [[package]] name = "wasmer-derive" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c782d80401edb08e1eba206733f7859db6c997fc5a7f5fb44edc3ecd801468f6" +checksum = "6f448efbe12d656ba96d997c9e338f15cd80934c81f2286c2730cb9224d4e41d" dependencies = [ "proc-macro-error", "proc-macro2", @@ -2015,9 +2503,9 @@ dependencies = [ [[package]] name = "wasmer-middlewares" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d4f27f76b7b5325476c8851f34920ae562ef0de3c830fdbc4feafff6782187" +checksum = "c4a3c1a7474e5abd75fe6bde4d34fee77c22261b45f157bb769d4a297749463c" dependencies = [ "wasmer", "wasmer-types", @@ -2026,67 +2514,73 @@ dependencies = [ [[package]] name = "wasmer-object" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66dc76ddf602e15266c6cc792dde7592cb3fcfe2bf55b792c51bb400d7a26c0b" +checksum = "70dabd8c3abd7b72a89052f0dd1991aeeabed2a783d474f6c06bca42c8ce73c4" dependencies = [ - "object 0.28.4", + "object 0.29.0", "thiserror", "wasmer-types", ] [[package]] name = "wasmer-types" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd09e80d4d74bb9fd0ce6c3c106b1ceba1a050f9948db9d9b78ae53c172d6157" +checksum = "c8b383ef63005176be3bc2056d3b4078ae1497b324f573d79acbf81036f1c9ec" dependencies = [ "bytecheck", "enum-iterator", "enumset", + "getrandom", + "hex", "indexmap 1.9.3", "more-asserts 0.2.2", "rkyv", + "sha2", "target-lexicon", "thiserror", + "webc", + "xxhash-rust", ] [[package]] name = "wasmer-vm" -version = "4.2.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdcd8a4fd36414a7b6a003dbfbd32393bce3e155d715dd877c05c1b7a41d224d" +checksum = "3c371597ec33248e775de641c7a475173fb60f2b5ea085c74d34cee9fad06b83" dependencies = [ "backtrace", "cc", "cfg-if", "corosensei", "crossbeam-queue", - "dashmap", + "dashmap 6.0.1", "derivative", "enum-iterator", "fnv", "indexmap 1.9.3", "lazy_static", "libc", - "mach", + "mach2", "memoffset", "more-asserts 0.2.2", "region", "scopeguard", "thiserror", "wasmer-types", - "winapi", + "windows-sys 0.59.0", ] [[package]] name = "wasmparser" -version = "0.95.0" +version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "indexmap 1.9.3", - "url", + "bitflags 2.4.1", + "indexmap 2.4.0", + "semver", ] [[package]] @@ -2110,6 +2604,35 @@ dependencies = [ "wast", ] +[[package]] +name = "webc" +version = "6.0.0-rc2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3e2ccb43d303c5bd48f31db7a129481a9aaa5343d623f92951751df190df81" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes", + "cfg-if", + "document-features", + "flate2", + "indexmap 1.9.3", + "libc", + "once_cell", + "semver", + "serde", + "serde_cbor", + "serde_json", + "sha2", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml", + "url", + "wasmer-config", +] + [[package]] name = "which" version = "4.4.2" @@ -2135,6 +2658,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -2157,6 +2686,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.51.1" @@ -2166,6 +2705,49 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.33.0" @@ -2194,7 +2776,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -2214,17 +2805,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2235,9 +2827,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -2253,9 +2845,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -2271,9 +2863,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -2289,9 +2887,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -2307,9 +2905,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -2319,9 +2917,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -2337,9 +2935,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -2350,6 +2948,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "wyz" version = "0.5.1" @@ -2358,3 +2965,20 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" diff --git a/Cargo.toml b/Cargo.toml index 24950cbe..c5e32d9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow = "1.0" -as-ffi-bindings = { git = "https://github.com/massalabs/as-ffi-bindings.git", tag = "v0.5.5" } +as-ffi-bindings = { git = "https://github.com/massalabs/as-ffi-bindings.git", branch = "feature/update_wasmer_4_3_4" } base64 = "=0.21" chrono = { version = "=0.4", features = ["clock"], default-features = false } displaydoc = "0.2" @@ -27,15 +27,17 @@ sha2 = "=0.10.8" sha3 = "=0.10.8" thiserror = "1.0" tracing = "0.1" -wasmer = { version = "=4.2.4", features = ["static-artifact-create"] } -wasmer-compiler-cranelift = "=4.2.4" -wasmer-compiler-singlepass = "=4.2.4" -wasmer-middlewares = "=4.2.4" -wasmer-types = "=4.2.4" +wasmer = { version = "=4.3.6", features = ["static-artifact-create"] } +wasmer-compiler-cranelift = "=4.3.6" +wasmer-compiler-singlepass = "=4.3.6" +wasmer-middlewares = "=4.3.6" +wasmer-types = "=4.3.6" rust_decimal = { version = "1.32", default-features = false, optional = true } [dev-dependencies] bs58 = { version = "=0.5.0", features = ["check"] } +sysinfo = "0.31" +num-format = { version = "0.4.3", features = ["with-system-locale"] } [build-dependencies] serde = "=1.0" diff --git a/src/as_execution/common.rs b/src/as_execution/common.rs index 945faff8..dd48c62d 100644 --- a/src/as_execution/common.rs +++ b/src/as_execution/common.rs @@ -45,6 +45,7 @@ pub(crate) fn call_module( param, remaining_gas, env.get_gas_costs(), + env.get_condom_limits(), )?; if cfg!(not(feature = "gas_calibration")) { set_remaining_points(&env, ctx, resp.remaining_gas)?; @@ -79,6 +80,7 @@ pub(crate) fn local_call( param, remaining_gas, gas_costs, + env.get_condom_limits(), )?; if cfg!(not(feature = "gas_calibration")) { set_remaining_points(&env, ctx, resp.remaining_gas)?; diff --git a/src/as_execution/context.rs b/src/as_execution/context.rs index 1628cc83..69d45d4a 100644 --- a/src/as_execution/context.rs +++ b/src/as_execution/context.rs @@ -1,7 +1,7 @@ use super::abi::*; use super::env::{get_remaining_points, set_remaining_points, ASEnv, Metered}; use crate::types::Response; -use crate::{GasCosts, Interface}; +use crate::{CondomLimits, GasCosts, Interface}; use anyhow::{bail, Result}; use as_ffi_bindings::{BufferPtr, Read as ASRead, Write as ASWrite}; use wasmer::{ @@ -26,9 +26,10 @@ impl ASContext { interface: &dyn Interface, binary_module: Module, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> Self { Self { - env: ASEnv::new(interface, gas_costs), + env: ASEnv::new(interface, gas_costs, condom_limits), module: binary_module, } } diff --git a/src/as_execution/env.rs b/src/as_execution/env.rs index f8370946..70ac0760 100644 --- a/src/as_execution/env.rs +++ b/src/as_execution/env.rs @@ -1,5 +1,5 @@ use super::{abi_bail, ABIResult}; -use crate::types::Interface; +use crate::{types::Interface, CondomLimits}; #[cfg(feature = "execution-trace")] use crate::types::AbiTrace; @@ -32,6 +32,8 @@ pub struct ASEnv { pub exhausted_points: Option, /// Gas costs of different execution operations. gas_costs: GasCosts, + /// Maximum number of exports + condom_limits: CondomLimits, /// Initially added for gas calibration but unused at the moment. param_size_map: HashMap>, #[cfg(feature = "execution-trace")] @@ -39,7 +41,11 @@ pub struct ASEnv { } impl ASEnv { - pub fn new(interface: &dyn Interface, gas_costs: GasCosts) -> Self { + pub fn new( + interface: &dyn Interface, + gas_costs: GasCosts, + condom_limits: CondomLimits, + ) -> Self { Self { ffi_env: Default::default(), abi_enabled: Arc::new(AtomicBool::new(false)), @@ -48,6 +54,7 @@ impl ASEnv { remaining_points: None, exhausted_points: None, param_size_map: Default::default(), + condom_limits, #[cfg(feature = "execution-trace")] trace: Default::default(), } @@ -76,6 +83,9 @@ impl Metered for ASEnv { fn get_gas_costs(&self) -> GasCosts { self.gas_costs.clone() } + fn get_condom_limits(&self) -> CondomLimits { + self.condom_limits.clone() + } } /// Trait describing a metered object. @@ -86,6 +96,7 @@ pub(crate) trait Metered { fn get_remaining_points(&self) -> Option<&Global>; fn get_gc_param(&self, name: &str) -> Option<&Global>; fn get_gas_costs(&self) -> GasCosts; + fn get_condom_limits(&self) -> CondomLimits; } /// Get remaining metering points. diff --git a/src/as_execution/mod.rs b/src/as_execution/mod.rs index d48343c7..4a87752c 100644 --- a/src/as_execution/mod.rs +++ b/src/as_execution/mod.rs @@ -6,16 +6,21 @@ mod error; use crate::error::{exec_bail, VMResult}; use crate::execution::Compiler; +use crate::middlewares::condom::CondomMiddleware; use crate::middlewares::gas_calibration::{get_gas_calibration_result, GasCalibrationResult}; use crate::middlewares::{dumper::Dumper, gas_calibration::GasCalibration}; use crate::settings::max_number_of_pages; use crate::tunable_memory::LimitingTunables; -use crate::{GasCosts, Interface, Response}; +use crate::{CondomLimits, GasCosts, Interface, Response}; use anyhow::Result; use std::sync::Arc; use wasmer::NativeEngineExt; -use wasmer::{wasmparser::Operator, BaseTunables, Engine, EngineBuilder, Pages, Target}; -use wasmer::{CompilerConfig, Cranelift, Features, Module, Store}; +use wasmer::{sys::Features, CompilerConfig, Cranelift, Module, Store}; +use wasmer::{ + sys::{BaseTunables, EngineBuilder}, + wasmparser::Operator, + Engine, Pages, Target, +}; use wasmer_compiler_singlepass::Singlepass; use wasmer_middlewares::metering::MeteringPoints; use wasmer_middlewares::{metering, Metering}; @@ -39,10 +44,11 @@ impl ASModule { limit: u64, gas_costs: GasCosts, compiler: Compiler, + condom_limits: CondomLimits, ) -> Result { let engine = match compiler { - Compiler::CL => init_cl_engine(limit, gas_costs), - Compiler::SP => init_sp_engine(limit, gas_costs), + Compiler::CL => init_cl_engine(limit, gas_costs, condom_limits), + Compiler::SP => init_sp_engine(limit, gas_costs, condom_limits), }; Ok(Self { binary_module: Module::new(&engine, bytecode)?, @@ -61,9 +67,14 @@ impl ASModule { } } - pub fn deserialize(ser_module: &[u8], limit: u64, gas_costs: GasCosts) -> Result { + pub fn deserialize( + ser_module: &[u8], + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, + ) -> Result { // Deserialization is only meant for Cranelift modules - let engine = init_cl_engine(limit, gas_costs); + let engine = init_cl_engine(limit, gas_costs, condom_limits); let store = Store::new(engine.clone()); // Unsafe because code injection is possible // That's not an issue because we only deserialize modules we have @@ -111,7 +122,11 @@ const FEATURES: Features = Features { extended_const: false, // experimental }; -pub(crate) fn init_sp_engine(limit: u64, gas_costs: GasCosts) -> Engine { +pub(crate) fn init_sp_engine( + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, +) -> Engine { // Singlepass is used to compile arbitrary bytecode. // // Reference: @@ -121,6 +136,9 @@ pub(crate) fn init_sp_engine(limit: u64, gas_costs: GasCosts) -> Engine { // Canonicalize NaN compiler_config.canonicalize_nans(true); + // Add condom middleware + compiler_config.push_middleware(Arc::new(CondomMiddleware::new(condom_limits))); + if cfg!(feature = "gas_calibration") { // Add gas calibration middleware let gas_calibration = Arc::new(GasCalibration::new()); @@ -145,7 +163,11 @@ pub(crate) fn init_sp_engine(limit: u64, gas_costs: GasCosts) -> Engine { engine } -pub(crate) fn init_cl_engine(limit: u64, gas_costs: GasCosts) -> Engine { +pub(crate) fn init_cl_engine( + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, +) -> Engine { // Cranelift is used to compile bytecode that will be cached. // // Reference: @@ -155,6 +177,9 @@ pub(crate) fn init_cl_engine(limit: u64, gas_costs: GasCosts) -> Engine { // Canonicalize NaN compiler_config.canonicalize_nans(true); + // Add condom middleware + compiler_config.push_middleware(Arc::new(CondomMiddleware::new(condom_limits))); + if cfg!(feature = "gas_calibration") { // Add gas calibration middleware let gas_calibration = Arc::new(GasCalibration::new()); @@ -203,13 +228,19 @@ pub(crate) fn exec_as_module( param: &[u8], limit: u64, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> VMResult<(Response, Option)> { let engine = match as_module.compiler { - Compiler::CL => init_cl_engine(limit, gas_costs.clone()), - Compiler::SP => init_sp_engine(limit, gas_costs.clone()), + Compiler::CL => init_cl_engine(limit, gas_costs.clone(), condom_limits.clone()), + Compiler::SP => init_sp_engine(limit, gas_costs.clone(), condom_limits.clone()), }; let mut store = Store::new(engine); - let mut context = ASContext::new(interface, as_module.binary_module, gas_costs); + let mut context = ASContext::new( + interface, + as_module.binary_module, + gas_costs, + condom_limits.clone(), + ); // save the gas remaining before sub-execution: used by readonly execution interface.save_gas_remaining_before_subexecution(limit); diff --git a/src/execution.rs b/src/execution.rs index 136387d8..26431b25 100644 --- a/src/execution.rs +++ b/src/execution.rs @@ -1,10 +1,10 @@ use crate::as_execution::{exec_as_module, ASModule}; use crate::error::VMResult; use crate::middlewares::gas_calibration::GasCalibrationResult; -use crate::settings; use crate::types::{Interface, Response}; use crate::wasmv1_execution::{exec_wasmv1_module, WasmV1Module}; use crate::GasCosts; +use crate::{settings, CondomLimits}; use anyhow::{anyhow, Result}; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -35,7 +35,12 @@ impl RuntimeModule { /// * (0): legacy AssemblyScript module /// * (1): new agnostic module /// * (_): unsupported module - pub fn new(bytecode: &[u8], gas_costs: GasCosts, compiler: Compiler) -> Result { + pub fn new( + bytecode: &[u8], + gas_costs: GasCosts, + compiler: Compiler, + condom_limits: CondomLimits, + ) -> Result { if bytecode.len() <= 2 { return Err(anyhow!("Too small bytecode")); } @@ -54,6 +59,7 @@ impl RuntimeModule { gas_costs.max_instance_cost, gas_costs, compiler, + condom_limits, )?)), RuntimeModuleId::WasmV1ModuleId => { // Safe to use [1..] as we checked the bytecode length @@ -63,6 +69,7 @@ impl RuntimeModule { gas_costs.max_instance_cost, gas_costs, compiler, + condom_limits, ) .map_err(|err| anyhow!("Failed to compile WasmV1 module: {}", err))?; Ok(Self::WasmV1Module(res)) @@ -95,7 +102,12 @@ impl RuntimeModule { } /// Deserialize a RuntimeModule - pub fn deserialize(ser_module: &[u8], limit: u64, gas_costs: GasCosts) -> Result { + pub fn deserialize( + ser_module: &[u8], + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, + ) -> Result { let module_id = ser_module .first() .map(|&id| RuntimeModuleId::try_from(id)) @@ -103,10 +115,10 @@ impl RuntimeModule { match module_id { Some(RuntimeModuleId::ASModuleId) => Ok(RuntimeModule::ASModule( - ASModule::deserialize(&ser_module[1..], limit, gas_costs)?, + ASModule::deserialize(&ser_module[1..], limit, gas_costs, condom_limits)?, )), Some(RuntimeModuleId::WasmV1ModuleId) => Ok(RuntimeModule::WasmV1Module( - WasmV1Module::deserialize(&ser_module[1..], limit, gas_costs)?, + WasmV1Module::deserialize(&ser_module[1..], limit, gas_costs, condom_limits)?, )), None => Err(anyhow!("Empty bytecode")), } @@ -130,15 +142,28 @@ pub(crate) fn exec( param: &[u8], limit: u64, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> VMResult<(Response, Option)> { let response = match rt_module { - RuntimeModule::ASModule(module) => { - exec_as_module(interface, module, function, param, limit, gas_costs)? - } - RuntimeModule::WasmV1Module(module) => { - exec_wasmv1_module(interface, module, function, param, limit, gas_costs) - .map_err(|err| anyhow!("Failed to execute WasmV1 module: {}", err.to_string()))? - } + RuntimeModule::ASModule(module) => exec_as_module( + interface, + module, + function, + param, + limit, + gas_costs, + condom_limits, + )?, + RuntimeModule::WasmV1Module(module) => exec_wasmv1_module( + interface, + module, + function, + param, + limit, + gas_costs, + condom_limits, + ) + .map_err(|err| anyhow!("Failed to execute WasmV1 module: {}", err.to_string()))?, }; Ok(response) } @@ -161,8 +186,18 @@ pub fn run_main( rt_module: RuntimeModule, limit: u64, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> VMResult { - Ok(exec(interface, rt_module, settings::MAIN, b"", limit, gas_costs)?.0) + Ok(exec( + interface, + rt_module, + settings::MAIN, + b"", + limit, + gas_costs, + condom_limits, + )? + .0) } /// Library Input, take a `module` wasm built with the massa environment, @@ -183,8 +218,18 @@ pub fn run_function( param: &[u8], limit: u64, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> VMResult { - Ok(exec(interface, rt_module, function, param, limit, gas_costs)?.0) + Ok(exec( + interface, + rt_module, + function, + param, + limit, + gas_costs, + condom_limits, + )? + .0) } /// Same as run_main but return a GasCalibrationResult @@ -195,6 +240,7 @@ pub fn run_main_gc( param: &[u8], limit: u64, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> VMResult { Ok(exec( interface, @@ -203,6 +249,7 @@ pub fn run_main_gc( param, limit, gas_costs, + condom_limits, )? .1 .unwrap()) @@ -216,7 +263,14 @@ fn test_serialize_deserialize() { // ASModule { let module = RuntimeModule::ASModule( - ASModule::new(bytecode, 0, GasCosts::default(), Compiler::CL).unwrap(), + ASModule::new( + bytecode, + 0, + GasCosts::default(), + Compiler::CL, + CondomLimits::default(), + ) + .unwrap(), ); let serialized = module.serialize().unwrap(); @@ -225,10 +279,15 @@ fn test_serialize_deserialize() { RuntimeModuleId::ASModuleId as u8 ); - let serialized2 = RuntimeModule::deserialize(&serialized, 0, GasCosts::default()) - .unwrap() - .serialize() - .unwrap(); + let serialized2 = RuntimeModule::deserialize( + &serialized, + 0, + GasCosts::default(), + CondomLimits::default(), + ) + .unwrap() + .serialize() + .unwrap(); assert_eq!(serialized, serialized2); } @@ -236,7 +295,14 @@ fn test_serialize_deserialize() { // WasmV1Module { let module = RuntimeModule::WasmV1Module( - WasmV1Module::compile(bytecode, 0, GasCosts::default(), Compiler::CL).unwrap(), + WasmV1Module::compile( + bytecode, + 0, + GasCosts::default(), + Compiler::CL, + CondomLimits::default(), + ) + .unwrap(), ); let serialized = module.serialize().unwrap(); @@ -245,10 +311,15 @@ fn test_serialize_deserialize() { RuntimeModuleId::WasmV1ModuleId as u8 ); - let serialized2 = RuntimeModule::deserialize(&serialized, 0, GasCosts::default()) - .unwrap() - .serialize() - .unwrap(); + let serialized2 = RuntimeModule::deserialize( + &serialized, + 0, + GasCosts::default(), + CondomLimits::default(), + ) + .unwrap() + .serialize() + .unwrap(); assert_eq!(serialized, serialized2); } diff --git a/src/middlewares/condom.rs b/src/middlewares/condom.rs new file mode 100644 index 00000000..e4499c32 --- /dev/null +++ b/src/middlewares/condom.rs @@ -0,0 +1,1301 @@ +/// An entry-point protection middleware that prevents malicious WASM files from reaching the compilation step. +use std::fmt; +use wasmer::{ + FunctionMiddleware, LocalFunctionIndex, MiddlewareError, MiddlewareReaderState, + ModuleMiddleware, +}; +use wasmer_types::ModuleInfo; + +use crate::CondomLimits; + +/// The module-level export limit middleware, named `CondomMiddleware`. +pub struct CondomMiddleware { + /// Maximum allowed number of exports. + limits: CondomLimits, +} + +impl CondomMiddleware { + /// Creates a new `CondomMiddleware`. + pub fn new(limits: CondomLimits) -> Self { + Self { limits } + } +} + +impl fmt::Debug for CondomMiddleware { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CondomMiddleware") + .field("limits", &self.limits) + .finish() + } +} + +impl ModuleMiddleware for CondomMiddleware { + /// This method is called before applying middleware on functions, + /// and it will enforce the export limits on the module. + fn transform_module_info(&self, module_info: &mut ModuleInfo) -> Result<(), MiddlewareError> { + // Check the export limits and return an error if exceeded + if let Some(max_exports) = self.limits.max_exports { + if module_info.exports.len() > max_exports { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many exports. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check the number of function limits + if let Some(max_functions) = self.limits.max_functions { + if module_info.functions.len() > max_functions { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many functions. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check the signature limits i.e. the number of arguments a function + // can take. + // NOTE, at the moment (2024-09-30) : + // - functions can returns only one value, see: + // https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#signatures_and_parameters + // - tweaking test_condom_middleware_exceeds_args_limit_max(), one can + // see that wasmer limits number of arguments to 1024 + if let Some(max_signature_len) = self.limits.max_signature_len { + for signature in module_info.signatures.values() { + if signature.params().len() + signature.results().len() > max_signature_len { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file contains a function with too many parameters and return values. Blocked to prevent compile-time memory bloat", + )); + } + } + } + + // Check the name limit + if let Some(max_name_len) = self.limits.max_name_len { + if let Some(name) = &module_info.name { + if name.len() > max_name_len { + dbg!(max_name_len, name.len()); + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has a too long name. Blocked to prevent compile-time memory bloat", + )); + } + } + } + + // Check the import limits + if let Some(max_imports) = self.limits.max_imports_len { + if module_info.imports.len() > max_imports { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many imports. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check the table initializer limits + if let Some(max_table_initializers) = self.limits.max_table_initializers_len { + if module_info.table_initializers.len() > max_table_initializers { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many table initializers. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check passive elements limits + if let Some(max_passive_elements) = self.limits.max_passive_elements_len { + if module_info.passive_elements.len() > max_passive_elements { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many passive elements. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check passive data limits + if let Some(max_passive_data) = self.limits.max_passive_data_len { + if module_info.passive_data.len() > max_passive_data { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many passive data. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check the global initializer limits + if let Some(max_global_initializers) = self.limits.max_global_initializers_len { + if module_info.global_initializers.len() > max_global_initializers { + return Err(MiddlewareError::new( + "CondomMiddleware", + format!("The WASM file has too many global initializers (contains; {} limit: {}). Blocked to prevent compile-time memory bloat", + module_info.global_initializers.len(), + max_global_initializers, + ), + )); + } + } + + // Check the function name limits + if let Some(max_function_names) = self.limits.max_function_names_len { + for (_, f_name) in module_info.function_names.iter() { + if f_name.len() > max_function_names { + return Err(MiddlewareError::new( + "CondomMiddleware", + format!("The WASM file has too long function names ({} is {}). Blocked to prevent compile-time memory bloat", + f_name, + f_name.len()), + )); + } + } + } + + // Check the table limits + if let Some(max_tables) = self.limits.max_tables_count { + if module_info.tables.len() > max_tables { + return Err(MiddlewareError::new( + "CondomMiddleware", + format!("The WASM file has too many tables (contains: {} limit: {}). Blocked to prevent compile-time memory bloat", + module_info.tables.len(), + max_tables, + ), + )); + } + } + + // Check the memory limits + if let Some(max_memories) = self.limits.max_memories_len { + if module_info.memories.len() > max_memories { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many memories. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check the global limits + if let Some(max_globals) = self.limits.max_globals_len { + if module_info.globals.len() > max_globals { + return Err(MiddlewareError::new( + "CondomMiddleware", + format!("The WASM file has too many globals (contains: {}, limit: {}). Blocked to prevent compile-time memory bloat", + module_info.globals.len(), + max_globals + ) + )); + } + } + + // custom_sections: IndexMap, + // Check the custom section limits + if let Some(max_custom_sections) = self.limits.max_custom_sections_len { + if module_info.custom_sections.len() > max_custom_sections { + return Err(MiddlewareError::new( + "CondomMiddleware", + "The WASM file has too many custom sections. Blocked to prevent compile-time memory bloat", + )); + } + } + + // Check the custom section data limits + if let Some(max_custom_sections_data) = self.limits.max_custom_sections_data_len { + for (idx, data) in module_info.custom_sections_data.iter() { + if data.len() > max_custom_sections_data { + let section_name = module_info + .custom_sections + .get_index(idx.as_u32() as usize) + .map(|(name, _)| name.to_owned()) + .unwrap_or("Unknown section".to_string()); + + return Err(MiddlewareError::new( + "CondomMiddleware", + format!("The WASM file custom section {:?} named '{}' with size {} is too big (limit: {}). Blocked to prevent compile-time memory bloat", + idx, + section_name, + data.len(), + max_custom_sections_data, + ), + )); + }; + } + } + + Ok(()) + } + + /// Generates a `FunctionMiddleware` for a given function. + fn generate_function_middleware(&self, _: LocalFunctionIndex) -> Box { + // This middleware doesn't need to modify functions, so we return a no-op middleware. + Box::new(NoOpFunctionMiddleware) + } +} + +/// A no-op function middleware used as a placeholder. +struct NoOpFunctionMiddleware; + +impl fmt::Debug for NoOpFunctionMiddleware { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NoOpFunctionMiddleware").finish() + } +} + +impl FunctionMiddleware for NoOpFunctionMiddleware { + fn feed<'a>( + &mut self, + operator: wasmer::wasmparser::Operator<'a>, + state: &mut MiddlewareReaderState<'a>, + ) -> Result<(), MiddlewareError> { + state.push_operator(operator); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::Arc; + use wasmer::{sys::EngineBuilder, wat2wasm, CompilerConfig, Cranelift, Module, Store}; + + const MEMORY_LIMIT_1GB: u64 = 1024 * 1024 * 1024; + + fn bytecode_within_limits() -> Vec { + wat2wasm( + br#" + (module + (func (export "f1") (result i32) (i32.const 1)) + (func (export "f2") (result i32) (i32.const 2)) + (global (export "g1") i32 (i32.const 0)) + ) + "#, + ) + .unwrap() + .into() + } + + fn bytecode_exceeding_exports_limits() -> Vec { + wat2wasm( + br#" + (module + (func (export "f1") (result i32) (i32.const 1)) + (func (export "f2") (result i32) (i32.const 2)) + (func (export "f3") (result i32) (i32.const 3)) + (global (export "g1") i32 (i32.const 0)) + (global (export "g2") i32 (i32.const 0)) + ) + "#, + ) + .unwrap() + .into() + } + + fn generate_wasm_bloated_with_functions(nb_fn: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + for i in 1..=nb_fn { + wasm_code.push_str(&format!(" (func (result i32) (i32.const {}))\n", i)); + } + wasm_code.push(')'); + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_bloated_with_args(nb_args: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + if nb_args == 0 { + wasm_code.push_str(" (func $f (result i32) (i32.const 0))\n"); + } else { + wasm_code.push_str(" (func $f (param"); + for _ in 1..nb_args { + wasm_code.push_str(" i32 "); + } + wasm_code.push_str(") (result i32)\n"); + wasm_code.push_str(" local.get 0\n"); + } + + wasm_code.push_str(" )\n)"); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_bloated_with_table_initializers(table_size: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + wasm_code.push_str(" (func $f (result i32) (i32.const 42))\n"); + wasm_code.push_str(&format!(" (table {} funcref)\n", table_size)); + + for i in 0..table_size { + wasm_code.push_str(&format!(" (elem (i32.const {}) $f)\n", i)); + } + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_bloated_with_variable_passive_elements(passive_count: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + wasm_code.push_str(" (func $f (result i32) (i32.const 42))\n"); + + for _ in 0..passive_count { + wasm_code.push_str(" (elem func $f)\n"); + } + + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_with_variable_passive_data(data_size: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + wasm_code.push_str(" (memory $m 1)\n"); + + for i in 0..data_size { + wasm_code.push_str(&format!("(data $d{} \"Hello, World!\")\n", i)); + } + + wasm_code.push_str(")\n"); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_with_global_initializers(data_size: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + for i in 0..data_size { + wasm_code.push_str(&format!( + "(global $g{} (export \"g{}\") i32 (i32.const 42))\n", + i, i + )); + } + + wasm_code.push_str(")\n"); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_with_function_names(data_size: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + let fn_name = "f".repeat(data_size); + + wasm_code.push_str(&format!( + "(func ${} (result i32) (i32.const 42))\n", + fn_name + )); + + wasm_code.push_str(")\n"); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_bloated_with_tables(table_count: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + for _ in 0..table_count { + wasm_code.push_str(" (table 1 funcref)\n"); + } + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_bloated_with_memories(memories_count: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + for i in 0..memories_count { + wasm_code.push_str(&format!( + " (import \"m{}\" \"memory{}\" (memory 1))\n", + i, i + )); + } + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_bloated_with_globals(globals_count: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + for i in 0..globals_count { + wasm_code.push_str(&format!("(global $g{} (mut i32) (i32.const 10))", i)); + } + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_with_multiple_returns(nb_returns: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + if nb_returns == 0 { + wasm_code.push_str(" (func $f (result))\n"); + } else { + wasm_code.push_str(" (func $f (result"); + for _ in 0..nb_returns { + wasm_code.push_str(" i32"); + } + wasm_code.push_str(")\n"); + + for i in 0..nb_returns { + wasm_code.push_str(&format!(" i32.const {}\n", i)); + } + + wasm_code.push_str(" )\n"); + } + + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + fn generate_wasm_with_local_vars(nb_locals: usize) -> Vec { + let mut wasm_code = String::from("(module\n"); + + wasm_code.push_str(" (func $f (result i32)\n"); + + if nb_locals > 0 { + wasm_code.push_str(" (local"); + for _ in 0..nb_locals { + wasm_code.push_str(" i32"); + } + wasm_code.push_str(")\n"); + } + + for i in 0..nb_locals { + wasm_code.push_str(&format!(" i32.const 0\n local.set {}\n", i)); + } + + if nb_locals > 0 { + wasm_code.push_str(" local.get 0\n"); + } else { + wasm_code.push_str(" i32.const 0\n"); + } + + wasm_code.push_str(" )\n"); + wasm_code.push(')'); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + #[test] + fn test_condom_middleware_exceeds_exports_limit() { + let condom_limits = CondomLimits { + max_exports: Some(2), + ..Default::default() + }; + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits)); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new(&store, bytecode_exceeding_exports_limits()); + + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many exports")); + } + } + + use sysinfo::{Pid, System}; + fn get_memory_usage() -> Result { + let mut system = System::new_all(); + system.refresh_all(); + let pid = Pid::from_u32(std::process::id()); + if let Some(process) = system.process(pid) { + Ok(process.memory()) + } else { + Err("Proccess not found".to_string()) + } + } + + use num_format::{SystemLocale, ToFormattedString}; + #[test] + fn test_condom_middleware_exceeds_functions_limit_max() { + let condom_limits = CondomLimits { + max_functions: Some(10000), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + // starting from 1000 functions + let mut function_count = 1000; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = + Module::new(&store, generate_wasm_bloated_with_functions(function_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "functions {:>8} memory usage: {:>12}o ", + function_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many functions")); + } + break; + } + + function_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_args_limit_max() { + let condom_limits = CondomLimits { + max_signature_len: Some(500), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + // starting from 2 arguments + let mut arg_count = 2; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new(&store, generate_wasm_bloated_with_args(arg_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "args {:>4} memory usage: {:>12}o ", + arg_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many parameters")); + } + break; + } + + arg_count *= 2; + } + } + + #[test] + fn test_condom_middleware_exceeds_return_values_limit_max() { + let condom_limits = CondomLimits { + max_signature_len: Some(500), + ..Default::default() + }; + + let mut arg_count = 2; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new(&store, generate_wasm_with_multiple_returns(arg_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "args {:>4} memory usage: {:>12}o ", + arg_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many parameters")); + } + break; + } + + arg_count *= 2; + } + } + + #[test] + fn test_condom_middleware_exceeds_table_initializers_limit_max() { + let condom_limits = CondomLimits { + max_table_initializers_len: Some(100), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut ini_count = 10; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new( + &store, + generate_wasm_bloated_with_table_initializers(ini_count), + ); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Initializers {:>6} memory usage: {:>12}o ", + ini_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many table initializers")); + } + break; + } + + ini_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_passive_elements_limit_max() { + let condom_limits = CondomLimits { + max_passive_elements_len: Some(100), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut ini_count = 10; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new( + &store, + generate_wasm_bloated_with_variable_passive_elements(ini_count), + ); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Passive elements {:>6} memory usage: {:>12}o ", + ini_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many passive elements")); + } + break; + } + + ini_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_passive_data_limit_max() { + let condom_limits = CondomLimits { + max_passive_data_len: Some(10000), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut ini_count = 10; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = + Module::new(&store, generate_wasm_with_variable_passive_data(ini_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Passive data {:>6} memory usage: {:>12}o ", + ini_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many passive data")); + } + break; + } + + ini_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_global_initializers_limit_max() { + let condom_limits = CondomLimits { + max_global_initializers_len: Some(10000), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut ini_count = 10; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = + Module::new(&store, generate_wasm_with_global_initializers(ini_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Global initializers {:>6} memory usage: {:>12}o ", + ini_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many global initializers")); + } + break; + } + + ini_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_function_names_limit_max() { + let condom_limits = CondomLimits { + max_function_names_len: Some(99999), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut fn_name_count = 10; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = + Module::new(&store, generate_wasm_with_function_names(fn_name_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Function names {:>8} memory usage: {:>12}o ", + fn_name_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too long function names")); + } + break; + } + + fn_name_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_tables_limit_max() { + let condom_limits = CondomLimits { + max_tables_count: Some(15), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut table_count = 2; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new(&store, generate_wasm_bloated_with_tables(table_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Table count {:>6} memory usage: {:>12}o ", + table_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many tables")); + } + break; + } + + table_count *= 2; + } + } + + #[test] + fn test_condom_middleware_exceeds_memories_limit_max() { + let condom_limits = CondomLimits { + // NOTE: max_memories_len is defined to Some(0) because the + // specification, FOR NOW, only support ONE memory. That being said + // wasmer seems ready for extension. + max_memories_len: Some(0), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut memory_count = 1; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = + Module::new(&store, generate_wasm_bloated_with_memories(memory_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Memory count {:>6} memory usage: {:>12}o ", + memory_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many memories")); + } + break; + } + + memory_count *= 2; + } + } + #[test] + fn test_condom_middleware_exceeds_globals_limit_max() { + let condom_limits = CondomLimits { + max_globals_len: Some(1000), + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut memory_count = 10; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = + Module::new(&store, generate_wasm_bloated_with_globals(memory_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Global count {:>6} memory usage: {:>12}o ", + memory_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many globals")); + } + break; + } + + memory_count *= 10; + } + } + #[test] + fn test_condom_middleware_exceeds_function_locales_limit_max() { + // NOTE: can't find a way to set limit for locals. We are currently + // relying on the wasmpaser limit that is set to 50_000 locales + // (https://github.com/bytecodealliance/wasm-tools/blob/610b7aacdb41f129b8dda3f04785934105bd6791/crates/wasmprinter/src/lib.rs#L20) + // This should do the trick as + // 50 locals use 51 134 464b of ram + // 500000 locals use 90 607 616b of ram + let condom_limits = CondomLimits { + ..Default::default() + }; + + // Keep increasing the wasm size until the memory usage is above the limit + let mut memory_count = 50; + loop { + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new(&store, generate_wasm_with_local_vars(memory_count)); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Locals count {:>6} memory usage: {:>12}o ", + memory_count, + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + // dbg!(&module_result); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many locals")); + } + break; + } + + memory_count *= 10; + } + } + + #[test] + fn test_condom_middleware_exceeds_custom_sections_limit_max() { + // NOTE: + // custom section can't be generated in wat + // external tools are needed. + // - first `wat2wasm simple.wat -o simple-name.wasm --debug-names` add a + // `name` custom section useful for debugging. + // - then `https://wasmer.io/liftm/wasm-custom-section` allows to add + // other custom sections. + // + // current example contains: + // wasm-custom-section simple-custom-section.wasm list + // Section `name` (21 bytes) + // Section `1` (2 bytes) + // Section `2` (2 bytes) + // Section `3` (2 bytes) + // Section `3` (11 bytes) + + let condom_limits = CondomLimits { + max_custom_sections_len: Some(2), + ..Default::default() + }; + + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let wasm = include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/wasm/simple-custom-section.wasm" + )); + let module_result = Module::new(&store, wasm); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Memory usage: {:>12}o ", + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("too many custom sections")); + } + } + } + + #[test] + fn test_condom_middleware_exceeds_custom_sections_data_limit_max() { + // NOTE: + // custom section can't be generated in wat + // external tools are needed. + // - first `wat2wasm simple.wat -o simple-name.wasm --debug-names` add a + // `name` custom section useful for debugging. + // - then `https://wasmer.io/liftm/wasm-custom-section` allows to add + // other custom sections. + // + // current example contains: + // wasm-custom-section simple-custom-section.wasm list + // Section `name` (21 bytes) + // Section `1` (2 bytes) + // Section `2` (2 bytes) + // Section `3` (2 bytes) + // Section `3` (11 bytes) + + let condom_limits = CondomLimits { + max_custom_sections_data_len: Some(9), + ..Default::default() + }; + + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let wasm = include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/wasm/simple-custom-section.wasm" + )); + let module_result = Module::new(&store, wasm); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Memory usage: {:>12}o ", + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("is too big")); + } + } + } + + fn generate_wasm_calibrate( + nb_fn: usize, + fn_name_len: usize, + nb_params: usize, + nb_return_values: usize, + nb_locals: usize, + nb_exports_fn: usize, + nb_imports_fn: usize, + nb_table_ini: usize, + nb_passive_elm: usize, + nb_passive_data: usize, + nb_global_ini: usize, + nb_tables: usize, + ) -> Vec { + assert!(fn_name_len > 0); + + fn gen_fn_names(count: usize, length: usize) -> Vec { + use rand::distributions::Alphanumeric; + use rand::thread_rng; + use rand::Rng; + use std::collections::HashSet; + + let mut unique_strings = HashSet::new(); + let mut rng = thread_rng(); + + while unique_strings.len() < count { + // Générer une chaîne de caractères aléatoire + let random_string: String = (0..length) + .map(|_| rng.sample(Alphanumeric) as char) + .collect(); + + // Ajouter la chaîne générée à l'ensemble + unique_strings.insert(random_string); + } + + unique_strings.into_iter().collect::>() + } + let fn_names = gen_fn_names(nb_fn, fn_name_len); + + let mut wasm_code = String::from("(module\n"); + + // import mem + wasm_code.push_str(";; import memory\n"); + wasm_code.push_str(" (import \"env\" \"memory\" (memory 1 10))\n"); + wasm_code.push('\n'); + + // import fn + wasm_code.push_str(";; import functions\n"); + for i in 0..nb_imports_fn { + wasm_code.push_str(&format!( + " (import \"env\" \"external_fn{}\" (func (param i32 i32) (result i32)))\n", + i + )); + } + wasm_code.push('\n'); + + // passive data + wasm_code.push_str(";; passive data\n"); + for i in 0..nb_passive_data { + wasm_code.push_str(&format!("(data $d{} \"Hello, World!\")\n", i)); + } + wasm_code.push('\n'); + + // global initializers + wasm_code.push_str(";; global initializers\n"); + for i in 0..nb_global_ini { + wasm_code.push_str(&format!("(global $g{} i32 (i32.const 42))\n", i,)); + } + wasm_code.push('\n'); + + // table + wasm_code.push_str(";; table\n"); + for _ in 0..nb_tables { + wasm_code.push_str(" (table 1 funcref)\n"); + } + wasm_code.push('\n'); + + // decl fn + wasm_code.push_str(";; declare functions\n"); + for i in 0..nb_fn { + wasm_code.push_str(&format!(" (func ${} (param", fn_names.get(i).unwrap())); + + for _ in 0..nb_params { + wasm_code.push_str(" i32"); + } + wasm_code.push_str(") (result"); + + for _ in 0..nb_return_values { + wasm_code.push_str(" i32"); + } + wasm_code.push_str(")\n"); + + for _ in 0..nb_locals { + wasm_code.push_str(" (local i32)\n"); + } + + wasm_code.push_str(" (block (result"); + for _ in 0..nb_return_values { + wasm_code.push_str(" i32"); + } + wasm_code.push_str(")\n"); + + for _ in 0..nb_return_values { + wasm_code.push_str(&format!(" i32.const {}\n", i)); + } + + wasm_code.push_str(" )\n )\n"); + } + wasm_code.push('\n'); + + // export fn + wasm_code.push_str(";; export functions\n"); + for i in 0..nb_exports_fn { + wasm_code.push_str(&format!( + " (export \"fn_{}\" (func ${}))\n", + i, + fn_names.get(i).unwrap() + )); + } + wasm_code.push('\n'); + + // table initializer + wasm_code.push_str(";; table initializers\n"); + wasm_code.push_str(&format!(" (table {} funcref)\n", nb_table_ini)); + for i in 0..nb_table_ini { + wasm_code.push_str(&format!( + " (elem (i32.const {}) ${})\n", + i, + fn_names.get(i).unwrap() + )); + } + wasm_code.push('\n'); + + // passive elements + wasm_code.push_str(";; passive elements\n"); + for i in 0..nb_passive_elm { + wasm_code.push_str(&format!(" (elem func ${})\n", fn_names.get(i).unwrap())); + } + + wasm_code.push(')'); + + std::fs::write("calibrate.wat", &wasm_code).unwrap(); + + wat2wasm(wasm_code.as_bytes()).unwrap().into() + } + + #[test] + fn test_condom_middleware_calibrate() { + use std::time::Instant; + let nb_fn = 512; + let nb_params = 64; + let nb_return_values = 8; + let name_len = 256; + let fn_name_len = 256; + let custon_section_data_len = 1_000_000; + let nb_exports = nb_fn; + let nb_imports_fn = 256; + let nb_imports_mem = 1; + let nb_table_ini = nb_fn; + let nb_passive_elm = nb_fn; + let nb_passive_data = 512; + let nb_global_ini = 512; + let nb_tables = 16; + let nb_memories = 1; // only 1 supported so far (cf specification) + + let nb_locals = 512; + + let condom_limits = CondomLimits { + max_exports: Some(nb_exports + nb_global_ini), + max_functions: Some(nb_fn + nb_imports_fn), + max_signature_len: Some(nb_params + nb_return_values), + max_name_len: Some(name_len), + max_imports_len: Some(nb_imports_fn + nb_imports_mem), + max_table_initializers_len: Some(nb_table_ini), + max_passive_elements_len: Some(nb_passive_elm), + max_passive_data_len: Some(nb_passive_data), + max_global_initializers_len: Some(nb_global_ini), + max_function_names_len: Some(fn_name_len), + max_tables_count: Some(nb_tables + 1), // +1 for the table with initializers + max_memories_len: Some(nb_memories), + max_globals_len: Some(nb_global_ini), + max_custom_sections_len: Some(1), + max_custom_sections_data_len: Some(custon_section_data_len), + }; + + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits.clone())); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let wasm_bytes = generate_wasm_calibrate( + nb_fn, + fn_name_len, + nb_params, + nb_return_values, + nb_locals, + nb_exports, + nb_imports_fn, + nb_table_ini, + nb_passive_elm, + nb_passive_data, + nb_global_ini, + nb_tables, + ); + + let start_time = Instant::now(); + let module_result = Module::new(&store, wasm_bytes); + let compilation_duration = Instant::now().duration_since(start_time); + println!("Module creation took: {:?}", compilation_duration); + + let memory_usage = get_memory_usage().unwrap(); + println!( + "Memory usage: {:>12}o ", + memory_usage.to_formatted_string(&SystemLocale::default().unwrap()), + ); + + if memory_usage > MEMORY_LIMIT_1GB || module_result.is_err() { + dbg!(&module_result); + assert!(module_result.is_err()); + if let Err(e) = module_result { + assert!(e.to_string().contains("is too big")); + } + } + } + + #[test] + fn test_condom_middleware_exports_within_limits() { + let condom_limits = CondomLimits { + max_exports: Some(3), + ..Default::default() + }; + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits)); + let mut compiler_config = Cranelift::default(); + compiler_config.push_middleware(condom_middleware); + + let store = Store::new(EngineBuilder::new(compiler_config)); + let module_result = Module::new(&store, bytecode_within_limits()); + + assert!(module_result.is_ok()); + } +} diff --git a/src/middlewares/dumper.rs b/src/middlewares/dumper.rs index bbc88169..97d0b239 100644 --- a/src/middlewares/dumper.rs +++ b/src/middlewares/dumper.rs @@ -30,8 +30,10 @@ impl ModuleMiddleware for Dumper { Box::new(FunctionDumper {}) } - fn transform_module_info(&self, _module_info: &mut ModuleInfo) { + fn transform_module_info(&self, _module_info: &mut ModuleInfo) -> Result<(), MiddlewareError> { println!("Transform module info..."); + + Ok(()) } } diff --git a/src/middlewares/gas_calibration.rs b/src/middlewares/gas_calibration.rs index c0b55f61..e3731349 100644 --- a/src/middlewares/gas_calibration.rs +++ b/src/middlewares/gas_calibration.rs @@ -54,7 +54,7 @@ impl ModuleMiddleware for GasCalibration { }) } - fn transform_module_info(&self, module_info: &mut ModuleInfo) { + fn transform_module_info(&self, module_info: &mut ModuleInfo) -> Result<(), MiddlewareError> { let current = Instant::now(); let mut global_indexes = self.global_indexes.lock().unwrap(); @@ -171,7 +171,9 @@ impl ModuleMiddleware for GasCalibration { // println!("Time elapsed in {}() is: {:?}", "transform_module_info", // duration); - *global_indexes = Some(indexes) + *global_indexes = Some(indexes); + + Ok(()) } } diff --git a/src/middlewares/mod.rs b/src/middlewares/mod.rs index 76caee37..459a10a8 100644 --- a/src/middlewares/mod.rs +++ b/src/middlewares/mod.rs @@ -1,3 +1,4 @@ +pub mod condom; pub mod dumper; pub mod gas_calibration; pub mod operator; diff --git a/src/middlewares/operator.rs b/src/middlewares/operator.rs index a8da688a..29a1c85e 100644 --- a/src/middlewares/operator.rs +++ b/src/middlewares/operator.rs @@ -1535,18 +1535,6 @@ pub fn operator_field_str<'a>(op: &'a Operator) -> &'a str { Operator::I8x16RelaxedSwizzle => { stringify!(I8x16RelaxedSwizzle) } - Operator::I32x4RelaxedTruncSatF32x4S => { - stringify!(I32x4RelaxedTruncSatF32x4S) - } - Operator::I32x4RelaxedTruncSatF32x4U => { - stringify!(I32x4RelaxedTruncSatF32x4U) - } - Operator::I32x4RelaxedTruncSatF64x2SZero => { - stringify!(I32x4RelaxedTruncSatF64x2SZero) - } - Operator::I32x4RelaxedTruncSatF64x2UZero => { - stringify!(I32x4RelaxedTruncSatF64x2UZero) - } Operator::F32x4RelaxedMin => { stringify!(F32x4RelaxedMin) } @@ -1561,20 +1549,61 @@ pub fn operator_field_str<'a>(op: &'a Operator) -> &'a str { } Operator::I8x16AvgrU => stringify!(I8x16AvgrU), Operator::I16x8AvgrU => stringify!(I16x8AvgrU), - Operator::F32x4RelaxedFma => stringify!(F32x4RelaxedFma), - Operator::F32x4RelaxedFnma => stringify!(F32x4RelaxedFnma), - Operator::F64x2RelaxedFma => stringify!(F64x2RelaxedFma), - Operator::F64x2RelaxedFnma => stringify!(F64x2RelaxedFnma), Operator::I8x16RelaxedLaneselect => stringify!(I8x16RelaxedLaneselect), Operator::I16x8RelaxedLaneselect => stringify!(I16x8RelaxedLaneselect), Operator::I32x4RelaxedLaneselect => stringify!(I32x4RelaxedLaneselect), Operator::I64x2RelaxedLaneselect => stringify!(I64x2RelaxedLaneselect), Operator::I16x8RelaxedQ15mulrS => stringify!(I16x8RelaxedQ15mulrS), - Operator::I16x8DotI8x16I7x16S => stringify!(I16x8DotI8x16I7x16S), - Operator::I32x4DotI8x16I7x16AddS => stringify!(I32x4DotI8x16I7x16AddS), - Operator::F32x4RelaxedDotBf16x8AddF32x4 => { - stringify!(F32x4RelaxedDotBf16x8AddF32x4) - } + Operator::TryTable { .. } => stringify!(TryTable), + Operator::ThrowRef => stringify!(ThrowRef), + Operator::RefEq => stringify!(RefEq), + Operator::StructNew { .. } => stringify!(StructNew), + Operator::StructNewDefault { .. } => stringify!(StructNewDefault), + Operator::StructGet { .. } => stringify!(StructGet), + Operator::StructGetS { .. } => stringify!(StructGetS), + Operator::StructGetU { .. } => stringify!(StructGetU), + Operator::StructSet { .. } => stringify!(StructSet), + Operator::ArrayNew { .. } => stringify!(ArrayNew), + Operator::ArrayNewDefault { .. } => stringify!(ArrayNewDefault), + Operator::ArrayNewFixed { .. } => stringify!(ArrayNewFixed), + Operator::ArrayNewData { .. } => stringify!(ArrayNewData), + Operator::ArrayNewElem { .. } => stringify!(ArrayNewElem), + Operator::ArrayGet { .. } => stringify!(ArrayGet), + Operator::ArrayGetS { .. } => stringify!(ArrayGetS), + Operator::ArrayGetU { .. } => stringify!(ArrayGetU), + Operator::ArraySet { .. } => stringify!(ArraySet), + Operator::ArrayLen => stringify!(ArrayLen), + Operator::ArrayFill { .. } => stringify!(ArrayFill), + Operator::ArrayCopy { .. } => stringify!(ArrayCopy), + Operator::ArrayInitData { .. } => stringify!(ArrayInitData), + Operator::ArrayInitElem { .. } => stringify!(ArrayInitElem), + Operator::RefTestNonNull { .. } => stringify!(RefTestNonNull), + Operator::RefTestNullable { .. } => stringify!(RefTestNullable), + Operator::RefCastNonNull { .. } => stringify!(RefCastNonNull), + Operator::RefCastNullable { .. } => stringify!(RefCastNullable), + Operator::BrOnCast { .. } => stringify!(BrOnCast), + Operator::BrOnCastFail { .. } => stringify!(BrOnCastFail), + Operator::AnyConvertExtern => stringify!(AnyConvertExtern), + Operator::ExternConvertAny => stringify!(ExternConvertAny), + Operator::RefI31 => stringify!(RefI31), + Operator::I31GetS => stringify!(I31GetS), + Operator::I31GetU => stringify!(I31GetU), + Operator::MemoryDiscard { .. } => stringify!(MemoryDiscard), + Operator::I32x4RelaxedTruncF32x4S => stringify!(I32x4RelaxedTruncF32x4S), + Operator::I32x4RelaxedTruncF32x4U => stringify!(I32x4RelaxedTruncF32x4U), + Operator::I32x4RelaxedTruncF64x2SZero => stringify!(I32x4RelaxedTruncF64x2SZero), + Operator::I32x4RelaxedTruncF64x2UZero => stringify!(I32x4RelaxedTruncF64x2UZero), + Operator::F32x4RelaxedMadd => stringify!(F32x4RelaxedMadd), + Operator::F32x4RelaxedNmadd => stringify!(F32x4RelaxedNmadd), + Operator::F64x2RelaxedMadd => stringify!(F64x2RelaxedMadd), + Operator::F64x2RelaxedNmadd => stringify!(F64x2RelaxedNmadd), + Operator::I16x8RelaxedDotI8x16I7x16S => stringify!(I16x8RelaxedDotI8x16I7x16S), + Operator::I32x4RelaxedDotI8x16I7x16AddS => stringify!(I32x4RelaxedDotI8x16I7x16AddS), + Operator::CallRef { .. } => stringify!(CallRef), + Operator::ReturnCallRef { .. } => stringify!(ReturnCallRef), + Operator::RefAsNonNull => stringify!(RefAsNonNull), + Operator::BrOnNull { .. } => stringify!(BrOnNull), + Operator::BrOnNonNull { .. } => stringify!(BrOnNonNull), } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index e498b7dc..8d7f4a7e 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,6 +1,6 @@ use crate::as_execution::ASModule; use crate::types::{Interface, InterfaceClone}; -use crate::{Compiler, GasCosts, RuntimeModule}; +use crate::{Compiler, CondomLimits, GasCosts, RuntimeModule}; use anyhow::Result; use massa_proto_rs::massa::model::v1::*; @@ -117,14 +117,26 @@ impl Interface for TestInterface { fn get_module(&self, bytecode: &[u8], gas_limit: u64) -> Result { println!("Get module"); - let as_module = ASModule::new(bytecode, gas_limit, GasCosts::default(), Compiler::CL)?; + let as_module = ASModule::new( + bytecode, + gas_limit, + GasCosts::default(), + Compiler::CL, + CondomLimits::default(), + )?; let module = RuntimeModule::ASModule(as_module); Ok(module) } fn get_tmp_module(&self, bytecode: &[u8], gas_limit: u64) -> Result { println!("Get tmp module"); - let as_module = ASModule::new(bytecode, gas_limit, GasCosts::default(), Compiler::SP)?; + let as_module = ASModule::new( + bytecode, + gas_limit, + GasCosts::default(), + Compiler::SP, + CondomLimits::default(), + )?; let module = RuntimeModule::ASModule(as_module); Ok(module) } @@ -397,8 +409,8 @@ impl Interface for TestInterface { fn create_module(&self, module: &[u8]) -> Result { if module.len() > 32 { let mut bytes = Vec::new(); - for i in 0..32 { - bytes.push(module[i]); + for item in module.iter().take(32) { + bytes.push(item); } println!("Create module with module (cut) {:?}", bytes.as_slice()); } else { diff --git a/src/tests/tests_gas_calibration.rs b/src/tests/tests_gas_calibration.rs index 028e9dae..c40634d3 100644 --- a/src/tests/tests_gas_calibration.rs +++ b/src/tests/tests_gas_calibration.rs @@ -4,7 +4,7 @@ use crate::middlewares::operator::{ _OPERATOR_BULK_MEMORY, _OPERATOR_NON_TRAPPING_FLOAT_TO_INT, _OPERATOR_THREAD, _OPERATOR_VECTOR, }; use crate::tests::TestInterface; -use crate::{run_main_gc, types::Interface, GasCosts, RuntimeModule}; +use crate::{run_main_gc, types::Interface, CondomLimits, GasCosts, RuntimeModule}; use std::collections::HashSet; use anyhow::Result; @@ -21,9 +21,21 @@ fn test_basic_abi_call_counter() -> Result<()> { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP)?; - let gas_calibration_result = - run_main_gc(&interface, runtime_module, b"", 100_000, gas_costs.clone())?; + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + )?; + let gas_calibration_result = run_main_gc( + &interface, + runtime_module, + b"", + 100_000, + gas_costs.clone(), + condom_limits.clone(), + )?; // println!("gas_calibration_result: {:?}", gas_calibration_result); // Note: @@ -82,11 +94,18 @@ fn test_basic_abi_call_counter_wasmv1() -> Result<()> { )); let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); // let runtime_module = // RuntimeModule::new(bytecode, 100_000, gas_costs.clone(), - // Compiler::SP)?; + // Compiler::SP, CondomLimits::default())?;?; - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -97,8 +116,14 @@ fn test_basic_abi_call_counter_wasmv1() -> Result<()> { } } - let gas_calibration_result = - run_main_gc(&*interface, runtime_module, b"", 100_000, gas_costs.clone())?; + let gas_calibration_result = run_main_gc( + &*interface, + runtime_module, + b"", + 100_000, + gas_costs.clone(), + condom_limits.clone(), + )?; // println!("gas_calibration_result: {:?}", gas_calibration_result); // Note: @@ -160,9 +185,21 @@ fn test_basic_abi_call_loop() -> Result<()> { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP)?; - let gas_calibration_result = - run_main_gc(&interface, runtime_module, b"", 100_000, gas_costs.clone())?; + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + )?; + let gas_calibration_result = run_main_gc( + &interface, + runtime_module, + b"", + 100_000, + gas_costs.clone(), + condom_limits.clone(), + )?; assert_eq!( gas_calibration_result.counters.len(), 2 + 5 + OPERATOR_CARDINALITY @@ -191,9 +228,21 @@ fn test_basic_abi_call_loop_wasmv1() -> Result<()> { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP)?; - let gas_calibration_result = - run_main_gc(&interface, runtime_module, b"", 100_000, gas_costs.clone())?; + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + )?; + let gas_calibration_result = run_main_gc( + &interface, + runtime_module, + b"", + 100_000, + gas_costs.clone(), + condom_limits.clone(), + )?; assert_eq!( gas_calibration_result.counters.len(), 2 + 2 + OPERATOR_CARDINALITY @@ -224,9 +273,21 @@ fn test_basic_op() -> Result<()> { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP)?; - let gas_calibration_result = - run_main_gc(&interface, runtime_module, b"", 100_000, gas_costs.clone())?; + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + )?; + let gas_calibration_result = run_main_gc( + &interface, + runtime_module, + b"", + 100_000, + gas_costs.clone(), + condom_limits.clone(), + )?; // 1 for env.abort + 4 env.abort parameters assert_eq!( gas_calibration_result.counters.len(), @@ -276,9 +337,21 @@ fn test_basic_op_wasmv1() -> Result<()> { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP)?; - let gas_calibration_result = - run_main_gc(&interface, runtime_module, b"", 100_000, gas_costs.clone())?; + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + )?; + let gas_calibration_result = run_main_gc( + &interface, + runtime_module, + b"", + 100_000, + gas_costs.clone(), + condom_limits.clone(), + )?; // 1 for env.abort + 1 env.abort parameters assert_eq!( gas_calibration_result.counters.len(), @@ -334,13 +407,20 @@ fn test_basic_abi_call_param_size() -> Result<()> { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP)?; + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + )?; let gas_calibration_result = run_main_gc( &interface, runtime_module, b"9876543", 100_000, gas_costs.clone(), + condom_limits.clone(), )?; // println!("gas_calibration_result: {:?}", gas_calibration_result); diff --git a/src/tests/tests_runtime.rs b/src/tests/tests_runtime.rs index f17b8fff..bd76f83e 100644 --- a/src/tests/tests_runtime.rs +++ b/src/tests/tests_runtime.rs @@ -1,11 +1,11 @@ use crate::as_execution::{ASContext, ASModule}; use crate::tests::TestInterface; -use crate::Compiler; use crate::{ run_function, run_main, types::{GasCosts, Interface}, RuntimeModule, }; +use crate::{Compiler, CondomLimits}; use rand::Rng; use serial_test::serial; use wasmer::Store; @@ -25,9 +25,23 @@ fn test_exhaustive_smart_contract() { "/wasm/test_exhaustive_smart_contract.wasm_add" )); let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&interface, runtime_module, 100_000_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -40,9 +54,23 @@ fn test_native_time_arithmetic_abis() { "/wasm/test_native_time_arithmetic.wasm_add" )); let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&interface, runtime_module, 100_000_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -55,9 +83,23 @@ fn test_structs_check_and_version_abis() { "/wasm/test_structs_check_and_version.wasm_add" )); let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&interface, runtime_module, 100_000_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -70,9 +112,23 @@ fn test_datastore_abis() { "/wasm/test_datastore.wasm_add" )); let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&interface, runtime_module, 100_000_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -85,9 +141,23 @@ fn test_ledger_op_keys_abis() { "/wasm/test_ledger_op_keys.wasm_add" )); let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&interface, runtime_module, 100_000_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -101,8 +171,22 @@ fn test_metering_safety() { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP).unwrap(); - let resp = run_main(&interface, runtime_module, 100_000, gas_costs.clone()).unwrap(); + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + let resp = run_main( + &interface, + runtime_module, + 100_000, + gas_costs.clone(), + condom_limits.clone(), + ) + .unwrap(); assert_ne!(resp.remaining_gas, 42); } @@ -117,8 +201,22 @@ fn test_instantiation_safety() { )); let gas_costs = GasCosts::default(); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP).unwrap(); - let error = run_main(&interface, runtime_module, 100_000, gas_costs.clone()).unwrap_err(); + let condom_limits = CondomLimits::default(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + let error = run_main( + &interface, + runtime_module, + 100_000, + gas_costs.clone(), + condom_limits.clone(), + ) + .unwrap_err(); let expected_error = "ABI calls are not available during instantiation"; assert!(error.to_string().contains(expected_error)); } @@ -128,11 +226,25 @@ fn test_instantiation_safety() { /// Test basic main-only SC execution fn test_run_main() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/basic_main.wasm")); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&*interface, runtime_module, 100_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &*interface, + runtime_module, + 100_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[cfg(feature = "execution-trace")] @@ -141,11 +253,25 @@ fn test_run_main() { /// Test basic main-only SC execution fn test_run_main_get_execution_traces() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/basic_main.wasm")); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - let resp = run_main(&*interface, runtime_module, 100_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + let resp = run_main( + &*interface, + runtime_module, + 100_000, + gas_costs, + condom_limits, + ) + .unwrap(); assert_eq!(resp.trace.is_empty(), false); assert_eq!( @@ -163,6 +289,7 @@ fn test_run_main_get_execution_traces() { #[serial] fn test_run_register_wasmv1() { // let gas_costs = GasCosts::default(); + // let condom_limits = CondomLimits::default(); // let interface: Box = // Box::new(TestInterface); // let module = include_bytes!(concat!( @@ -172,7 +299,7 @@ fn test_run_register_wasmv1() { // let runtime_module = // RuntimeModule::new(module, gas_costs.clone(), - // Compiler::SP).unwrap(); + // Compiler::SP, condom_limits.clone()))?;.unwrap(); // match runtime_module.clone() { // RuntimeModule::ASModule(_) => { @@ -207,7 +334,7 @@ fn test_run_register_wasmv1() { // )); // let runtime_module = -// RuntimeModule::new(module, gas_costs.clone(), Compiler::SP) +// RuntimeModule::new(module, gas_costs.clone(), Compiler::SP, condom_limits.clone())?; // .unwrap(); // match runtime_module.clone() { @@ -218,7 +345,7 @@ fn test_run_register_wasmv1() { // println!("Module type WasmV1Module"); // } // } -// run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); +// run_main(&*interface, runtime_module, 100_000_000, gas_costs, condom_limits).unwrap(); // } #[test] @@ -226,13 +353,20 @@ fn test_run_register_wasmv1() { /// Test test_get_current_period_and_thread fn test_get_current_period_and_thread_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_period_thread.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -242,7 +376,14 @@ fn test_get_current_period_and_thread_wasmv1_as() { println!("Module type WasmV1Module"); } } - run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); + run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -250,13 +391,20 @@ fn test_get_current_period_and_thread_wasmv1_as() { /// Test test_native_hash fn test_native_hash_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_hash.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -266,7 +414,14 @@ fn test_native_hash_wasmv1_as() { println!("Module type WasmV1Module"); } } - run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); + run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -274,13 +429,20 @@ fn test_native_hash_wasmv1_as() { /// This test call the main function of a SC that calls generate_event abi fn test_generate_event_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_generate_event.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -290,7 +452,14 @@ fn test_generate_event_wasmv1_as() { println!("Module type WasmV1Module"); } } - run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); + run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -298,13 +467,20 @@ fn test_generate_event_wasmv1_as() { /// This test arithmetic operations on native amount fn test_native_amount_arithmetic_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_native_amount_arithmetic.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -314,7 +490,14 @@ fn test_native_amount_arithmetic_wasmv1_as() { println!("Module type WasmV1Module"); } } - run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); + run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -322,13 +505,20 @@ fn test_native_amount_arithmetic_wasmv1_as() { /// This test call the main function of a SC that will abort fn test_abort_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_abort.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -339,7 +529,13 @@ fn test_abort_wasmv1_as() { } } - let res = run_main(&*interface, runtime_module, 100_000, gas_costs); + let res = run_main( + &*interface, + runtime_module, + 100_000, + gas_costs, + condom_limits, + ); match res { Err(e) if e.to_string().contains("abort test message") => { @@ -361,13 +557,20 @@ fn test_abort_wasmv1_as() { /// This test call the main function of a SC that will abort fn test_assert_in_release_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_assert_in_release.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -378,7 +581,13 @@ fn test_assert_in_release_wasmv1_as() { } } - let res = run_main(&*interface, runtime_module, 100_000_000, gas_costs); + let res = run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ); match res { Err(e) if e.to_string().contains("expected assert") => { @@ -400,13 +609,20 @@ fn test_assert_in_release_wasmv1_as() { /// This test call the main function of a SC that calls transfer_coins abi fn test_transfer_coins_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_transfer_coins.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -417,7 +633,14 @@ fn test_transfer_coins_wasmv1_as() { } } - let _resp = run_main(&*interface, runtime_module, 100_000, gas_costs).unwrap(); + let _resp = run_main( + &*interface, + runtime_module, + 100_000, + gas_costs, + condom_limits, + ) + .unwrap(); #[cfg(feature = "execution-trace")] { @@ -442,13 +665,20 @@ fn test_transfer_coins_wasmv1_as() { /// This test call the main function of a SC that calls bs58 encode/decode abi fn test_bs58_to_from_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_bs58_to_from.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -458,7 +688,14 @@ fn test_bs58_to_from_wasmv1_as() { println!("Module type WasmV1Module"); } } - run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); + run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -466,13 +703,20 @@ fn test_bs58_to_from_wasmv1_as() { /// This test call the main function of a SC that calls comparisons abis fn test_compare_wasmv1_as() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/test_compare.wasm_add" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match runtime_module.clone() { RuntimeModule::ASModule(_) => { @@ -482,7 +726,14 @@ fn test_compare_wasmv1_as() { println!("Module type WasmV1Module"); } } - run_main(&*interface, runtime_module, 100_000_000, gas_costs).unwrap(); + run_main( + &*interface, + runtime_module, + 100_000_000, + gas_costs, + condom_limits, + ) + .unwrap(); } #[test] @@ -490,11 +741,27 @@ fn test_compare_wasmv1_as() { /// Test basic function-only SC execution fn test_run_function() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/basic_func.wasm")); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_function(&*interface, runtime_module, "ping", b"", 100_000, gas_costs).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_function( + &*interface, + runtime_module, + "ping", + b"", + 100_000, + gas_costs, + condom_limits, + ) + .unwrap(); } // NOTE: this test is outdated as module are now pre-compiled with max_instance_cost @@ -508,7 +775,7 @@ fn test_run_function() { // let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/basic_main.wasm")); // // Test giving not enough gas to create the instance -// let runtime_module = RuntimeModule::new(module, 100, gas_costs.clone(), Compiler::SP).unwrap(); +// let runtime_module = RuntimeModule::new(module, 100, gas_costs.clone(), Compiler::SP, condom_limits.clone()).unwrap(); // let error = run_main(&*interface, runtime_module, 100_000, gas_costs.clone()) // .unwrap_err() // .to_string(); @@ -519,7 +786,7 @@ fn test_run_function() { // // Test giving enough gas to create the instance but not enough for the VM // let runtime_module = -// RuntimeModule::new(module, 100_000, gas_costs.clone(), Compiler::SP).unwrap(); +// RuntimeModule::new(module, 100_000, gas_costs.clone(), Compiler::SP, condom_limits.clone()).unwrap(); // let error = run_main(&*interface, runtime_module, 100, gas_costs) // .unwrap_err() // .to_string(); @@ -531,11 +798,24 @@ fn test_run_function() { /// Test that a no-main SC executed through `run_main` fails as expected fn test_run_main_without_main() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/no_main.wasm")); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&*interface, runtime_module, 100_000, gas_costs) - .expect_err("An error should spawn here"); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &*interface, + runtime_module, + 100_000, + gas_costs, + condom_limits, + ) + .expect_err("An error should spawn here"); } #[test] @@ -546,15 +826,23 @@ fn test_run_main_without_main() { /// This test ensure that this initial cost is correctly debited. fn test_run_empty_main() { let mut gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/empty_main.wasm")); gas_costs.launch_cost = 0; - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); let a = run_main( &*interface, runtime_module.clone(), 10_000_000, gas_costs.clone(), + condom_limits.clone(), ) .expect("Failed to run empty_main.wasm"); // Here we avoid hard-coding a value (that can change in future wasmer @@ -564,8 +852,14 @@ fn test_run_empty_main() { let mut rng = rand::thread_rng(); let cost = rng.gen_range(1..1_000_000); gas_costs.launch_cost = cost; - let b = run_main(&*interface, runtime_module, 10_000_000, gas_costs) - .expect("Failed to run empty_main.wasm"); + let b = run_main( + &*interface, + runtime_module, + 10_000_000, + gas_costs, + condom_limits, + ) + .expect("Failed to run empty_main.wasm"); // Between 2 calls, the metering cost should be the difference assert_eq!(a.remaining_gas - b.remaining_gas, cost); } @@ -584,7 +878,7 @@ fn test_run_main_rust_wasmv1() { // "/../massa-rust-sc-examples/target/wasm32-unknown-unknown/debug/ // massa_rust_sc_deploy_sc.wasm_add")); gas_costs.launch_cost = 0; // let runtime_module = - // RuntimeModule::new(module, gas_costs.clone(), Compiler::SP) + // RuntimeModule::new(module, gas_costs.clone(), Compiler::SP, condom_limits.clone())?; // .unwrap(); // let a = match run_main( @@ -619,11 +913,24 @@ fn test_run_main_rust_wasmv1() { /// * getOpData fn test_op_fn() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/op_fn.wasm")); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - run_main(&*interface, runtime_module, 10_000_000, gas_costs.clone()) - .expect("Failed to run op_fn.wasm"); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + run_main( + &*interface, + runtime_module, + 10_000_000, + gas_costs.clone(), + condom_limits.clone(), + ) + .expect("Failed to run op_fn.wasm"); } /// Test `seed`, `Date.now`, `console.log` and `abort` @@ -633,14 +940,27 @@ fn test_op_fn() { #[serial] fn test_builtins() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/use_builtins.wasm" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); // let before = chrono::offset::Utc::now().timestamp_millis(); - match run_main(&*interface, runtime_module, 10_000_000, gas_costs.clone()) { + match run_main( + &*interface, + runtime_module, + 10_000_000, + gas_costs.clone(), + condom_limits.clone(), + ) { Err(e) => { let msg = e.to_string(); // make sure the error was caused by a manual abort @@ -666,13 +986,20 @@ fn test_builtins() { /// These are AS functions that we choose to handle in the VM fn test_builtin_assert_and_exit() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let module = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/wasm/use_builtin_assert.wasm" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match run_function( &*interface, runtime_module, @@ -680,6 +1007,7 @@ fn test_builtin_assert_and_exit() { b"", 100_000, gas_costs.clone(), + condom_limits.clone(), ) { Err(e) => { assert!(e.to_string().contains("Result is not true!")) @@ -687,15 +1015,24 @@ fn test_builtin_assert_and_exit() { _ => panic!("test should return an error!"), } - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); - if let Ok(_) = run_function( + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + if run_function( &*interface, runtime_module, "assert_no_msg", b"", 100_000, gas_costs.clone(), - ) { + condom_limits.clone(), + ) + .is_ok() + { panic!("test should return an error!"); } @@ -704,7 +1041,13 @@ fn test_builtin_assert_and_exit() { "/wasm/use_builtin_exit.wasm" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match run_function( &*interface, runtime_module, @@ -712,6 +1055,7 @@ fn test_builtin_assert_and_exit() { b"", 100_000, gas_costs.clone(), + condom_limits.clone(), ) { Err(e) => { assert!(e.to_string().contains("exit with code: 0")) @@ -719,7 +1063,13 @@ fn test_builtin_assert_and_exit() { _ => panic!("test should return an error!"), } - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); match run_function( &*interface, runtime_module, @@ -727,6 +1077,7 @@ fn test_builtin_assert_and_exit() { b"", 100_000, gas_costs, + condom_limits, ) { Err(e) => { assert!(e.to_string().contains("exit with code: 2")) @@ -740,6 +1091,7 @@ fn test_builtin_assert_and_exit() { /// Test WASM files compiled with unsupported builtin functions fn test_unsupported_builtins() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); // Test for hrtime @@ -747,9 +1099,21 @@ fn test_unsupported_builtins() { env!("CARGO_MANIFEST_DIR"), "/wasm/unsupported_builtin_hrtime.wasm" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); - match run_main(&*interface, runtime_module, 10_000_000, gas_costs.clone()) { + match run_main( + &*interface, + runtime_module, + 10_000_000, + gas_costs.clone(), + condom_limits.clone(), + ) { Err(e) => { assert!(e .to_string() @@ -763,9 +1127,21 @@ fn test_unsupported_builtins() { env!("CARGO_MANIFEST_DIR"), "/wasm/unsupported_builtin_random_values.wasm" )); - let runtime_module = RuntimeModule::new(module, gas_costs.clone(), Compiler::SP).unwrap(); + let runtime_module = RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); - match run_main(&*interface, runtime_module, 10_000_000, gas_costs.clone()) { + match run_main( + &*interface, + runtime_module, + 10_000_000, + gas_costs.clone(), + condom_limits.clone(), + ) { Err(e) => { assert!(e .to_string() @@ -784,27 +1160,44 @@ fn test_unsupported_builtins() { fn test_wat() { { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let bytecode = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/dummy.wat")); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ); match runtime_module { - Ok(_) => assert!(false, ".wat are not supported anymore"), + Ok(_) => panic!(".wat are not supported anymore"), Err(err) => { - assert_eq!( - true, - err.to_string().contains("Unsupported file format for SC") - ); + assert!(err.to_string().contains("Unsupported file format for SC")); } } } { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let interface: Box = Box::new(TestInterface); let bytecode = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/dummy.wasm")); - let runtime_module = RuntimeModule::new(bytecode, gas_costs.clone(), Compiler::SP).unwrap(); - let response = run_main(&*interface, runtime_module, 100_000, gas_costs.clone()).unwrap(); + let runtime_module = RuntimeModule::new( + bytecode, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) + .unwrap(); + let response = run_main( + &*interface, + runtime_module, + 100_000, + gas_costs.clone(), + condom_limits.clone(), + ) + .unwrap(); // Note: for now, exec main always return an empty vec let excepted: Vec = Vec::new(); @@ -817,9 +1210,15 @@ fn test_wat() { /// Test a WASM execution using features disabled in engine (simd & threads) fn test_features_disabled() { let gas_costs = GasCosts::default(); + let condom_limits = CondomLimits::default(); let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/simd.wasm")); - match RuntimeModule::new(module, gas_costs.clone(), Compiler::SP) { + match RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) { Err(e) => { // println!("Error: {}", e); assert!(e @@ -830,7 +1229,12 @@ fn test_features_disabled() { } let module = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/wasm/threads.wasm")); - match RuntimeModule::new(module, gas_costs.clone(), Compiler::SP) { + match RuntimeModule::new( + module, + gas_costs.clone(), + Compiler::SP, + condom_limits.clone(), + ) { Err(e) => { // println!("Error: {}", e); assert!(e @@ -851,9 +1255,21 @@ fn test_class_id() { env!("CARGO_MANIFEST_DIR"), "/wasm/return_basic.wasm" )); - let module = ASModule::new(bytecode, 100_000, GasCosts::default(), Compiler::SP).unwrap(); + let module = ASModule::new( + bytecode, + 100_000, + GasCosts::default(), + Compiler::SP, + CondomLimits::default(), + ) + .unwrap(); let mut store = Store::new(module._engine); - let mut context = ASContext::new(&*interface, module.binary_module, GasCosts::default()); + let mut context = ASContext::new( + &*interface, + module.binary_module, + GasCosts::default(), + CondomLimits::default(), + ); let (instance, _function_env, _) = context.create_vm_instance_and_init_env(&mut store).unwrap(); // setup test specific context diff --git a/src/types.rs b/src/types.rs index 3d0c0250..2e07ded2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -166,6 +166,25 @@ impl Clone for Box { } } +#[derive(Clone, Debug, Default)] +pub struct CondomLimits { + pub max_exports: Option, + pub max_functions: Option, + pub max_signature_len: Option, + pub max_name_len: Option, + pub max_imports_len: Option, + pub max_table_initializers_len: Option, + pub max_passive_elements_len: Option, + pub max_passive_data_len: Option, + pub max_global_initializers_len: Option, + pub max_function_names_len: Option, + pub max_tables_count: Option, + pub max_memories_len: Option, + pub max_globals_len: Option, + pub max_custom_sections_len: Option, + pub max_custom_sections_data_len: Option, +} + #[derive(Clone, Debug)] pub struct GasCosts { pub(crate) abi_costs: HashMap, diff --git a/src/wasmv1_execution/abi/abis.rs b/src/wasmv1_execution/abi/abis.rs index 82cc6df8..996aeb8c 100644 --- a/src/wasmv1_execution/abi/abis.rs +++ b/src/wasmv1_execution/abi/abis.rs @@ -159,6 +159,7 @@ fn abi_call(store_env: FunctionEnvMut, arg_offset: i32) -> Result, arg_offset: i32) -> Result< &req.function_arg, remaining_gas, handler.get_gas_costs().clone(), + handler.get_condom_limits().clone(), ) .map_err(|err| WasmV1Error::RuntimeError(format!("Could not run function: {}", err)))?; handler.set_remaining_gas(response.remaining_gas); @@ -1029,6 +1031,7 @@ fn abi_local_execution( &req.function_arg, remaining_gas, handler.get_gas_costs().clone(), + handler.get_condom_limits().clone(), ) { Ok(response) => { handler.set_remaining_gas(response.remaining_gas); diff --git a/src/wasmv1_execution/abi/handler.rs b/src/wasmv1_execution/abi/handler.rs index 1d0ae960..cdcce5af 100644 --- a/src/wasmv1_execution/abi/handler.rs +++ b/src/wasmv1_execution/abi/handler.rs @@ -1,5 +1,5 @@ use super::super::env::{ABIEnv, ExecutionEnv}; -use crate::{wasmv1_execution::WasmV1Error, GasCosts}; +use crate::{wasmv1_execution::WasmV1Error, CondomLimits, GasCosts}; use std::io::Cursor; use wasmer::FunctionEnvMut; @@ -180,6 +180,11 @@ impl<'a, 'b> ABIHandler<'a, 'b> { .unwrap_or(&0) } + /// Get condom limits + pub fn get_condom_limits(&self) -> &CondomLimits { + self.exec_env.get_condom_limits() + } + /// Get the memory maximum size in bytes pub fn get_max_mem_size(&mut self) -> u64 { self.exec_env.get_max_mem_size(self.store_env) diff --git a/src/wasmv1_execution/env.rs b/src/wasmv1_execution/env.rs index 5cc9f08a..814a14c6 100644 --- a/src/wasmv1_execution/env.rs +++ b/src/wasmv1_execution/env.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use super::{ffi::Ffi, WasmV1Error}; -use crate::types::Interface; use crate::GasCosts; +use crate::{types::Interface, CondomLimits}; use parking_lot::Mutex; use wasmer::{AsStoreMut, AsStoreRef, Imports, Instance, InstantiationError, TypedFunction}; use wasmer_middlewares::metering::{self, MeteringPoints}; @@ -27,6 +27,9 @@ pub struct ExecutionEnv { ffi: Ffi, /// Gas cost of instance creation init_gas_cost: u64, + /// Maximum number of exports + condom_limits: CondomLimits, + #[cfg(feature = "execution-trace")] pub trace: Vec, } @@ -40,6 +43,7 @@ impl ExecutionEnv { interface: &dyn Interface, gas_costs: GasCosts, import_object: &Imports, + condom_limits: CondomLimits, ) -> Result { // Create the instance let instance = match Instance::new(store, &module.binary_module, import_object) { @@ -92,6 +96,7 @@ impl ExecutionEnv { instance, ffi, init_gas_cost, + condom_limits, #[cfg(feature = "execution-trace")] trace: Default::default(), }) @@ -198,6 +203,11 @@ impl ExecutionEnv { &self.gas_costs } + /// Get the condom limits. + pub fn get_condom_limits(&self) -> &CondomLimits { + &self.condom_limits + } + /// Get the memory maximum size in bytes pub fn get_max_mem_size(&self, store: &mut impl AsStoreMut) -> u64 { self.ffi.get_max_mem_size(&store) diff --git a/src/wasmv1_execution/mod.rs b/src/wasmv1_execution/mod.rs index b2b297ca..208914af 100644 --- a/src/wasmv1_execution/mod.rs +++ b/src/wasmv1_execution/mod.rs @@ -6,20 +6,25 @@ mod ffi; use self::env::{ABIEnv, ExecutionEnv}; use crate::error::VMResult; use crate::execution::Compiler; +use crate::middlewares::condom::CondomMiddleware; use crate::middlewares::gas_calibration::{ get_gas_calibration_result, GasCalibration, GasCalibrationResult, }; use crate::settings::max_number_of_pages; use crate::tunable_memory::LimitingTunables; -use crate::{GasCosts, Interface, Response, VMError}; +use crate::{CondomLimits, GasCosts, Interface, Response, VMError}; use abi::*; use anyhow::Result; pub(crate) use error::*; use parking_lot::Mutex; use std::sync::Arc; use wasmer::NativeEngineExt; -use wasmer::{wasmparser::Operator, BaseTunables, EngineBuilder, Pages, Target}; -use wasmer::{CompilerConfig, Cranelift, Engine, Features, Module, Store}; +use wasmer::{sys::Features, CompilerConfig, Cranelift, Engine, Module, Store}; +use wasmer::{ + sys::{BaseTunables, EngineBuilder}, + wasmparser::Operator, + Pages, Target, +}; use wasmer_compiler_singlepass::Singlepass; use wasmer_middlewares::Metering; @@ -39,10 +44,11 @@ impl WasmV1Module { limit: u64, gas_costs: GasCosts, compiler: Compiler, + condom_limits: CondomLimits, ) -> Result { let engine = match compiler { - Compiler::CL => init_cl_engine(limit, gas_costs), - Compiler::SP => init_sp_engine(limit, gas_costs), + Compiler::CL => init_cl_engine(limit, gas_costs, condom_limits), + Compiler::SP => init_sp_engine(limit, gas_costs, condom_limits), }; let binary_module = match Module::new(&engine, bytecode) { Ok(module) => module, @@ -76,9 +82,14 @@ impl WasmV1Module { } /// Deserialize a module - pub fn deserialize(ser_module: &[u8], limit: u64, gas_costs: GasCosts) -> Result { + pub fn deserialize( + ser_module: &[u8], + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, + ) -> Result { // Deserialization is only meant for Cranelift modules - let engine = init_cl_engine(limit, gas_costs); + let engine = init_cl_engine(limit, gas_costs, condom_limits); let store = Store::new(engine.clone()); // Unsafe because code injection is possible // That's not an issue because we only deserialize modules we have @@ -129,7 +140,11 @@ const FEATURES: Features = Features { extended_const: false, // experimental }; -pub(crate) fn init_sp_engine(limit: u64, gas_costs: GasCosts) -> Engine { +pub(crate) fn init_sp_engine( + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, +) -> Engine { // Singlepass is used to compile arbitrary bytecode. // // Reference: @@ -138,7 +153,7 @@ pub(crate) fn init_sp_engine(limit: u64, gas_costs: GasCosts) -> Engine { // Canonicalize NaN compiler_config.canonicalize_nans(true); - add_middleware(&mut compiler_config, limit, gas_costs); + add_middleware(&mut compiler_config, limit, gas_costs, condom_limits); let base = BaseTunables::for_target(&Target::default()); let tunables = LimitingTunables::new(base, Pages(max_number_of_pages())); @@ -152,7 +167,11 @@ pub(crate) fn init_sp_engine(limit: u64, gas_costs: GasCosts) -> Engine { engine } -pub(crate) fn init_cl_engine(limit: u64, gas_costs: GasCosts) -> Engine { +pub(crate) fn init_cl_engine( + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, +) -> Engine { // Cranelift is used to compile bytecode that will be cached. // // Reference: @@ -161,7 +180,7 @@ pub(crate) fn init_cl_engine(limit: u64, gas_costs: GasCosts) -> Engine { // Canonicalize NaN compiler_config.canonicalize_nans(true); - add_middleware(&mut compiler_config, limit, gas_costs); + add_middleware(&mut compiler_config, limit, gas_costs, condom_limits); let base = BaseTunables::for_target(&Target::default()); let tunables = LimitingTunables::new(base, Pages(max_number_of_pages())); @@ -175,10 +194,18 @@ pub(crate) fn init_cl_engine(limit: u64, gas_costs: GasCosts) -> Engine { engine } -fn add_middleware(compiler_config: &mut T, limit: u64, gas_costs: GasCosts) -where +fn add_middleware( + compiler_config: &mut T, + limit: u64, + gas_costs: GasCosts, + condom_limits: CondomLimits, +) where T: CompilerConfig, { + // Add condom middleware + let condom_middleware = Arc::new(CondomMiddleware::new(condom_limits)); + compiler_config.push_middleware(condom_middleware); + if cfg!(feature = "gas_calibration") { // Add gas calibration middleware let gas_calibration = Arc::new(GasCalibration::new()); @@ -199,11 +226,12 @@ pub(crate) fn exec_wasmv1_module( param: &[u8], gas_limit: u64, gas_costs: GasCosts, + condom_limits: CondomLimits, ) -> VMResult<(Response, Option)> { // Init store let engine = match module.compiler { - Compiler::CL => init_cl_engine(gas_limit, gas_costs.clone()), - Compiler::SP => init_sp_engine(gas_limit, gas_costs.clone()), + Compiler::CL => init_cl_engine(gas_limit, gas_costs.clone(), condom_limits.clone()), + Compiler::SP => init_sp_engine(gas_limit, gas_costs.clone(), condom_limits.clone()), }; let mut store = Store::new(engine); @@ -215,14 +243,20 @@ pub(crate) fn exec_wasmv1_module( interface.save_gas_remaining_before_subexecution(gas_limit); // Create an instance of the execution environment. - let execution_env = - ExecutionEnv::create_instance(&mut store, &module, interface, gas_costs, &import_object) - .map_err(|err| { - VMError::InstanceError(format!( - "Failed to create instance of execution environment: {}", - err - )) - })?; + let execution_env = ExecutionEnv::create_instance( + &mut store, + &module, + interface, + gas_costs, + &import_object, + condom_limits, + ) + .map_err(|err| { + VMError::InstanceError(format!( + "Failed to create instance of execution environment: {}", + err + )) + })?; // Get gas cost of instance creation let init_gas_cost = execution_env.get_init_gas_cost(); diff --git a/wasm/simple-custom-section.wasm b/wasm/simple-custom-section.wasm new file mode 100644 index 00000000..ce4e1557 Binary files /dev/null and b/wasm/simple-custom-section.wasm differ diff --git a/wasm/simple.wat b/wasm/simple.wat new file mode 100644 index 00000000..236ddb73 --- /dev/null +++ b/wasm/simple.wat @@ -0,0 +1,5 @@ +(module + (type (;0;) (func (result i32))) + (func $my_function (type 0) (result i32) + i32.const 42) + (export "my_named_function" (func $my_function)))