diff --git a/Cargo.lock b/Cargo.lock index c5e5e392ef3..9fad58a65a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli 0.28.1", + "gimli 0.31.1", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -29,9 +29,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -78,9 +78,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -108,47 +108,48 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -156,21 +157,21 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "as-ffi-bindings" @@ -203,7 +204,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", "synstructure", @@ -215,7 +216,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -228,9 +229,9 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -239,24 +240,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -267,15 +268,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -292,8 +293,8 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", - "tower", + "sync_wrapper 1.0.1", + "tower 0.5.1", "tower-layer", "tower-service", ] @@ -313,24 +314,24 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", ] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.32.2", + "object 0.36.5", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -341,9 +342,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" @@ -370,12 +371,12 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -386,9 +387,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -405,9 +406,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec", @@ -436,9 +437,9 @@ dependencies = [ [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "sha2 0.10.8", "tinyvec", @@ -446,15 +447,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytecheck" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ "bytecheck_derive", "ptr_meta", @@ -463,11 +464,11 @@ dependencies = [ [[package]] name = "bytecheck_derive" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -521,12 +522,13 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -550,24 +552,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -576,15 +584,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -602,9 +610,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -613,9 +621,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.11" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -623,33 +631,33 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.86", + "heck 0.5.0", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clipboard-win" @@ -664,18 +672,18 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" dependencies = [ "cc", ] [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "combine" @@ -708,15 +716,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -727,9 +735,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation" @@ -743,9 +751,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "corosensei" @@ -762,9 +770,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -854,9 +862,9 @@ checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -899,11 +907,10 @@ dependencies = [ [[package]] name = "crossbeam" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eb9105919ca8e40d437fc9cbb8f1975d916f1bd28afe795a48aae32a2cc8920" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ - "cfg-if", "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", @@ -913,54 +920,46 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc6598521bb5a83d491e8c1fe51db7296019d2ca3cb93cc6c2a20369a4d78a2" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1000,12 +999,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.2" +version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ - "nix 0.27.1", - "windows-sys 0.52.0", + "nix 0.29.0", + "windows-sys 0.59.0", ] [[package]] @@ -1030,9 +1029,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1047,12 +1046,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.3", - "darling_macro 0.20.3", + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -1063,24 +1062,24 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "strsim", - "syn 2.0.75", + "strsim 0.11.1", + "syn 2.0.79", ] [[package]] @@ -1096,13 +1095,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.3", + "darling_core 0.20.10", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1112,7 +1111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -1126,7 +1125,7 @@ checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", "crossbeam-utils", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -1134,15 +1133,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -1164,9 +1163,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", @@ -1178,7 +1177,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -1199,7 +1198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -1276,13 +1275,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1322,7 +1321,7 @@ dependencies = [ "byteorder", "lazy_static", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -1350,9 +1349,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", @@ -1366,9 +1365,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encode_unicode" @@ -1397,7 +1396,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -1409,7 +1408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8ea75f31022cba043afe037940d73684327e915f88f62478e778c3de914cd0a" dependencies = [ "enum_delegate_lib", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -1420,7 +1419,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e1f6c3800b304a6be0012039e2a45a322a093539c45ab818d9e6895a39c90fe" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "rand", "syn 1.0.109", @@ -1428,23 +1427,23 @@ dependencies = [ [[package]] name = "enumset" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" +checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" dependencies = [ "enumset_derive", ] [[package]] name = "enumset_derive" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" dependencies = [ - "darling 0.20.3", - "proc-macro2 1.0.86", + "darling 0.20.10", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1464,9 +1463,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1490,9 +1489,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fd-lock" @@ -1501,15 +1500,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix 0.38.34", + "rustix", "windows-sys 0.48.0", ] [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" @@ -1519,7 +1518,7 @@ checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "libredox 0.1.3", + "libredox", "windows-sys 0.59.0", ] @@ -1531,9 +1530,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -1592,9 +1591,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1607,9 +1606,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1617,15 +1616,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1634,38 +1633,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers", "send_wrapper", @@ -1673,9 +1672,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1723,9 +1722,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", @@ -1744,9 +1743,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1811,8 +1810,8 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.11", - "indexmap 2.4.0", + "http 0.2.12", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1831,7 +1830,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1840,9 +1839,13 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -1850,7 +1853,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -1861,9 +1864,15 @@ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "hdrhistogram" @@ -1889,9 +1898,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "hex" @@ -1946,9 +1961,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1973,7 +1988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.11", + "http 0.2.12", "pin-project-lite", ] @@ -2002,9 +2017,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2020,15 +2035,15 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "http 0.2.11", + "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", @@ -2043,9 +2058,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -2070,7 +2085,7 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "log", "rustls", @@ -2086,7 +2101,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "pin-project-lite", "tokio", @@ -2095,29 +2110,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2165,12 +2179,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.15.0", "serde", ] @@ -2185,24 +2199,13 @@ dependencies = [ [[package]] name = "intrusive-collections" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b694dc9f70c3bda874626d2aed13b780f137aab435f4e9814121955cf706122e" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" dependencies = [ "memoffset", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ip_rfc" version = "0.1.0" @@ -2211,15 +2214,21 @@ checksum = "6b8a253fc120dd6c624b7beb0a82330fc0135e0a9cec685bf039a07ba032af1e" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi", - "rustix 0.38.34", - "windows-sys 0.48.0", + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -2231,18 +2240,27 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jni" @@ -2266,18 +2284,18 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2372,7 +2390,7 @@ dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-rustls", "hyper-util", "jsonrpsee-core", @@ -2383,7 +2401,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] @@ -2395,10 +2413,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.86", + "proc-macro-crate", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -2411,7 +2429,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", @@ -2424,7 +2442,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] @@ -2466,18 +2484,18 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -2493,18 +2511,18 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "winapi", + "windows-targets 0.52.6", ] [[package]] @@ -2513,26 +2531,15 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "libredox" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" -dependencies = [ - "bitflags 2.4.1", - "libc", - "redox_syscall 0.4.1", -] - [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "libc", - "redox_syscall 0.5.7", + "redox_syscall", ] [[package]] @@ -2601,9 +2608,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "pkg-config", @@ -2618,15 +2625,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litrs" @@ -2636,9 +2637,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2646,9 +2647,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loupe" @@ -2672,9 +2673,9 @@ dependencies = [ [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -2724,7 +2725,7 @@ dependencies = [ "strum", "strum_macros", "tokio", - "toml_edit 0.21.0", + "toml_edit 0.21.1", ] [[package]] @@ -2747,6 +2748,7 @@ dependencies = [ "massa_consensus_worker", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_execution_exports", "massa_execution_worker", @@ -2782,7 +2784,7 @@ dependencies = [ [[package]] name = "massa-proto-rs" version = "0.1.0" -source = "git+https://github.com/massalabs/massa-proto-rs?branch=mainnet_2_3#860785129328e3132a020da1eab1a677e8eeea14" +source = "git+https://github.com/massalabs/massa-proto-rs?rev=b5267178eaf266ec724691d7de163e4c34343416#b5267178eaf266ec724691d7de163e4c34343416" dependencies = [ "glob", "prost", @@ -2796,11 +2798,11 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?branch=next_breaking_update#d06eca4c1126c20f1e705a0ab42fdd44c5853d0a" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=82dd714d38cbcd863ae0bb215c06442917bb6404#82dd714d38cbcd863ae0bb215c06442917bb6404" dependencies = [ "anyhow", "as-ffi-bindings", - "base64 0.21.5", + "base64 0.21.7", "chrono", "displaydoc", "function_name", @@ -2836,7 +2838,7 @@ dependencies = [ "async-trait", "futures", "http 1.1.0", - "itertools 0.12.0", + "itertools 0.12.1", "jsonrpsee", "massa_api_exports", "massa_channel", @@ -2862,7 +2864,7 @@ dependencies = [ "tempfile", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tower-http 0.6.1", "tracing", ] @@ -2873,6 +2875,7 @@ version = "2.5.0" dependencies = [ "displaydoc", "jsonrpsee", + "massa_deferred_calls", "massa_final_state", "massa_hash", "massa_models", @@ -2923,6 +2926,7 @@ dependencies = [ "massa_consensus_exports", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_final_state", "massa_hash", @@ -2938,7 +2942,7 @@ dependencies = [ "massa_test_framework", "massa_time", "massa_versioning", - "mio", + "mio 0.8.11", "mockall", "nom", "num", @@ -3007,7 +3011,7 @@ version = "2.5.0" dependencies = [ "crossbeam", "crossbeam-channel", - "itertools 0.12.0", + "itertools 0.12.1", "massa_channel", "massa_consensus_exports", "massa_execution_exports", @@ -3058,6 +3062,24 @@ dependencies = [ "tempfile", ] +[[package]] +name = "massa_deferred_calls" +version = "2.2.0" +dependencies = [ + "massa-proto-rs", + "massa_db_exports", + "massa_db_worker", + "massa_ledger_exports", + "massa_models", + "massa_serialization", + "nom", + "parking_lot", + "serde", + "serde_json", + "serde_with", + "tempfile", +] + [[package]] name = "massa_executed_ops" version = "2.5.0" @@ -3079,6 +3101,7 @@ dependencies = [ "displaydoc", "massa-proto-rs", "massa-sc-runtime", + "massa_deferred_calls", "massa_final_state", "massa_hash", "massa_models", @@ -3112,6 +3135,7 @@ dependencies = [ "massa_channel", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_execution_exports", "massa_final_state", @@ -3197,6 +3221,7 @@ dependencies = [ "massa_async_pool", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_hash", "massa_ledger_exports", @@ -3226,8 +3251,8 @@ dependencies = [ "displaydoc", "futures-util", "h2 0.3.26", - "hyper 1.4.1", - "itertools 0.12.0", + "hyper 1.5.0", + "itertools 0.12.1", "massa-proto-rs", "massa_bootstrap", "massa_consensus_exports", @@ -3325,7 +3350,7 @@ dependencies = [ name = "massa_metrics" version = "2.5.0" dependencies = [ - "hyper 0.14.30", + "hyper 0.14.31", "lazy_static", "prometheus", "tokio", @@ -3647,7 +3672,7 @@ version = "2.5.0" dependencies = [ "massa-sc-runtime", "massa_models", - "toml_edit 0.21.0", + "toml_edit 0.21.1", "walkdir", ] @@ -3668,9 +3693,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -3692,9 +3717,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -3725,11 +3750,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -3744,6 +3769,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "mockall" version = "0.11.4" @@ -3766,7 +3803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -3777,9 +3814,9 @@ version = "0.11.2" source = "git+https://github.com/AurelienFT/mockall-wrap?rev=18f88253a000df96cf407dfe4b9158c69c0aeb96#18f88253a000df96cf407dfe4b9158c69c0aeb96" dependencies = [ "cfg-if", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -3796,9 +3833,9 @@ checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "multimap" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "nibble_vec" @@ -3822,12 +3859,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cfg-if", + "cfg_aliases", "libc", ] @@ -3859,9 +3897,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -3873,11 +3911,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", @@ -3885,9 +3922,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", "serde", @@ -3901,19 +3938,18 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -3922,11 +3958,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -3935,43 +3970,33 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.86", + "proc-macro-crate", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -3988,9 +4013,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -4012,21 +4037,21 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" @@ -4064,9 +4089,9 @@ checksum = "5ac1db209d9d6dc8e4435b744ed76198494406cd20eb8ca14baf9828664664c8" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -4074,18 +4099,18 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "backtrace", "cfg-if", "libc", "petgraph", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "thread-id", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4101,15 +4126,15 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "pbkdf2" @@ -4137,7 +4162,7 @@ dependencies = [ "crossbeam", "enum_delegate", "log", - "mio", + "mio 0.8.11", "parking_lot", "quiche", "rand", @@ -4148,11 +4173,11 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.21.5", + "base64 0.22.1", "serde", ] @@ -4164,9 +4189,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -4175,9 +4200,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.5" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -4185,22 +4210,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.5" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "pest_meta" -version = "2.7.5" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -4209,39 +4234,39 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.6.0", ] [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -4261,15 +4286,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -4280,24 +4305,24 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "polyval" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", @@ -4313,9 +4338,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" @@ -4333,15 +4361,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -4349,22 +4377,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ - "proc-macro2 1.0.86", - "syn 2.0.75", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "proc-macro2 1.0.88", + "syn 2.0.79", ] [[package]] @@ -4373,7 +4391,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -4383,7 +4401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", "version_check", @@ -4395,7 +4413,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "version_check", ] @@ -4411,31 +4429,41 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] [[package]] name = "procfs" -version = "0.14.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de8dacb0873f77e6aefc6d71e044761fcc68060290f5b1089fcdf84626bb69" +checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 1.3.2", - "byteorder", + "bitflags 2.6.0", "hex", "lazy_static", - "rustix 0.36.17", + "procfs-core", + "rustix", +] + +[[package]] +name = "procfs-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +dependencies = [ + "bitflags 2.6.0", + "hex", ] [[package]] name = "prometheus" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ "cfg-if", "fnv", @@ -4465,8 +4493,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.12.0", + "heck 0.5.0", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -4475,7 +4503,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.75", + "syn 2.0.79", "tempfile", ] @@ -4486,10 +4514,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.12.0", - "proc-macro2 1.0.86", + "itertools 0.13.0", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -4522,7 +4550,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -4541,7 +4569,7 @@ dependencies = [ "log", "octets", "once_cell", - "ring 0.17.7", + "ring 0.17.8", "slab", "smallvec", "winapi", @@ -4562,7 +4590,7 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", ] [[package]] @@ -4632,9 +4660,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -4642,9 +4670,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -4663,32 +4691,23 @@ dependencies = [ "yasna", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", - "libredox 0.0.1", + "libredox", "thiserror", ] @@ -4706,14 +4725,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", - "regex-syntax 0.8.2", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4727,13 +4746,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -4744,9 +4763,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "region" @@ -4762,9 +4781,9 @@ dependencies = [ [[package]] name = "rend" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ "bytecheck", ] @@ -4786,23 +4805,24 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rkyv" -version = "0.7.43" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -4819,11 +4839,11 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.43" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -4867,9 +4887,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.33.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06676aec5ccb8fc1da723cc8c0f9a46549f21ebb8753d3915c6c41db1e7f1dc4" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "num-traits", @@ -4877,9 +4897,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -4895,9 +4915,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -4913,40 +4933,26 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.45.0", -] - -[[package]] -name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.12", + "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki", "subtle", @@ -4977,9 +4983,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-platform-verifier" @@ -5014,16 +5020,16 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rustyline" @@ -5031,7 +5037,7 @@ version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "994eca4bca05c87e86e15d90fc7a91d1be64b4482b38cb2d27474568fe7c9db9" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cfg-if", "clipboard-win", "fd-lock", @@ -5054,16 +5060,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a32af5427251d2e4be14fc151eabe18abb4a7aad5efee7044da9f096c906a43" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -5076,11 +5082,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5102,19 +5108,19 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "serde_derive_internals", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "schnellru" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", "cfg-if", "hashbrown 0.13.2", ] @@ -5133,11 +5139,11 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -5157,15 +5163,15 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] @@ -5178,9 +5184,9 @@ checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -5196,25 +5202,15 @@ 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.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5223,18 +5219,19 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.109" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -5261,16 +5258,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.4.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ - "base64 0.21.5", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -5278,14 +5276,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.4.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ - "darling 0.20.3", - "proc-macro2 1.0.86", + "darling 0.20.10", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5294,7 +5292,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -5321,9 +5319,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5404,9 +5402,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -5422,9 +5420,9 @@ dependencies = [ [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" @@ -5452,12 +5450,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5528,6 +5526,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.25.0" @@ -5544,10 +5548,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "rustversion", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5561,9 +5565,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -5582,22 +5586,28 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.75" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" @@ -5610,10 +5620,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", - "unicode-xid 0.2.4", + "unicode-xid 0.2.6", ] [[package]] @@ -5635,21 +5645,21 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.12" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", - "rustix 0.38.34", - "windows-sys 0.48.0", + "once_cell", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -5660,29 +5670,29 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.55" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.55" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "thread-id" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" +checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" dependencies = [ "libc", "winapi", @@ -5690,9 +5700,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -5741,9 +5751,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -5756,32 +5766,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.2", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5809,9 +5818,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -5819,7 +5828,6 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -5840,7 +5848,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -5854,37 +5862,26 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "toml_datetime", - "winnow 0.5.31", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.4.0", - "toml_datetime", - "winnow 0.5.31", -] - -[[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", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] @@ -5903,7 +5900,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-timeout", "hyper-util", "percent-encoding", @@ -5914,7 +5911,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -5927,11 +5924,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "prost-build", "prost-types", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -6001,13 +5998,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-http" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "bytes", "http 1.1.0", "http-body 1.0.1", @@ -6023,7 +6034,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "bytes", "http 1.1.0", "pin-project-lite", @@ -6061,9 +6072,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -6119,7 +6130,7 @@ version = "0.1.0" source = "git+https://github.com/massalabs/transition.git?rev=93fa3bf82f9f5ff421c78536879b7fd1b948ca75#93fa3bf82f9f5ff421c78536879b7fd1b948ca75" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", "unsigned-varint 0.7.1", @@ -6139,42 +6150,42 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" @@ -6184,9 +6195,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -6235,9 +6246,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -6247,15 +6258,15 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.6.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "valuable" @@ -6281,15 +6292,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -6312,34 +6323,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -6349,9 +6361,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote 1.0.37", "wasm-bindgen-macro-support", @@ -6359,22 +6371,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-encoder" @@ -6484,19 +6496,19 @@ dependencies = [ [[package]] name = "wasmer-config" -version = "0.4.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4a632496950fde9ad821e195ef1a301440076f7c7d80de55239a140359bcbd" +checksum = "644b7e3547bd7e796d92220f60bf57734914254c6cee56607e80177a3e8a28da" dependencies = [ "anyhow", "bytesize", + "ciborium", "derive_builder", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "schemars", "semver", "serde", - "serde_cbor", "serde_json", "serde_yaml", "thiserror", @@ -6511,7 +6523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f448efbe12d656ba96d997c9e338f15cd80934c81f2286c2730cb9224d4e41d" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", "syn 1.0.109", ] @@ -6593,8 +6605,8 @@ version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "bitflags 2.4.1", - "indexmap 2.4.0", + "bitflags 2.6.0", + "indexmap 2.6.0", "semver", ] @@ -6621,9 +6633,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -6631,14 +6643,15 @@ dependencies = [ [[package]] name = "webc" -version = "6.0.0-rc3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85ffb11d1fabf0ebfc458a3d1d34ccf6d4d9596ca7576370cae4eab554c63d1" +checksum = "cdea84cf234555864ca9b7a5084c1a99dbdf2d148035f62a09b19ce5606532c1" dependencies = [ "anyhow", "base64 0.22.1", "bytes", "cfg-if", + "ciborium", "document-features", "flate2", "indexmap 1.9.3", @@ -6646,7 +6659,6 @@ dependencies = [ "once_cell", "semver", "serde", - "serde_cbor", "serde_json", "sha2 0.10.8", "shared-buffer", @@ -6676,7 +6688,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.34", + "rustix", "windows-sys 0.48.0", ] @@ -6698,11 +6710,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -6713,11 +6725,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -6733,15 +6745,6 @@ dependencies = [ "windows_x86_64_msvc 0.33.0", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -6769,21 +6772,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -6815,12 +6803,6 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6839,12 +6821,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6863,12 +6839,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6893,12 +6863,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6917,12 +6881,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6935,12 +6893,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6959,12 +6911,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6979,18 +6925,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -7029,8 +6975,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys 0.4.12", - "rustix 0.38.34", + "linux-raw-sys", + "rustix", ] [[package]] @@ -7059,29 +7005,30 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -7092,16 +7039,16 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.88", "quote 1.0.37", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 4178921d123..0390ccbe859 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,7 @@ massa_consensus_exports = { path = "./massa-consensus-exports" } massa_consensus_worker = { path = "./massa-consensus-worker" } massa_db_exports = { path = "./massa-db-exports" } massa_db_worker = { path = "./massa-db-worker" } +massa_deferred_calls = { path = "./massa-deferred-calls" } massa_executed_ops = { path = "./massa-executed-ops" } massa_execution_exports = { path = "./massa-execution-exports" } massa_execution_worker = { path = "./massa-execution-worker" } @@ -106,12 +107,16 @@ massa_versioning = { path = "./massa-versioning" } massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies -massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", branch = "mainnet_2_3" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "branch" = "next_breaking_update" } +# massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", branch = "deferred_calls" } +# massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "branch" = "deferred_calls" } +massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "b5267178eaf266ec724691d7de163e4c34343416" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "82dd714d38cbcd863ae0bb215c06442917bb6404" } + + peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } # Dev only - use local dependencies # massa-proto-rs = { path = "../massa-proto-rs" } -# massa-sc-runtime = { path = "../massa-sc-runtime_3" } +# massa-sc-runtime = { path = "../massa-sc-runtime" } # peernet = { path = "../peernet" } # Common dependencies @@ -179,7 +184,7 @@ serde = "1.0" serde_json = "1.0" serde_qs = "0.12" serde_with = "3.3" -serde_yaml = "0.9.34" # 0.9.34+deprecated +serde_yaml = "0.9.34" # 0.9.34+deprecated serial_test = "2.0" sha2 = "=0.10" sha3 = "=0.10" diff --git a/massa-api-exports/Cargo.toml b/massa-api-exports/Cargo.toml index e047228fbb0..48f39472b43 100644 --- a/massa-api-exports/Cargo.toml +++ b/massa-api-exports/Cargo.toml @@ -22,6 +22,7 @@ massa_final_state = {workspace = true} massa_hash = {workspace = true} massa_wallet = {workspace = true} massa_versioning = {workspace = true} +massa_deferred_calls = { workspace = true } [dev-dependencies] serial_test = {workspace = true} diff --git a/massa-api-exports/src/config.rs b/massa-api-exports/src/config.rs index 6ec7e31abc3..7412d3e4af9 100644 --- a/massa-api-exports/src/config.rs +++ b/massa-api-exports/src/config.rs @@ -1,5 +1,6 @@ // Copyright (c) 2022 MASSA LABS +use massa_deferred_calls::config::DeferredCallsConfig; use massa_models::amount::Amount; use massa_signature::KeyPair; use massa_time::MassaTime; @@ -84,4 +85,6 @@ pub struct APIConfig { pub deferred_credits_delta: MassaTime, /// minimal fees to include an operation in a block pub minimal_fees: Amount, + /// deferred calls config + pub deferred_calls_config: DeferredCallsConfig, } diff --git a/massa-api-exports/src/execution.rs b/massa-api-exports/src/execution.rs index c90cc7eb538..527d3cb574e 100644 --- a/massa-api-exports/src/execution.rs +++ b/massa-api-exports/src/execution.rs @@ -1,5 +1,6 @@ // Copyright (c) 2022 MASSA LABS +use massa_deferred_calls::DeferredCall; use massa_final_state::StateChanges; use massa_models::{ address::Address, amount::Amount, block_id::BlockId, operation::OperationId, @@ -121,3 +122,45 @@ pub struct Transfer { /// Context pub context: TransferContext, } + +/// request for deferred call quote +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallsQuoteRequest { + /// The slot at which the deferred call is to be executed. + pub target_slot: Slot, + /// The maximum gas requested. + pub max_gas_request: u64, + /// Size of parameters + pub params_size: u64, +} + +/// The response to a request for a deferred call quote. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallsQuoteResponse { + /// The slot at which the deferred call is to be executed. + pub target_slot: Slot, + /// The maximum gas requested. + pub max_gas_request: u64, + /// if the slot is bookable + pub available: bool, + /// the cost for booking the call + pub price: Amount, +} + +/// response for deferred call +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallResponse { + /// deferred call id + pub call_id: String, + /// deferred call + pub call: DeferredCall, +} + +/// response for deferred calls by slot +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallsSlotResponse { + /// deferred calls + pub slot: Slot, + /// deferred calls + pub call_ids: Vec, +} diff --git a/massa-api/src/lib.rs b/massa-api/src/lib.rs index 7db1bcee6ed..c448292c12a 100644 --- a/massa-api/src/lib.rs +++ b/massa-api/src/lib.rs @@ -11,7 +11,10 @@ use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::middleware::http::HostFilterLayer; use jsonrpsee::server::{BatchRequestConfig, PingConfig, ServerBuilder, ServerHandle}; use jsonrpsee::RpcModule; -use massa_api_exports::execution::Transfer; +use massa_api_exports::execution::{ + DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse, + DeferredCallsSlotResponse, Transfer, +}; use massa_api_exports::{ address::{AddressFilter, AddressInfo}, block::{BlockInfo, BlockSummary}, @@ -401,6 +404,27 @@ pub trait MassaRpc { /// Get OpenRPC specification. #[method(name = "rpc.discover")] async fn get_openrpc_spec(&self) -> RpcResult; + + /// DeferredCall quote + #[method(name = "get_deferred_call_quote")] + async fn get_deferred_call_quote( + &self, + arg: Vec, + ) -> RpcResult>; + + /// DeferredCall get info + #[method(name = "get_deferred_call_info")] + async fn get_deferred_call_info( + &self, + arg: Vec, + ) -> RpcResult>; + + /// List deferred calls for given slot + #[method(name = "get_deferred_call_ids_by_slot")] + async fn get_deferred_call_ids_by_slot( + &self, + arg: Vec, + ) -> RpcResult>; } fn wrong_api() -> RpcResult { diff --git a/massa-api/src/private.rs b/massa-api/src/private.rs index 75783118aa5..ca144dc18af 100644 --- a/massa-api/src/private.rs +++ b/massa-api/src/private.rs @@ -11,7 +11,11 @@ use massa_api_exports::{ datastore::{DatastoreEntryInput, DatastoreEntryOutput}, endorsement::EndorsementInfo, error::ApiError, - execution::{ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, ReadOnlyCall, Transfer}, + execution::{ + DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse, + DeferredCallsSlotResponse, ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, + ReadOnlyCall, Transfer, + }, node::NodeStatus, operation::{OperationInfo, OperationInput}, page::{PageRequest, PagedVec}, @@ -351,6 +355,26 @@ impl MassaRpcServer for API { ) } + async fn get_deferred_call_quote( + &self, + _req: Vec, + ) -> RpcResult> { + crate::wrong_api::>() + } + async fn get_deferred_call_info( + &self, + _arg: Vec, + ) -> RpcResult> { + crate::wrong_api::>() + } + + async fn get_deferred_call_ids_by_slot( + &self, + _slot: Vec, + ) -> RpcResult> { + crate::wrong_api::>() + } + async fn get_openrpc_spec(&self) -> RpcResult { crate::wrong_api::() } diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index b3db1247ba2..391120833db 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -13,7 +13,9 @@ use massa_api_exports::{ endorsement::EndorsementInfo, error::ApiError, execution::{ - ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, ReadOnlyCall, ReadOnlyResult, Transfer, + DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse, + DeferredCallsSlotResponse, ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, + ReadOnlyCall, ReadOnlyResult, Transfer, }, node::NodeStatus, operation::{OperationInfo, OperationInput}, @@ -37,20 +39,17 @@ use massa_models::{ composite::PubkeySig, config::CompactConfig, datastore::DatastoreDeserializer, - endorsement::EndorsementId, - endorsement::SecureShareEndorsement, + deferred_calls::DeferredCallId, + endorsement::{EndorsementId, SecureShareEndorsement}, error::ModelsError, execution::EventFilter, node::NodeId, - operation::OperationDeserializer, - operation::OperationId, - operation::{OperationType, SecureShareOperation}, + operation::{OperationDeserializer, OperationId, OperationType, SecureShareOperation}, output_event::SCOutputEvent, prehash::{PreHashMap, PreHashSet}, secure_share::SecureShareDeserializer, slot::{IndexedSlot, Slot}, - timeslots, - timeslots::{get_latest_block_slot_at_timestamp, time_range_to_slot_range}, + timeslots::{self, get_latest_block_slot_at_timestamp, time_range_to_slot_range}, version::Version, }; use massa_pool_exports::PoolController; @@ -63,8 +62,8 @@ use massa_versioning::versioning_factory::FactoryStrategy; use massa_versioning::{ keypair_factory::KeyPairFactory, versioning::MipStore, versioning_factory::VersioningFactory, }; -use std::collections::BTreeMap; use std::net::{IpAddr, SocketAddr}; +use std::{collections::BTreeMap, str::FromStr}; impl API { /// generate a new public API @@ -1157,6 +1156,132 @@ impl MassaRpcServer for API { Ok(res?) } + async fn get_deferred_call_quote( + &self, + req: Vec, + ) -> RpcResult> { + if req.len() as u64 > self.0.api_settings.max_arguments { + return Err(ApiError::BadRequest("too many arguments".into()).into()); + } + + let queries: Vec = req + .into_iter() + .map(|call| ExecutionQueryRequestItem::DeferredCallQuote { + target_slot: call.target_slot, + max_gas_request: call.max_gas_request, + params_size: call.params_size, + }) + .collect(); + + let result = self + .0 + .execution_controller + .query_state(ExecutionQueryRequest { requests: queries }) + .responses + .into_iter() + .map(|response| match response { + Ok(ExecutionQueryResponseItem::DeferredCallQuote( + target_slot, + max_gas_request, + available, + price, + )) => Ok(DeferredCallsQuoteResponse { + target_slot, + max_gas_request, + available, + price, + }), + Ok(_) => Err(ApiError::InternalServerError( + "unexpected response type".to_string(), + )), + Err(err) => Err(ApiError::InternalServerError(err.to_string())), + }) + .collect::, ApiError>>()?; + + Ok(result) + } + + async fn get_deferred_call_info( + &self, + arg: Vec, + ) -> RpcResult> { + if arg.len() as u64 > self.0.api_settings.max_arguments { + return Err(ApiError::BadRequest("too many arguments".into()).into()); + } + + let requests: Vec = arg + .into_iter() + .map(|id_str| { + DeferredCallId::from_str(&id_str) + .map_err(|e| ApiError::BadRequest(e.to_string())) + .map(ExecutionQueryRequestItem::DeferredCallInfo) + }) + .collect::>()?; + + let result: Vec = self + .0 + .execution_controller + .query_state(ExecutionQueryRequest { requests }) + .responses + .into_iter() + .map(|exec| match exec { + Ok(ExecutionQueryResponseItem::DeferredCallInfo(id, call)) => { + Ok(DeferredCallResponse { + call_id: id.to_string(), + call, + }) + } + Ok(_) => Err(ApiError::InternalServerError( + "unexpected response type".to_string(), + )), + Err(err) => Err(ApiError::InternalServerError(err.to_string())), + }) + .collect::>()?; + + Ok(result) + } + + async fn get_deferred_call_ids_by_slot( + &self, + slots: Vec, + ) -> RpcResult> { + if slots.len() as u64 > self.0.api_settings.max_arguments { + return Err(ApiError::BadRequest("too many arguments".into()).into()); + } + + let requests: Vec = slots + .into_iter() + .map(ExecutionQueryRequestItem::DeferredCallsBySlot) + .collect(); + + let mut slot_calls = Vec::new(); + + for exec in self + .0 + .execution_controller + .query_state(ExecutionQueryRequest { requests }) + .responses + .into_iter() + { + match exec { + Ok(ExecutionQueryResponseItem::DeferredCallsBySlot(slot, result)) => { + let call_ids = result.into_iter().map(|id| id.to_string()).collect(); + + slot_calls.push(DeferredCallsSlotResponse { slot, call_ids }); + } + Ok(_) => { + return Err(ApiError::InternalServerError( + "unexpected response type".to_string(), + ) + .into()) + } + Err(err) => return Err(ApiError::InternalServerError(err.to_string()).into()), + } + } + + Ok(slot_calls) + } + /// send operations async fn send_operations(&self, ops: Vec) -> RpcResult> { let mut cmd_sender = self.0.pool_command_sender.clone(); diff --git a/massa-api/src/tests/mock.rs b/massa-api/src/tests/mock.rs index 735da5266b9..9f1f714d215 100644 --- a/massa-api/src/tests/mock.rs +++ b/massa-api/src/tests/mock.rs @@ -70,6 +70,7 @@ pub(crate) fn get_apiv2_server(addr: &SocketAddr) -> (API, APIConfig) { chain_id: *CHAINID, deferred_credits_delta: MassaTime::from_millis(24 * 3600 * 2), minimal_fees: Amount::zero(), + deferred_calls_config: Default::default(), }; // let shared_storage: massa_storage::Storage = massa_storage::Storage::create_root(); @@ -146,6 +147,7 @@ pub(crate) fn start_public_api(addr: SocketAddr) -> (API, APIConfig) { chain_id: *CHAINID, deferred_credits_delta: MassaTime::from_millis(24 * 3600 * 2), minimal_fees: Amount::zero(), + deferred_calls_config: Default::default(), }; let shared_storage: massa_storage::Storage = massa_storage::Storage::create_root(); diff --git a/massa-async-pool/src/changes.rs b/massa-async-pool/src/changes.rs index 22ee4cd2700..da81c2a0fd0 100644 --- a/massa-async-pool/src/changes.rs +++ b/massa-async-pool/src/changes.rs @@ -14,7 +14,7 @@ use crate::{ AsyncMessageDeserializer, AsyncMessageSerializer, }; -use massa_ledger_exports::{ +use massa_models::types::{ Applicable, SetOrKeep, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, SetUpdateOrDeleteSerializer, }; @@ -233,7 +233,7 @@ impl AsyncPoolChanges { mod tests { use std::str::FromStr; - use massa_ledger_exports::SetUpdateOrDelete; + use massa_models::types::SetUpdateOrDelete; use massa_models::{address::Address, amount::Amount, slot::Slot}; use massa_serialization::{DeserializeError, Deserializer, Serializer}; diff --git a/massa-async-pool/src/mapping_grpc.rs b/massa-async-pool/src/mapping_grpc.rs index 3aefef50024..4aa5b52c1b1 100644 --- a/massa-async-pool/src/mapping_grpc.rs +++ b/massa-async-pool/src/mapping_grpc.rs @@ -1,7 +1,7 @@ // Copyright (c) 2023 MASSA LABS use crate::{AsyncMessage, AsyncMessageTrigger, AsyncMessageUpdate}; -use massa_ledger_exports::SetOrKeep; +use massa_models::types::SetOrKeep; use massa_proto_rs::massa::model::v1 as grpc_model; impl From for grpc_model::AsyncMessage { diff --git a/massa-async-pool/src/message.rs b/massa-async-pool/src/message.rs index 9b5379426ea..0c1ff814a96 100644 --- a/massa-async-pool/src/message.rs +++ b/massa-async-pool/src/message.rs @@ -2,12 +2,12 @@ //! This file defines the structure representing an asynchronous message -use massa_ledger_exports::{Applicable, SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::address::{AddressDeserializer, AddressSerializer}; use massa_models::amount::{AmountDeserializer, AmountSerializer}; use massa_models::config::GENESIS_KEY; use massa_models::serialization::{StringDeserializer, StringSerializer}; use massa_models::slot::{SlotDeserializer, SlotSerializer}; +use massa_models::types::{Applicable, SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::{ address::Address, amount::Amount, @@ -1006,7 +1006,7 @@ impl Applicable for AsyncMessageInfo { #[cfg(test)] mod tests { - use massa_ledger_exports::{Applicable, SetOrKeep}; + use massa_models::types::{Applicable, SetOrKeep}; use massa_serialization::{DeserializeError, Deserializer, Serializer}; use num::rational::Ratio; diff --git a/massa-async-pool/src/pool.rs b/massa-async-pool/src/pool.rs index 43b2ce2564b..5905380fa9a 100644 --- a/massa-async-pool/src/pool.rs +++ b/massa-async-pool/src/pool.rs @@ -13,8 +13,8 @@ use massa_db_exports::{ DBBatch, MassaDirection, MassaIteratorMode, ShareableMassaDBController, ASYNC_POOL_PREFIX, MESSAGE_ID_DESER_ERROR, MESSAGE_ID_SER_ERROR, MESSAGE_SER_ERROR, STATE_CF, }; -use massa_ledger_exports::{Applicable, SetOrKeep, SetUpdateOrDelete}; use massa_models::address::Address; +use massa_models::types::{Applicable, SetOrKeep, SetUpdateOrDelete}; use massa_serialization::{ DeserializeError, Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, diff --git a/massa-bootstrap/Cargo.toml b/massa-bootstrap/Cargo.toml index c50831bf3cd..6d20f3725e1 100644 --- a/massa-bootstrap/Cargo.toml +++ b/massa-bootstrap/Cargo.toml @@ -5,54 +5,64 @@ authors = ["Massa Labs "] edition = "2021" [features] -test-exports = ["massa_final_state/test-exports", "massa_ledger_worker/test-exports", "massa_consensus_exports/test-exports", "massa_async_pool/test-exports"] -sandbox = ["massa_async_pool/sandbox", "massa_final_state/sandbox", "massa_models/sandbox"] +test-exports = [ + "massa_final_state/test-exports", + "massa_ledger_worker/test-exports", + "massa_consensus_exports/test-exports", + "massa_async_pool/test-exports", +] +sandbox = [ + "massa_async_pool/sandbox", + "massa_final_state/sandbox", + "massa_models/sandbox", +] heavy_testing = [] [dependencies] -displaydoc = {workspace = true} -num_enum = {workspace = true} -nom = {workspace = true} -rand = {workspace = true} -serde = {workspace = true, "features" = ["derive"]} -serde_json = {workspace = true} # BOM UPGRADE Revert to "1.0" if problem -humantime = {workspace = true} -thiserror = {workspace = true} -parking_lot = {workspace = true} -tracing = {workspace = true} -substruct = {workspace = true} -socket2 = {workspace = true} -crossbeam = {workspace = true} # BOM UPGRADE Revert to "0.8.2" if problem -mio = {workspace = true, "features" = ["net", "os-poll"]} +displaydoc = { workspace = true } +num_enum = { workspace = true } +nom = { workspace = true } +rand = { workspace = true } +serde = { workspace = true, "features" = ["derive"] } +serde_json = { workspace = true } # BOM UPGRADE Revert to "1.0" if problem +humantime = { workspace = true } +thiserror = { workspace = true } +parking_lot = { workspace = true } +tracing = { workspace = true } +substruct = { workspace = true } +socket2 = { workspace = true } +crossbeam = { workspace = true } # BOM UPGRADE Revert to "0.8.2" if problem +mio = { workspace = true, "features" = ["net", "os-poll"] } stream_limiter = { workspace = true } -massa_consensus_exports = {workspace = true} -massa_final_state = {workspace = true} -massa_hash = {workspace = true} -massa_logging = {workspace = true} -massa_models = {workspace = true} -massa_protocol_exports = {workspace = true} -massa_serialization = {workspace = true} -massa_signature = {workspace = true} -massa_pos_exports = {workspace = true} -massa_time = {workspace = true} -massa_db_exports = {workspace = true} -massa_versioning = {workspace = true} -massa_metrics = {workspace = true} +massa_consensus_exports = { workspace = true } +massa_final_state = { workspace = true } +massa_hash = { workspace = true } +massa_logging = { workspace = true } +massa_models = { workspace = true } +massa_protocol_exports = { workspace = true } +massa_serialization = { workspace = true } +massa_signature = { workspace = true } +massa_pos_exports = { workspace = true } +massa_time = { workspace = true } +massa_db_exports = { workspace = true } +massa_versioning = { workspace = true } +massa_metrics = { workspace = true } [dev-dependencies] -mockall = {workspace = true} -bitvec = {workspace = true, "features" = ["serde"]} -lazy_static = {workspace = true} # BOM UPGRADE Revert to "1.4" if problem -tempfile = {workspace = true} # BOM UPGRADE Revert to "3.3" if problem -serial_test = {workspace = true} # BOM UPGRADE Revert to "2.0.0" if problem -num = {workspace = true} -massa_final_state = {workspace = true, "features" = ["test-exports"]} -massa_async_pool = {workspace = true, "features" = ["test-exports"]} -massa_ledger_exports = {workspace = true} -massa_ledger_worker = {workspace = true, "features" = ["test-exports"]} -massa_executed_ops = {workspace = true} -massa_pos_exports = {workspace = true, "features" = ["test-exports"]} -massa_consensus_exports = {workspace = true, "features" = ["test-exports"]} -massa_db_worker = {workspace = true, "features" = ["test-exports"]} -massa_test_framework = {workspace = true, "features" = ["test-exports"]} +mockall = { workspace = true } +bitvec = { workspace = true, "features" = ["serde"] } +lazy_static = { workspace = true } # BOM UPGRADE Revert to "1.4" if problem +tempfile = { workspace = true } # BOM UPGRADE Revert to "3.3" if problem +serial_test = { workspace = true } # BOM UPGRADE Revert to "2.0.0" if problem +num = { workspace = true } +massa_final_state = { workspace = true, "features" = ["test-exports"] } +massa_async_pool = { workspace = true, "features" = ["test-exports"] } +massa_ledger_exports = { workspace = true } +massa_ledger_worker = { workspace = true, "features" = ["test-exports"] } +massa_executed_ops = { workspace = true } +massa_pos_exports = { workspace = true, "features" = ["test-exports"] } +massa_consensus_exports = { workspace = true, "features" = ["test-exports"] } +massa_db_worker = { workspace = true, "features" = ["test-exports"] } +massa_test_framework = { workspace = true, "features" = ["test-exports"] } +massa_deferred_calls = { workspace = true } diff --git a/massa-bootstrap/src/tests/tools.rs b/massa-bootstrap/src/tests/tools.rs index 88309c84f89..e44614f342b 100644 --- a/massa-bootstrap/src/tests/tools.rs +++ b/massa-bootstrap/src/tests/tools.rs @@ -9,6 +9,8 @@ use massa_consensus_exports::{ bootstrapable_graph::BootstrapableGraph, export_active_block::ExportActiveBlock, }; use massa_db_exports::{DBBatch, ShareableMassaDBController, StreamBatch}; +use massa_deferred_calls::config::DeferredCallsConfig; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::{ ExecutedDenunciations, ExecutedDenunciationsChanges, ExecutedDenunciationsConfig, ExecutedOps, ExecutedOpsConfig, @@ -16,7 +18,7 @@ use massa_executed_ops::{ use massa_final_state::test_exports::create_final_state; use massa_final_state::{FinalState, FinalStateConfig, FinalStateController}; use massa_hash::{Hash, HASH_SIZE_BYTES}; -use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete}; +use massa_ledger_exports::LedgerEntry; use massa_ledger_worker::test_exports::create_final_ledger; use massa_models::bytecode::Bytecode; use massa_models::config::{ @@ -36,6 +38,7 @@ use massa_models::denunciation::DenunciationIndex; use massa_models::node::NodeId; use massa_models::prehash::{CapacityAllocator, PreHashSet}; use massa_models::streaming_step::StreamingStep; +use massa_models::types::SetUpdateOrDelete; use massa_models::version::Version; use massa_models::{ address::Address, @@ -275,6 +278,9 @@ pub fn get_random_final_state_bootstrap( .write() .write_batch(batch, versioning_batch, None); + let deferred_call_registry = + DeferredCallRegistry::new(db.clone(), DeferredCallsConfig::default()); + let executed_ops = get_random_executed_ops( r_limit, slot, @@ -304,6 +310,7 @@ pub fn get_random_final_state_bootstrap( config, Box::new(final_ledger), async_pool, + deferred_call_registry, pos_state, executed_ops, executed_denunciations, diff --git a/massa-db-exports/src/constants.rs b/massa-db-exports/src/constants.rs index 5716f078d63..771807b4a2f 100644 --- a/massa-db-exports/src/constants.rs +++ b/massa-db-exports/src/constants.rs @@ -29,6 +29,7 @@ pub const LEDGER_PREFIX: &str = "ledger/"; pub const MIP_STORE_PREFIX: &str = "versioning/"; pub const MIP_STORE_STATS_PREFIX: &str = "versioning_stats/"; pub const EXECUTION_TRAIL_HASH_PREFIX: &str = "execution_trail_hash/"; +pub const DEFERRED_CALLS_PREFIX: &str = "deferred_calls/"; // Async Pool pub const MESSAGE_DESER_ERROR: &str = "critical: message deserialization failed"; @@ -56,3 +57,7 @@ pub const EXECUTED_DENUNCIATIONS_INDEX_SER_ERROR: &str = pub const KEY_DESER_ERROR: &str = "critical: key deserialization failed"; pub const KEY_SER_ERROR: &str = "critical: key serialization failed"; pub const KEY_LEN_SER_ERROR: &str = "critical: key length serialization failed"; + +// deferred calls +pub const DEFERRED_CALL_DESER_ERROR: &str = "critical: message deserialization failed"; +pub const DEFERRED_CALL_SER_ERROR: &str = "critical: message serialization failed"; diff --git a/massa-deferred-calls/Cargo.toml b/massa-deferred-calls/Cargo.toml new file mode 100644 index 00000000000..6df8d5a9b71 --- /dev/null +++ b/massa-deferred-calls/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "massa_deferred_calls" +version = "2.2.0" +authors = ["Massa Labs "] +edition = "2021" + +[features] +test-exports = [] +sandbox = [] + +[dependencies] +serde = { workspace = true, "features" = ["derive"] } +nom = { workspace = true } +massa_db_exports = { workspace = true } +massa_ledger_exports = { workspace = true } +massa_models = { workspace = true } +massa_serialization = { workspace = true } +serde_with = { workspace = true } +serde_json = { workspace = true } +massa-proto-rs = { workspace = true, "features" = ["tonic"] } + +[dev-dependencies] +tempfile = { workspace = true } +massa_db_worker = { workspace = true } +parking_lot = { workspace = true } diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs new file mode 100644 index 00000000000..99b11b8a717 --- /dev/null +++ b/massa-deferred-calls/src/call.rs @@ -0,0 +1,295 @@ +use massa_models::{ + address::{Address, AddressDeserializer, AddressSerializer}, + amount::{Amount, AmountDeserializer, AmountSerializer}, + serialization::{StringDeserializer, StringSerializer, VecU8Deserializer, VecU8Serializer}, + slot::{Slot, SlotDeserializer, SlotSerializer}, +}; +use massa_proto_rs::massa::api::v1 as grpc_api; +use massa_serialization::{ + BoolDeserializer, BoolSerializer, Deserializer, SerializeError, Serializer, + U16VarIntDeserializer, U16VarIntSerializer, U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{context, ContextError, ParseError}, + sequence::tuple, + IResult, Parser, +}; +use serde::{Deserialize, Serialize}; +use std::ops::Bound; + +use crate::config::DeferredCallsConfig; + +/// Definition of a call in the future +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct DeferredCall { + // Sender address + pub sender_address: Address, + // The slot in which the call will be executed + pub target_slot: Slot, + // The address of the contract to call + pub target_address: Address, + // The function to call + pub target_function: String, + // The parameters of the call + pub parameters: Vec, + // The amount of coins to send to the contract + pub coins: Amount, + // The maximum amount of gas usable for the call (excluding the vm allocation cost) + // to get the effective gas, use get_effective_gas(&self) + pub max_gas: u64, + // The fee to pay for the reservation of the space for the call + pub fee: Amount, + // Whether the call is cancelled + pub cancelled: bool, +} + +impl DeferredCall { + #[allow(clippy::too_many_arguments)] + pub fn new( + sender_address: Address, + target_slot: Slot, + target_address: Address, + target_function: String, + parameters: Vec, + coins: Amount, + max_gas: u64, + fee: Amount, + cancelled: bool, + ) -> Self { + DeferredCall { + sender_address, + target_slot, + target_address, + target_function, + parameters, + coins, + max_gas, + fee, + cancelled, + } + } + + /// Get the effective gas of a call + /// This is the maximum gas of the call + vm allocation cost + pub fn get_effective_gas(&self, alloc_gas_cost: u64) -> u64 { + self.max_gas.saturating_add(alloc_gas_cost) + } + + /// Get the storage cost for a call + pub fn get_storage_cost( + cost_per_byte: Amount, + params_size: u64, + max_function_name_length: u16, + ) -> Amount { + // 35 (sender_address) + 16 (target_slot) + 35 (target_address) + target_function.len() + params_size + 8 (coins) + 8 (max_gas) + 8 (fee) + 1 (cancelled) + let total_size = params_size + .saturating_add(max_function_name_length as u64) + .saturating_add(111); // 35 + 16 + 35 + 8 + 8 + 8 + 1 + cost_per_byte.saturating_mul_u64(total_size) + } +} + +impl From for grpc_api::DeferredCallInfoEntry { + fn from(call: DeferredCall) -> Self { + grpc_api::DeferredCallInfoEntry { + sender_address: call.sender_address.to_string(), + target_slot: Some(call.target_slot.into()), + target_address: call.target_address.to_string(), + target_function: call.target_function, + parameters: call.parameters, + coins: Some(call.coins.into()), + max_gas: call.max_gas, + fee: Some(call.fee.into()), + cancelled: call.cancelled, + } + } +} + +/// Serializer for `AsyncCall` +#[derive(Clone)] +pub struct DeferredCallSerializer { + pub(crate) slot_serializer: SlotSerializer, + pub(crate) address_serializer: AddressSerializer, + pub(crate) string_serializer: StringSerializer, + pub(crate) vec_u8_serializer: VecU8Serializer, + pub(crate) amount_serializer: AmountSerializer, + pub(crate) u64_var_int_serializer: U64VarIntSerializer, + pub(crate) bool_serializer: BoolSerializer, +} + +impl DeferredCallSerializer { + /// Serializes an `DeferredCall` into a `Vec` + pub fn new() -> Self { + Self { + slot_serializer: SlotSerializer::new(), + address_serializer: AddressSerializer::new(), + string_serializer: StringSerializer::new(U16VarIntSerializer::new()), + vec_u8_serializer: VecU8Serializer::new(), + amount_serializer: AmountSerializer::new(), + u64_var_int_serializer: U64VarIntSerializer::new(), + bool_serializer: BoolSerializer::new(), + } + } +} + +impl Serializer for DeferredCallSerializer { + fn serialize(&self, value: &DeferredCall, buffer: &mut Vec) -> Result<(), SerializeError> { + self.address_serializer + .serialize(&value.sender_address, buffer)?; + self.slot_serializer.serialize(&value.target_slot, buffer)?; + self.address_serializer + .serialize(&value.target_address, buffer)?; + self.string_serializer + .serialize(&value.target_function, buffer)?; + self.vec_u8_serializer + .serialize(&value.parameters, buffer)?; + self.amount_serializer.serialize(&value.coins, buffer)?; + self.u64_var_int_serializer + .serialize(&value.max_gas, buffer)?; + self.amount_serializer.serialize(&value.fee, buffer)?; + self.bool_serializer.serialize(&value.cancelled, buffer)?; + Ok(()) + } +} + +/// Deserializer for `AsyncCall` +#[derive(Clone)] +pub struct DeferredCallDeserializer { + slot_deserializer: SlotDeserializer, + address_deserializer: AddressDeserializer, + string_deserializer: StringDeserializer, + vec_u8_deserializer: VecU8Deserializer, + pub(crate) amount_deserializer: AmountDeserializer, + pub(crate) u64_var_int_deserializer: U64VarIntDeserializer, + bool_deserializer: BoolDeserializer, +} + +impl DeferredCallDeserializer { + /// Deserializes a `Vec` into an `AsyncCall` + pub fn new(config: DeferredCallsConfig) -> Self { + Self { + slot_deserializer: SlotDeserializer::new( + (Bound::Included(0), Bound::Included(u64::MAX)), + (Bound::Included(0), Bound::Excluded(config.thread_count)), + ), + address_deserializer: AddressDeserializer::new(), + string_deserializer: StringDeserializer::new(U16VarIntDeserializer::new( + Bound::Included(0), + Bound::Included(config.max_function_name_length), + )), + vec_u8_deserializer: VecU8Deserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(config.max_parameter_size as u64), + ), + amount_deserializer: AmountDeserializer::new( + Bound::Included(Amount::MIN), + Bound::Included(Amount::MAX), + ), + u64_var_int_deserializer: U64VarIntDeserializer::new( + Bound::Included(0), + Bound::Included(u64::MAX), + ), + bool_deserializer: BoolDeserializer::new(), + } + } +} + +impl Deserializer for DeferredCallDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredCall, E> { + context( + "Failed AsyncCall deserialization", + tuple(( + context("Failed sender_address deserialization", |input| { + self.address_deserializer.deserialize(input) + }), + context("Failed target_slot deserialization", |input| { + self.slot_deserializer.deserialize(input) + }), + context("Failed target_address deserialization", |input| { + self.address_deserializer.deserialize(input) + }), + context("Failed target_function deserialization", |input| { + self.string_deserializer.deserialize(input) + }), + context("Failed parameters deserialization", |input| { + self.vec_u8_deserializer.deserialize(input) + }), + context("Failed coins deserialization", |input| { + self.amount_deserializer.deserialize(input) + }), + context("Failed max_gas deserialization", |input| { + self.u64_var_int_deserializer.deserialize(input) + }), + context("Failed fee deserialization", |input| { + self.amount_deserializer.deserialize(input) + }), + context("Failed cancelled deserialization", |input| { + self.bool_deserializer.deserialize(input) + }), + )), + ) + .map( + |( + sender_address, + target_slot, + target_address, + target_function, + parameters, + coins, + max_gas, + fee, + cancelled, + )| { + DeferredCall::new( + sender_address, + target_slot, + target_address, + target_function, + parameters, + coins, + max_gas, + fee, + cancelled, + ) + }, + ) + .parse(buffer) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use massa_serialization::DeserializeError; + + use super::*; + + #[test] + fn test_serialization_deserialization() { + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + Slot::new(42, 0), + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + "function".to_string(), + vec![0, 1, 2, 3], + Amount::from_raw(100), + 500000, + Amount::from_raw(25), + false, + ); + let serializer = DeferredCallSerializer::new(); + + let deserializer = DeferredCallDeserializer::new(DeferredCallsConfig::default()); + let mut buffer = Vec::new(); + serializer.serialize(&call, &mut buffer).unwrap(); + let (rest, deserialized_call) = deserializer + .deserialize::(&buffer) + .unwrap(); + assert_eq!(call, deserialized_call); + assert!(rest.is_empty()); + } +} diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs new file mode 100644 index 00000000000..8f1264e73e0 --- /dev/null +++ b/massa-deferred-calls/src/config.rs @@ -0,0 +1,62 @@ +use massa_models::{ + amount::Amount, + config::{ + DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFERRED_CALL_CST_GAS_COST, + DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_MAX_ASYNC_GAS, + DEFERRED_CALL_MAX_FUTURE_SLOTS, DEFERRED_CALL_MAX_POOL_CHANGES, DEFERRED_CALL_MIN_GAS_COST, + DEFERRED_CALL_MIN_GAS_INCREMENT, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, + LEDGER_COST_PER_BYTE, MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, THREAD_COUNT, + }, +}; +use serde::Deserialize; + +#[derive(Debug, Clone, Copy, Deserialize)] +pub struct DeferredCallsConfig { + /// thread count + pub thread_count: u8, + /// max function name length + pub max_function_name_length: u16, + /// Maximum size of deferred call future slots (1 week) + pub max_future_slots: u64, + /// base fee max max change denominator + pub base_fee_max_max_change_denominator: usize, + /// min gas increment (1 nanomassa) + pub min_gas_increment: u64, + /// min gas cost (10 nanomassa) + pub min_gas_cost: u64, + /// call gas cost + pub call_cst_gas_cost: u64, + /// global overbooking penalty + pub global_overbooking_penalty: Amount, + /// slot overbooking penalty + pub slot_overbooking_penalty: Amount, + + /// max parameter size + pub max_parameter_size: u32, + + pub max_pool_changes: u64, + + pub max_gas: u64, + + pub ledger_cost_per_byte: Amount, +} + +impl Default for DeferredCallsConfig { + fn default() -> Self { + Self { + thread_count: THREAD_COUNT, + max_function_name_length: MAX_FUNCTION_NAME_LENGTH, + max_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, + max_parameter_size: MAX_PARAMETERS_SIZE, + max_pool_changes: DEFERRED_CALL_MAX_POOL_CHANGES, + max_gas: DEFERRED_CALL_MAX_ASYNC_GAS, + base_fee_max_max_change_denominator: DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, + min_gas_increment: DEFERRED_CALL_MIN_GAS_INCREMENT, + min_gas_cost: DEFERRED_CALL_MIN_GAS_COST, + global_overbooking_penalty: DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + slot_overbooking_penalty: DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, + call_cst_gas_cost: DEFERRED_CALL_CST_GAS_COST, + ledger_cost_per_byte: LEDGER_COST_PER_BYTE, + } + } +} diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs new file mode 100644 index 00000000000..d6098aee8d9 --- /dev/null +++ b/massa-deferred-calls/src/lib.rs @@ -0,0 +1,499 @@ +use call::{DeferredCallDeserializer, DeferredCallSerializer}; +use config::DeferredCallsConfig; +use macros::{DEFERRED_CALL_TOTAL_GAS, DEFERRED_CALL_TOTAL_REGISTERED}; +use massa_db_exports::{ + DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, + DEFERRED_CALL_DESER_ERROR, DEFERRED_CALL_SER_ERROR, KEY_DESER_ERROR, STATE_CF, +}; +use massa_serialization::{DeserializeError, Deserializer, Serializer}; +use registry_changes::{ + DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, + DeferredRegistryChangesSerializer, +}; + +/// This module implements a new version of the Autonomous Smart Contracts. (ASC) +/// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. +mod call; +pub mod config; +pub mod registry_changes; +pub mod slot_changes; + +#[cfg(test)] +mod tests; + +#[macro_use] +mod macros; + +pub use call::DeferredCall; +use massa_models::types::{SetOrDelete, SetOrKeep}; +use massa_models::{ + amount::Amount, + deferred_calls::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, + slot::Slot, +}; +use std::collections::{BTreeMap, HashSet}; + +// #[derive(Debug)] +pub struct DeferredCallRegistry { + db: ShareableMassaDBController, + call_serializer: DeferredCallSerializer, + call_id_serializer: DeferredCallIdSerializer, + call_deserializer: DeferredCallDeserializer, + call_id_deserializer: DeferredCallIdDeserializer, + registry_changes_deserializer: DeferredRegistryChangesDeserializer, + registry_changes_serializer: DeferredRegistryChangesSerializer, +} + +impl DeferredCallRegistry { + /* + DB layout: + [DEFERRED_CALL_TOTAL_GAS] -> u128 // total currently booked gas + [DEFERRED_CALL_TOTAL_REGISTERED] -> u64 // total call registered + [DEFERRED_CALLS_PREFIX][slot][SLOT_TOTAL_GAS] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) + [DEFERRED_CALLS_PREFIX][slot][SLOT_BASE_FEE] -> u64 // deleted when set to 0 + [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> DeferredCalls.x // call data + */ + + pub fn new(db: ShareableMassaDBController, config: DeferredCallsConfig) -> Self { + Self { + db, + call_serializer: DeferredCallSerializer::new(), + call_id_serializer: DeferredCallIdSerializer::new(), + call_deserializer: DeferredCallDeserializer::new(config), + call_id_deserializer: DeferredCallIdDeserializer::new(), + registry_changes_deserializer: DeferredRegistryChangesDeserializer::new(config), + registry_changes_serializer: DeferredRegistryChangesSerializer::new(), + } + } + + pub fn get_nb_call_registered(&self) -> u64 { + match self + .db + .read() + .get_cf(STATE_CF, DEFERRED_CALL_TOTAL_REGISTERED.as_bytes().to_vec()) + .expect(CRUD_ERROR) + { + Some(v) => { + self.registry_changes_deserializer + .u64_deserializer + .deserialize::(&v) + .expect(DEFERRED_CALL_DESER_ERROR) + .1 + } + None => 0, + } + } + + /// Returns the DeferredSlotCalls for a given slot + pub fn get_slot_calls(&self, slot: Slot) -> DeferredSlotCalls { + let mut to_return = DeferredSlotCalls::new(slot); + let key = deferred_slot_call_prefix_key!(slot.to_bytes_key()); + + let mut temp = HashSet::new(); + + for (serialized_key, _serialized_value) in self.db.read().prefix_iterator_cf(STATE_CF, &key) + { + if !serialized_key.starts_with(&key) { + break; + } + + let rest_key = &serialized_key[key.len()..]; + + let (_rest, call_id) = self + .call_id_deserializer + .deserialize::(rest_key) + .expect(KEY_DESER_ERROR); + + if !temp.insert(call_id.clone()) { + continue; + } + + if let Some(call) = self.get_call(&slot, &call_id) { + to_return.slot_calls.insert(call_id, call); + } + } + + to_return.slot_base_fee = self.get_slot_base_fee(&slot); + to_return.effective_slot_gas = self.get_slot_gas(&slot); + to_return.effective_total_gas = self.get_total_gas(); + + to_return + } + + /// Returns the DeferredCall for a given slot and id + pub fn get_call(&self, slot: &Slot, id: &DeferredCallId) -> Option { + let mut buf_id = Vec::new(); + self.call_id_serializer + .serialize(id, &mut buf_id) + .expect(DEFERRED_CALL_SER_ERROR); + let key = deferred_call_prefix_key!(buf_id, slot.to_bytes_key()); + + let mut serialized_call: Vec = Vec::new(); + for (serialized_key, serialized_value) in self.db.read().prefix_iterator_cf(STATE_CF, &key) + { + if !serialized_key.starts_with(&key) { + break; + } + + serialized_call.extend(serialized_value.iter()); + } + + match self + .call_deserializer + .deserialize::(&serialized_call) + { + Ok((_rest, call)) => Some(call), + Err(_) => None, + } + } + + /// Returns the total effective amount of gas booked for a slot + pub fn get_slot_gas(&self, slot: &Slot) -> u64 { + // By default, if it is absent, it is 0 + let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); + match self.db.read().get_cf(STATE_CF, key) { + Ok(Some(v)) => { + let result = self + .call_deserializer + .u64_var_int_deserializer + .deserialize::(&v) + .expect(DEFERRED_CALL_DESER_ERROR) + .1; + result + } + _ => 0, + } + } + + /// Returns the base fee for a slot + pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { + let key = deferred_call_slot_base_fee_key!(slot.to_bytes_key()); + match self.db.read().get_cf(STATE_CF, key) { + Ok(Some(v)) => { + self.call_deserializer + .amount_deserializer + .deserialize::(&v) + .expect(DEFERRED_CALL_DESER_ERROR) + .1 + } + _ => Amount::zero(), + } + } + + /// Returns the total amount of effective gas booked + pub fn get_total_gas(&self) -> u128 { + match self + .db + .read() + .get_cf(STATE_CF, DEFERRED_CALL_TOTAL_GAS.as_bytes().to_vec()) + .expect(CRUD_ERROR) + { + Some(v) => { + let result = self + .registry_changes_deserializer + .effective_total_gas_deserializer + .deserialize::(&v) + .expect(DEFERRED_CALL_DESER_ERROR) + .1; + + match result { + DeferredRegistryGasChange::Set(v) => v, + DeferredRegistryGasChange::Keep => 0, + } + } + None => 0, + } + } + + pub fn put_entry( + &self, + slot: &Slot, + call_id: &DeferredCallId, + call: &DeferredCall, + batch: &mut DBBatch, + ) { + let mut buffer_id = Vec::new(); + self.call_id_serializer + .serialize(call_id, &mut buffer_id) + .expect(DEFERRED_CALL_SER_ERROR); + + let slot_bytes = slot.to_bytes_key(); + + let db = self.db.read(); + + { + // sender address + let mut buffer = Vec::new(); + self.call_serializer + .address_serializer + .serialize(&call.sender_address, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value( + batch, + sender_address_key!(buffer_id, slot_bytes), + &buffer, + ); + } + + { + // target slot + let mut buffer = Vec::new(); + self.call_serializer + .slot_serializer + .serialize(&call.target_slot, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, target_slot_key!(buffer_id, slot_bytes), &buffer); + } + + { + // target address + let mut buffer = Vec::new(); + self.call_serializer + .address_serializer + .serialize(&call.target_address, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value( + batch, + target_address_key!(buffer_id, slot_bytes), + &buffer, + ); + } + + { + // target function + let mut buffer = Vec::new(); + self.call_serializer + .string_serializer + .serialize(&call.target_function, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value( + batch, + target_function_key!(buffer_id, slot_bytes), + &buffer, + ); + } + + { + // parameters + let mut buffer = Vec::new(); + self.call_serializer + .vec_u8_serializer + .serialize(&call.parameters, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, parameters_key!(buffer_id, slot_bytes), &buffer); + } + + { + // coins + let mut buffer = Vec::new(); + self.call_serializer + .amount_serializer + .serialize(&call.coins, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, coins_key!(buffer_id, slot_bytes), &buffer); + } + + { + // max gas + let mut buffer = Vec::new(); + self.call_serializer + .u64_var_int_serializer + .serialize(&call.max_gas, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, max_gas_key!(buffer_id, slot_bytes), &buffer); + } + + { + // fee + let mut buffer = Vec::new(); + self.call_serializer + .amount_serializer + .serialize(&call.fee, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, fee_key!(buffer_id, slot_bytes), &buffer); + } + + // cancelled + let mut buffer = Vec::new(); + self.call_serializer + .bool_serializer + .serialize(&call.cancelled, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, cancelled_key!(buffer_id, slot_bytes), &buffer); + } + + fn delete_entry(&self, id: &DeferredCallId, slot: &Slot, batch: &mut DBBatch) { + let mut buffer_id = Vec::new(); + self.call_id_serializer + .serialize(id, &mut buffer_id) + .expect(DEFERRED_CALL_SER_ERROR); + + let slot_bytes = slot.to_bytes_key(); + + let db = self.db.read(); + + db.delete_key(batch, sender_address_key!(buffer_id, slot_bytes)); + db.delete_key(batch, target_slot_key!(buffer_id, slot_bytes)); + db.delete_key(batch, target_address_key!(buffer_id, slot_bytes)); + db.delete_key(batch, target_function_key!(buffer_id, slot_bytes)); + db.delete_key(batch, parameters_key!(buffer_id, slot_bytes)); + db.delete_key(batch, coins_key!(buffer_id, slot_bytes)); + db.delete_key(batch, max_gas_key!(buffer_id, slot_bytes)); + db.delete_key(batch, fee_key!(buffer_id, slot_bytes)); + db.delete_key(batch, cancelled_key!(buffer_id, slot_bytes)); + } + + pub fn apply_changes_to_batch( + &self, + changes: DeferredCallRegistryChanges, + batch: &mut DBBatch, + ) { + //Note: if a slot gas is zet to 0, delete the slot gas entry + // same for base fee + + for change in changes.slots_change.iter() { + let slot = change.0; + let slot_changes = change.1; + for (id, call_change) in slot_changes.calls.iter() { + match call_change { + DeferredRegistryCallChange::Set(call) => { + self.put_entry(slot, id, call, batch); + } + DeferredRegistryCallChange::Delete => { + self.delete_entry(id, slot, batch); + } + } + } + match slot_changes.effective_slot_gas { + DeferredRegistryGasChange::Set(v) => { + let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); + //Note: if a slot gas is zet to 0, delete the slot gas entry + if v.eq(&0) { + self.db.read().delete_key(batch, key); + } else { + let mut value_ser = Vec::new(); + self.call_serializer + .u64_var_int_serializer + .serialize(&v, &mut value_ser) + .expect(DEFERRED_CALL_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + } + DeferredRegistryGasChange::Keep => {} + } + match slot_changes.base_fee { + DeferredRegistryBaseFeeChange::Set(v) => { + let key = deferred_call_slot_base_fee_key!(slot.to_bytes_key()); + //Note: if a base fee is zet to 0, delete the base fee entry + if v.eq(&Amount::zero()) { + self.db.read().delete_key(batch, key); + } else { + let mut value_ser = Vec::new(); + self.call_serializer + .amount_serializer + .serialize(&v, &mut value_ser) + .expect(DEFERRED_CALL_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + } + DeferredRegistryBaseFeeChange::Keep => {} + } + } + + match changes.effective_total_gas { + DeferredRegistryGasChange::Set(_) => { + let key = DEFERRED_CALL_TOTAL_GAS.as_bytes().to_vec(); + let mut value_ser = Vec::new(); + self.registry_changes_serializer + .effective_total_gas_serializer + .serialize(&changes.effective_total_gas, &mut value_ser) + .expect(DEFERRED_CALL_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + DeferredRegistryGasChange::Keep => {} + } + + match changes.total_calls_registered { + DeferredRegistryGasChange::Set(_) => { + let key = DEFERRED_CALL_TOTAL_REGISTERED.as_bytes().to_vec(); + let mut value_ser = Vec::new(); + self.registry_changes_serializer + .total_calls_registered_serializer + .serialize(&changes.total_calls_registered, &mut value_ser) + .expect(DEFERRED_CALL_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + DeferredRegistryGasChange::Keep => {} + } + } +} + +pub type DeferredRegistryCallChange = SetOrDelete; +pub type DeferredRegistryGasChange = SetOrKeep; +pub type DeferredRegistryBaseFeeChange = SetOrKeep; + +/// A structure that lists slot calls for a given slot, +/// as well as global gas usage statistics. +#[derive(Debug, Clone)] +pub struct DeferredSlotCalls { + pub slot: Slot, + pub slot_calls: BTreeMap, + + // calls gas + gas_alloc_cost + // effective_slot_gas doesn't include gas of cancelled calls + pub effective_slot_gas: u64, + + pub slot_base_fee: Amount, + + // total gas booked + gas_alloc_cost + // effective_total_gas doesn't include gas of cancelled calls + pub effective_total_gas: u128, +} + +impl DeferredSlotCalls { + pub fn new(slot: Slot) -> Self { + Self { + slot, + slot_calls: BTreeMap::new(), + effective_slot_gas: 0, + slot_base_fee: Amount::zero(), + effective_total_gas: 0, + } + } + + pub fn apply_changes(&mut self, changes: &DeferredCallRegistryChanges) { + let Some(slot_changes) = changes.slots_change.get(&self.slot) else { + return; + }; + for (id, change) in &slot_changes.calls { + match change { + DeferredRegistryCallChange::Set(call) => { + self.slot_calls.insert(id.clone(), call.clone()); + } + DeferredRegistryCallChange::Delete => { + self.slot_calls.remove(id); + } + } + } + match slot_changes.effective_slot_gas { + DeferredRegistryGasChange::Set(v) => self.effective_slot_gas = v, + DeferredRegistryGasChange::Keep => {} + } + match slot_changes.base_fee { + DeferredRegistryGasChange::Set(v) => self.slot_base_fee = v, + DeferredRegistryGasChange::Keep => {} + } + match changes.effective_total_gas { + DeferredRegistryGasChange::Set(v) => self.effective_total_gas = v, + DeferredRegistryGasChange::Keep => {} + } + } +} diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs new file mode 100644 index 00000000000..93b902b9760 --- /dev/null +++ b/massa-deferred-calls/src/macros.rs @@ -0,0 +1,183 @@ +pub(crate) const DEFERRED_CALL_TOTAL_GAS: &str = "deferred_call_total_gas"; + +pub(crate) const DEFERRED_CALL_TOTAL_REGISTERED: &str = "deferred_call_total_registered"; + +pub(crate) const CALLS_TAG: u8 = 0u8; +// slot fields +pub(crate) const SLOT_TOTAL_GAS: u8 = 1u8; +pub(crate) const SLOT_BASE_FEE: u8 = 2u8; + +// call fields +pub(crate) const CALL_FIELD_SENDER_ADDRESS: u8 = 1u8; +pub(crate) const CALL_FIELD_TARGET_SLOT: u8 = 2u8; +pub(crate) const CALL_FIELD_TARGET_ADDRESS: u8 = 3u8; +pub(crate) const CALL_FIELD_TARGET_FUNCTION: u8 = 4u8; +pub(crate) const CALL_FIELD_PARAMETERS: u8 = 5u8; +pub(crate) const CALL_FIELD_COINS: u8 = 6u8; +pub(crate) const CALL_FIELD_MAX_GAS: u8 = 7u8; +pub(crate) const CALL_FIELD_FEE: u8 = 8u8; +pub(crate) const CALL_FIELD_CANCELED: u8 = 9u8; + +#[macro_export] +macro_rules! deferred_call_slot_total_gas_key { + ($slot:expr) => { + [ + DEFERRED_CALLS_PREFIX.as_bytes(), + &$slot[..], + &[$crate::macros::SLOT_TOTAL_GAS], + ] + .concat() + }; +} + +#[macro_export] +macro_rules! deferred_call_slot_base_fee_key { + ($slot:expr) => { + [ + DEFERRED_CALLS_PREFIX.as_bytes(), + &$slot[..], + &[$crate::macros::SLOT_BASE_FEE], + ] + .concat() + }; +} + +#[macro_export] +macro_rules! deferred_slot_call_prefix_key { + ($slot:expr) => { + [ + DEFERRED_CALLS_PREFIX.as_bytes(), + &$slot[..], + &[$crate::macros::CALLS_TAG], + ] + .concat() + }; +} + +#[macro_export] +macro_rules! deferred_call_prefix_key { + ($id:expr, $slot:expr) => { + [&deferred_slot_call_prefix_key!($slot), &$id[..]].concat() + }; +} + +/// key formatting macro +#[macro_export] +macro_rules! deferred_call_field_key { + ($id:expr, $slot:expr, $field:expr) => { + [deferred_call_prefix_key!($id, $slot), vec![$field]].concat() + }; +} + +/// sender address key formatting macro +#[macro_export] +macro_rules! sender_address_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_SENDER_ADDRESS) + }; +} + +/// target slot key formatting macro +#[macro_export] +macro_rules! target_slot_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_TARGET_SLOT) + }; +} + +/// target address key formatting macro +#[macro_export] +macro_rules! target_address_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_TARGET_ADDRESS) + }; +} + +/// target function key formatting macro +#[macro_export] +macro_rules! target_function_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_TARGET_FUNCTION) + }; +} + +/// parameters key formatting macro +#[macro_export] +macro_rules! parameters_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_PARAMETERS) + }; +} + +/// coins key formatting macro +#[macro_export] +macro_rules! coins_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_COINS) + }; +} + +/// max gas key formatting macro +#[macro_export] +macro_rules! max_gas_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_MAX_GAS) + }; +} + +/// fee key formatting macro +#[macro_export] +macro_rules! fee_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_FEE) + }; +} + +/// cancelled key formatting macro +#[macro_export] +macro_rules! cancelled_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_CANCELED) + }; +} + +#[cfg(test)] +mod tests { + use massa_db_exports::DEFERRED_CALLS_PREFIX; + use massa_models::{ + deferred_calls::{DeferredCallId, DeferredCallIdSerializer}, + slot::Slot, + }; + use massa_serialization::Serializer; + + #[test] + fn test_deferred_call_prefix_key() { + let slot_ser = Slot { + period: 1, + thread: 5, + } + .to_bytes_key(); + + let id = DeferredCallId::new( + 0, + Slot { + thread: 5, + period: 1, + }, + 1, + &[], + ) + .unwrap(); + + let id_ser = DeferredCallIdSerializer::new(); + let mut buf_id = Vec::new(); + id_ser.serialize(&id, &mut buf_id).unwrap(); + + let prefix = ["deferred_calls/".as_bytes(), &slot_ser, &[0u8], &buf_id].concat(); + + assert_eq!(deferred_call_prefix_key!(buf_id, slot_ser), prefix); + + // let to_check = [prefix[..], &[1u8]].concat(); + // assert_eq!(sender_address_key!(buf_id, slot_ser), to_check); + } +} diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs new file mode 100644 index 00000000000..c6475df304f --- /dev/null +++ b/massa-deferred-calls/src/registry_changes.rs @@ -0,0 +1,332 @@ +use std::{collections::BTreeMap, ops::Bound}; + +use massa_models::{ + amount::Amount, + deferred_calls::DeferredCallId, + slot::{Slot, SlotDeserializer, SlotSerializer}, + types::{SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}, +}; +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U128VarIntDeserializer, U128VarIntSerializer, + U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{context, ContextError, ParseError}, + multi::length_count, + sequence::tuple, + IResult, Parser, +}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::{ + config::DeferredCallsConfig, + slot_changes::{ + DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, + DeferredRegistrySlotChangesSerializer, + }, + DeferredCall, DeferredRegistryGasChange, +}; +use std::ops::Bound::Included; + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DeferredCallRegistryChanges { + #[serde_as(as = "Vec<(_, _)>")] + pub slots_change: BTreeMap, + + pub effective_total_gas: DeferredRegistryGasChange, + pub total_calls_registered: SetOrKeep, +} + +impl Default for DeferredCallRegistryChanges { + fn default() -> Self { + Self { + slots_change: Default::default(), + effective_total_gas: DeferredRegistryGasChange::Keep, + total_calls_registered: SetOrKeep::Keep, + } + } +} + +impl DeferredCallRegistryChanges { + pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { + self.slots_change + .entry(target_slot) + .or_default() + .delete_call(id) + } + + pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.slots_change + .entry(call.target_slot) + .or_default() + .set_call(id, call); + } + + pub fn get_call(&self, target_slot: &Slot, id: &DeferredCallId) -> Option<&DeferredCall> { + self.slots_change + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_call(id)) + } + + pub fn get_effective_slot_gas(&self, target_slot: &Slot) -> Option { + self.slots_change + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_effective_slot_gas()) + } + + pub fn set_effective_slot_gas(&mut self, target_slot: Slot, gas: u64) { + self.slots_change + .entry(target_slot) + .or_default() + .set_effective_slot_gas(gas); + } + + pub fn set_slot_base_fee(&mut self, target_slot: Slot, base_fee: Amount) { + self.slots_change + .entry(target_slot) + .or_default() + .set_base_fee(base_fee); + } + + pub fn get_slot_base_fee(&self, target_slot: &Slot) -> Option { + self.slots_change + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_base_fee()) + } + + pub fn set_effective_total_gas(&mut self, gas: u128) { + self.effective_total_gas = DeferredRegistryGasChange::Set(gas); + } + + pub fn get_effective_total_gas(&self) -> Option { + match self.effective_total_gas { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } + } + + pub fn set_total_calls_registered(&mut self, total_calls_registered: u64) { + self.total_calls_registered = SetOrKeep::Set(total_calls_registered); + } + + pub fn get_total_calls_registered(&self) -> Option { + match self.total_calls_registered { + SetOrKeep::Set(v) => Some(v), + SetOrKeep::Keep => None, + } + } +} + +pub struct DeferredRegistryChangesSerializer { + pub(crate) u64_serializer: U64VarIntSerializer, + slot_changes_serializer: DeferredRegistrySlotChangesSerializer, + slot_serializer: SlotSerializer, + pub(crate) effective_total_gas_serializer: SetOrKeepSerializer, + pub(crate) total_calls_registered_serializer: SetOrKeepSerializer, +} + +impl DeferredRegistryChangesSerializer { + pub fn new() -> Self { + Self { + u64_serializer: U64VarIntSerializer::new(), + slot_changes_serializer: DeferredRegistrySlotChangesSerializer::new(), + slot_serializer: SlotSerializer::new(), + effective_total_gas_serializer: SetOrKeepSerializer::new(U128VarIntSerializer::new()), + total_calls_registered_serializer: SetOrKeepSerializer::new(U64VarIntSerializer::new()), + } + } +} + +impl Default for DeferredRegistryChangesSerializer { + fn default() -> Self { + Self::new() + } +} + +impl Serializer for DeferredRegistryChangesSerializer { + fn serialize( + &self, + value: &DeferredCallRegistryChanges, + buffer: &mut Vec, + ) -> Result<(), SerializeError> { + self.u64_serializer.serialize( + &(value.slots_change.len().try_into().map_err(|_| { + SerializeError::GeneralError("Fail to transform usize to u64".to_string()) + })?), + buffer, + )?; + + for (slot, changes) in &value.slots_change { + self.slot_serializer.serialize(slot, buffer)?; + self.slot_changes_serializer.serialize(changes, buffer)?; + } + + self.effective_total_gas_serializer + .serialize(&value.effective_total_gas, buffer)?; + + self.total_calls_registered_serializer + .serialize(&value.total_calls_registered, buffer)?; + + Ok(()) + } +} + +pub struct DeferredRegistryChangesDeserializer { + pub(crate) u64_deserializer: U64VarIntDeserializer, + slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, + slot_deserializer: SlotDeserializer, + pub(crate) effective_total_gas_deserializer: + SetOrKeepDeserializer, + pub(crate) total_calls_registered_deserializer: + SetOrKeepDeserializer, +} + +impl DeferredRegistryChangesDeserializer { + pub fn new(config: DeferredCallsConfig) -> Self { + Self { + u64_deserializer: U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)), + slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new(config), + slot_deserializer: SlotDeserializer::new( + (Bound::Included(0), Bound::Included(u64::MAX)), + (Bound::Included(0), Bound::Excluded(config.thread_count)), + ), + effective_total_gas_deserializer: SetOrKeepDeserializer::new( + U128VarIntDeserializer::new(Included(u128::MIN), Included(u128::MAX)), + ), + total_calls_registered_deserializer: SetOrKeepDeserializer::new( + U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)), + ), + } + } +} + +impl Deserializer for DeferredRegistryChangesDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredCallRegistryChanges, E> { + context( + "Failed DeferredRegistryChanges deserialization", + tuple(( + length_count( + context("Failed length deserialization", |input| { + self.u64_deserializer.deserialize(input) + }), + |input| { + tuple(( + context("Failed slot deserialization", |input| { + self.slot_deserializer.deserialize(input) + }), + context( + "Failed set_update_or_delete_message deserialization", + |input| self.slot_changes_deserializer.deserialize(input), + ), + ))(input) + }, + ), + context("Failed total_gas deserialization", |input| { + self.effective_total_gas_deserializer.deserialize(input) + }), + context("Failed total call registered deserialization", |input| { + self.total_calls_registered_deserializer.deserialize(input) + }), + )), + ) + .map( + |(changes, total_gas, total_calls_registered)| DeferredCallRegistryChanges { + slots_change: changes.into_iter().collect::>(), + effective_total_gas: total_gas, + total_calls_registered, + }, + ) + .parse(buffer) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use massa_models::{address::Address, amount::Amount, deferred_calls::DeferredCallId}; + use massa_serialization::DeserializeError; + + use crate::{ + config::DeferredCallsConfig, + registry_changes::{ + DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, + }, + slot_changes::DeferredRegistrySlotChanges, + DeferredCall, + }; + + #[test] + fn test_deferred_registry_ser_deser() { + use crate::DeferredCallRegistryChanges; + use massa_models::slot::Slot; + use massa_serialization::{Deserializer, Serializer}; + use std::collections::BTreeMap; + + let mut changes = DeferredCallRegistryChanges { + slots_change: BTreeMap::new(), + effective_total_gas: Default::default(), + total_calls_registered: Default::default(), + }; + + let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); + registry_slot_changes.set_base_fee(Amount::from_str("100").unwrap()); + registry_slot_changes.set_effective_slot_gas(100_000); + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot, + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new( + 0, + Slot { + thread: 5, + period: 1, + }, + 1, + &[], + ) + .unwrap(); + registry_slot_changes.set_call(id, call); + + changes + .slots_change + .insert(target_slot, registry_slot_changes); + + changes.set_effective_total_gas(100_000); + + let mut buffer = Vec::new(); + let serializer = DeferredRegistryChangesSerializer::new(); + serializer.serialize(&changes, &mut buffer).unwrap(); + + let deserializer = DeferredRegistryChangesDeserializer::new(DeferredCallsConfig::default()); + let (rest, deserialized) = deserializer + .deserialize::(&buffer) + .unwrap(); + + assert_eq!(rest.len(), 0); + let base = changes.slots_change.get(&target_slot).unwrap(); + let slot_changes_deser = deserialized.slots_change.get(&target_slot).unwrap(); + assert_eq!(base.calls, slot_changes_deser.calls); + assert_eq!( + changes.effective_total_gas, + deserialized.effective_total_gas + ); + } +} diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs new file mode 100644 index 00000000000..7b73d570703 --- /dev/null +++ b/massa-deferred-calls/src/slot_changes.rs @@ -0,0 +1,283 @@ +use std::collections::BTreeMap; + +use crate::{ + call::{DeferredCallDeserializer, DeferredCallSerializer}, + config::DeferredCallsConfig, + DeferredCall, DeferredRegistryBaseFeeChange, DeferredRegistryCallChange, + DeferredRegistryGasChange, +}; +use massa_models::types::{ + SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeepDeserializer, + SetOrKeepSerializer, +}; +use massa_models::{ + amount::{Amount, AmountDeserializer, AmountSerializer}, + deferred_calls::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, +}; +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{context, ContextError, ParseError}, + multi::length_count, + sequence::tuple, + IResult, Parser, +}; +use serde::{Deserialize, Serialize}; +use std::ops::Bound::Included; + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct DeferredRegistrySlotChanges { + pub calls: BTreeMap, + pub effective_slot_gas: DeferredRegistryGasChange, + pub base_fee: DeferredRegistryBaseFeeChange, +} + +impl DeferredRegistrySlotChanges { + pub fn calls_len(&self) -> usize { + self.calls.len() + } + + /// add Delete changes will delete the call from the db registry when the slot is finalized + pub fn delete_call(&mut self, id: &DeferredCallId) { + match self.calls.entry(id.clone()) { + std::collections::btree_map::Entry::Occupied(mut v) => { + *v.get_mut() = DeferredRegistryCallChange::Delete; + } + std::collections::btree_map::Entry::Vacant(v) => { + v.insert(DeferredRegistryCallChange::Delete); + } + } + } + + pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.calls.insert(id, DeferredRegistryCallChange::Set(call)); + } + + pub fn get_call(&self, id: &DeferredCallId) -> Option<&DeferredCall> { + match self.calls.get(id) { + Some(SetOrDelete::Set(call)) => Some(call), + _ => None, + } + } + + pub fn set_effective_slot_gas(&mut self, gas: u64) { + self.effective_slot_gas = DeferredRegistryGasChange::Set(gas); + } + + pub fn get_effective_slot_gas(&self) -> Option { + match self.effective_slot_gas { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } + } + + pub fn get_base_fee(&self) -> Option { + match self.base_fee { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } + } + + pub fn set_base_fee(&mut self, base_fee: Amount) { + self.base_fee = DeferredRegistryGasChange::Set(base_fee); + } +} + +pub struct DeferredRegistrySlotChangesSerializer { + deferred_registry_slot_changes_length: U64VarIntSerializer, + call_id_serializer: DeferredCallIdSerializer, + calls_set_or_delete_serializer: SetOrDeleteSerializer, + gas_serializer: SetOrKeepSerializer, + base_fee_serializer: SetOrKeepSerializer, +} + +impl DeferredRegistrySlotChangesSerializer { + pub fn new() -> Self { + Self { + deferred_registry_slot_changes_length: U64VarIntSerializer::new(), + call_id_serializer: DeferredCallIdSerializer::new(), + calls_set_or_delete_serializer: SetOrDeleteSerializer::new( + DeferredCallSerializer::new(), + ), + gas_serializer: SetOrKeepSerializer::new(U64VarIntSerializer::new()), + base_fee_serializer: SetOrKeepSerializer::new(AmountSerializer::new()), + } + } +} + +impl Default for DeferredRegistrySlotChangesSerializer { + fn default() -> Self { + Self::new() + } +} + +impl Serializer for DeferredRegistrySlotChangesSerializer { + fn serialize( + &self, + value: &DeferredRegistrySlotChanges, + buffer: &mut Vec, + ) -> Result<(), massa_serialization::SerializeError> { + self.deferred_registry_slot_changes_length.serialize( + &(value.calls.len().try_into().map_err(|_| { + SerializeError::GeneralError("Fail to transform usize to u64".to_string()) + })?), + buffer, + )?; + for (id, call) in &value.calls { + self.call_id_serializer.serialize(id, buffer)?; + self.calls_set_or_delete_serializer + .serialize(call, buffer)?; + } + self.gas_serializer + .serialize(&value.effective_slot_gas, buffer)?; + self.base_fee_serializer + .serialize(&value.base_fee, buffer)?; + + Ok(()) + } +} + +pub struct DeferredRegistrySlotChangesDeserializer { + deferred_registry_slot_changes_length: U64VarIntDeserializer, + call_id_deserializer: DeferredCallIdDeserializer, + calls_set_or_delete_deserializer: + SetOrDeleteDeserializer, + gas_deserializer: SetOrKeepDeserializer, + base_fee_deserializer: SetOrKeepDeserializer, +} + +impl DeferredRegistrySlotChangesDeserializer { + pub fn new(config: DeferredCallsConfig) -> Self { + Self { + deferred_registry_slot_changes_length: U64VarIntDeserializer::new( + Included(u64::MIN), + Included(config.max_pool_changes), + ), + call_id_deserializer: DeferredCallIdDeserializer::new(), + calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( + DeferredCallDeserializer::new(config), + ), + gas_deserializer: SetOrKeepDeserializer::new(U64VarIntDeserializer::new( + Included(0), + Included(config.max_gas), + )), + base_fee_deserializer: SetOrKeepDeserializer::new(AmountDeserializer::new( + Included(Amount::MIN), + Included(Amount::MAX), + )), + } + } +} + +impl Deserializer for DeferredRegistrySlotChangesDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredRegistrySlotChanges, E> { + context( + "Failed DeferredRegistrySlotChanges deserialization", + tuple(( + length_count( + context("Failed length deserialization", |input| { + self.deferred_registry_slot_changes_length + .deserialize(input) + }), + |input: &'a [u8]| { + tuple(( + context("Failed id deserialization", |input| { + self.call_id_deserializer.deserialize(input) + }), + context( + "Failed set_update_or_delete_message deserialization", + |input| self.calls_set_or_delete_deserializer.deserialize(input), + ), + ))(input) + }, + ), + context("Failed gas deserialization", |input| { + self.gas_deserializer.deserialize(input) + }), + context("Failed base fee deserialize", |input| { + self.base_fee_deserializer.deserialize(input) + }), + )), + ) + .map(|(vec, gas, base_fee)| { + let calls = vec.into_iter().collect::>(); + + DeferredRegistrySlotChanges { + calls, + effective_slot_gas: gas, + base_fee, + } + }) + .parse(buffer) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use massa_models::{ + address::Address, amount::Amount, deferred_calls::DeferredCallId, slot::Slot, + }; + use massa_serialization::{DeserializeError, Deserializer, Serializer}; + + use crate::{config::DeferredCallsConfig, DeferredCall}; + + use super::{ + DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, + DeferredRegistrySlotChangesSerializer, + }; + + #[test] + fn test_slot_changes_ser_deser() { + let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); + registry_slot_changes.set_base_fee(Amount::from_str("100").unwrap()); + registry_slot_changes.set_effective_slot_gas(100_000); + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot, + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new( + 0, + Slot { + thread: 5, + period: 1, + }, + 1, + &[], + ) + .unwrap(); + + registry_slot_changes.set_call(id, call); + + let mut buffer = Vec::new(); + let serializer = DeferredRegistrySlotChangesSerializer::new(); + serializer + .serialize(®istry_slot_changes, &mut buffer) + .unwrap(); + + let deserializer = + DeferredRegistrySlotChangesDeserializer::new(DeferredCallsConfig::default()); + let (rest, changes_deser) = deserializer + .deserialize::(&buffer) + .unwrap(); + assert!(rest.is_empty()); + assert_eq!(changes_deser.calls, registry_slot_changes.calls); + } +} diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs new file mode 100644 index 00000000000..16879e738be --- /dev/null +++ b/massa-deferred-calls/src/tests/mod.rs @@ -0,0 +1,132 @@ +use super::*; +use crate::{DeferredCall, DeferredCallRegistry, DeferredCallRegistryChanges}; +use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController, ShareableMassaDBController}; +use massa_db_worker::MassaDB; +use massa_models::{ + address::Address, + amount::Amount, + config::THREAD_COUNT, + deferred_calls::{DeferredCallId, DeferredCallIdSerializer}, + slot::Slot, +}; +use parking_lot::RwLock; +use std::{str::FromStr, sync::Arc}; +use tempfile::tempdir; + +#[test] +fn call_registry_apply_changes() { + let temp_dir = tempdir().expect("Unable to create a temp folder"); + let db_config = MassaDBConfig { + path: temp_dir.path().to_path_buf(), + max_history_length: 100, + max_final_state_elements_size: 100, + max_versioning_elements_size: 100, + thread_count: THREAD_COUNT, + max_ledger_backups: 100, + }; + let call_id_serializer = DeferredCallIdSerializer::new(); + let db: ShareableMassaDBController = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> + )); + + let registry = DeferredCallRegistry::new(db, DeferredCallsConfig::default()); + + let mut changes = DeferredCallRegistryChanges::default(); + + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot, + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new(0, target_slot, 1, &[]).unwrap(); + let mut buf_id = Vec::new(); + call_id_serializer.serialize(&id, &mut buf_id).unwrap(); + + changes.set_call(id.clone(), call.clone()); + + let mut batch = DBBatch::new(); + registry.apply_changes_to_batch(changes, &mut batch); + + registry.db.write().write_batch(batch, DBBatch::new(), None); + + let result = registry.get_call(&target_slot, &id).unwrap(); + assert!(result.target_function.eq(&call.target_function)); + assert_eq!(result.sender_address, call.sender_address); +} + +#[test] +fn call_registry_get_slot_calls() { + let temp_dir = tempdir().expect("Unable to create a temp folder"); + let db_config = MassaDBConfig { + path: temp_dir.path().to_path_buf(), + max_history_length: 100, + max_final_state_elements_size: 100, + max_versioning_elements_size: 100, + thread_count: THREAD_COUNT, + max_ledger_backups: 100, + }; + let call_id_serializer = DeferredCallIdSerializer::new(); + let db: ShareableMassaDBController = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> + )); + + let registry = DeferredCallRegistry::new(db, DeferredCallsConfig::default()); + + let mut changes = DeferredCallRegistryChanges::default(); + + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot, + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new(0, target_slot, 1, &[]).unwrap(); + + let id2 = DeferredCallId::new(0, target_slot, 1, &[123]).unwrap(); + + let mut buf_id = Vec::new(); + call_id_serializer.serialize(&id, &mut buf_id).unwrap(); + + changes.set_call(id.clone(), call.clone()); + changes.set_call(id2.clone(), call.clone()); + changes.set_effective_total_gas(100); + changes.set_effective_slot_gas(target_slot, 100_000); + + changes.set_slot_base_fee(target_slot, Amount::from_raw(10000000)); + + let mut batch = DBBatch::new(); + // 2 calls + registry.apply_changes_to_batch(changes, &mut batch); + + registry.db.write().write_batch(batch, DBBatch::new(), None); + + let result = registry.get_slot_calls(target_slot); + + assert!(result.slot_calls.len() == 2); + assert!(result.slot_calls.contains_key(&id)); + assert!(result.slot_calls.contains_key(&id2)); + assert_eq!(result.effective_total_gas, 100); + assert_eq!(result.slot_base_fee, Amount::from_raw(10000000)); + assert_eq!(result.effective_slot_gas, 100_000); +} diff --git a/massa-execution-exports/Cargo.toml b/massa-execution-exports/Cargo.toml index fc0e62cfc46..a004bb533ee 100644 --- a/massa-execution-exports/Cargo.toml +++ b/massa-execution-exports/Cargo.toml @@ -12,23 +12,26 @@ dump-block = [] execution-info = ["execution-trace"] [dependencies] -displaydoc = {workspace = true} -thiserror = {workspace = true} -num = {workspace = true, "features" = ["serde"]} # BOM UPGRADE Revert to {"version": "0.4", "features": ["serde"]} if problem -tempfile = {workspace = true, "optional" = true} # BOM UPGRADE Revert to {"version": "3.3", "optional": true} if problem -tokio = {workspace = true, "features" = ["sync"]} -mockall = {workspace = true, "optional" = true} # BOM UPGRADE Revert to {"version": "0.11.4", "optional": true} if problem -massa-proto-rs = {workspace = true, "features" = ["tonic"]} -massa_hash = {workspace = true} -massa_models = {workspace = true} -massa_time = {workspace = true} -massa_storage = {workspace = true} -massa_final_state = {workspace = true} -massa_pos_exports = {workspace = true} -massa_module_cache = {workspace = true} -massa_versioning = {workspace = true} -massa-sc-runtime = {workspace = true} -serde = {workspace = true, "features" = ["derive"]} +displaydoc = { workspace = true } +thiserror = { workspace = true } +num = { workspace = true, "features" = [ + "serde", +] } # BOM UPGRADE Revert to {"version": "0.4", "features": ["serde"]} if problem +tempfile = { workspace = true, "optional" = true } # BOM UPGRADE Revert to {"version": "3.3", "optional": true} if problem +tokio = { workspace = true, "features" = ["sync"] } +mockall = { workspace = true, "optional" = true } # BOM UPGRADE Revert to {"version": "0.11.4", "optional": true} if problem +massa_deferred_calls = { workspace = true } +massa-proto-rs = { workspace = true, "features" = ["tonic"] } +massa_hash = { workspace = true } +massa_models = { workspace = true } +massa_time = { workspace = true } +massa_storage = { workspace = true } +massa_final_state = { workspace = true } +massa_pos_exports = { workspace = true } +massa_module_cache = { workspace = true } +massa_versioning = { workspace = true } +massa-sc-runtime = { workspace = true } +serde = { workspace = true, "features" = ["derive"] } [dev-dependencies] -mockall = {workspace = true} +mockall = { workspace = true } diff --git a/massa-execution-exports/src/error.rs b/massa-execution-exports/src/error.rs index 21fcbe3f85d..1f92cc75a44 100644 --- a/massa-execution-exports/src/error.rs +++ b/massa-execution-exports/src/error.rs @@ -67,6 +67,9 @@ pub enum ExecutionError { /// Factory error: {0} FactoryError(#[from] FactoryError), + + /// Autonomous smart contract call error: {0} + DeferredCallsError(String), } /// Execution query errors diff --git a/massa-execution-exports/src/mapping_grpc.rs b/massa-execution-exports/src/mapping_grpc.rs index 5aa9875442b..425d8d2942f 100644 --- a/massa-execution-exports/src/mapping_grpc.rs +++ b/massa-execution-exports/src/mapping_grpc.rs @@ -9,6 +9,7 @@ use crate::{ }; use grpc_api::execution_query_request_item as exec; use massa_models::address::Address; +use massa_models::deferred_calls::DeferredCallId; use massa_models::error::ModelsError; use massa_models::execution::EventFilter; use massa_models::mapping_grpc::to_denunciation_index; @@ -133,6 +134,30 @@ pub fn to_querystate_filter( let event_filter = to_event_filter(value.filters)?; Ok(ExecutionQueryRequestItem::Events(event_filter)) } + exec::RequestItem::DeferredCallQuote(value) => { + Ok(ExecutionQueryRequestItem::DeferredCallQuote { + target_slot: value + .target_slot + .ok_or(ModelsError::ErrorRaised( + "target slot is required".to_string(), + ))? + .into(), + max_gas_request: value.max_gas, + params_size: value.params_size, + }) + } + exec::RequestItem::DeferredCallInfo(info) => { + let id = DeferredCallId::from_str(&info.call_id)?; + Ok(ExecutionQueryRequestItem::DeferredCallInfo(id)) + } + exec::RequestItem::DeferredCallsBySlot(value) => { + Ok(ExecutionQueryRequestItem::DeferredCallsBySlot( + value + .slot + .ok_or(ModelsError::ErrorRaised("slot is required".to_string()))? + .into(), + )) + } } } else { Err(ModelsError::ErrorRaised("no filter provided".to_string())) @@ -265,6 +290,36 @@ fn to_execution_query_result( }, ) } + ExecutionQueryResponseItem::DeferredCallQuote( + target_slot, + max_gas_request, + available, + price, + ) => grpc_api::execution_query_response_item::ResponseItem::DeferredCallQuote( + grpc_api::DeferredCallQuoteResponse { + target_slot: Some(target_slot.into()), + max_gas_request, + available, + price: Some(price.into()), + }, + ), + ExecutionQueryResponseItem::DeferredCallInfo(call_id, call) => { + grpc_api::execution_query_response_item::ResponseItem::DeferredCallInfo( + grpc_api::DeferredCallInfoResponse { + call_id: call_id.to_string(), + call: Some(call.into()), + }, + ) + } + ExecutionQueryResponseItem::DeferredCallsBySlot(slot, ids) => { + let arr = ids.into_iter().map(|id| id.to_string()).collect(); + grpc_api::execution_query_response_item::ResponseItem::DeferredCallsBySlot( + grpc_api::DeferredCallsBySlotResponse { + slot: Some(slot.into()), + call_ids: arr, + }, + ) + } }; grpc_api::ExecutionQueryResponseItem { diff --git a/massa-execution-exports/src/settings.rs b/massa-execution-exports/src/settings.rs index 9a3cd4cd4d7..867803fb041 100644 --- a/massa-execution-exports/src/settings.rs +++ b/massa-execution-exports/src/settings.rs @@ -2,6 +2,7 @@ //! This module provides the structures used to provide configuration parameters to the Execution system +use massa_deferred_calls::config::DeferredCallsConfig; use massa_models::amount::Amount; use massa_sc_runtime::{CondomLimits, GasCosts}; use massa_time::MassaTime; @@ -107,6 +108,8 @@ pub struct ExecutionConfig { pub max_recursive_calls_depth: u16, /// Runtime condom middleware limits pub condom_limits: CondomLimits, + /// deferred calls config + pub deferred_calls_config: DeferredCallsConfig, /// Maximum number of event that an operation can emit pub max_event_per_operation: usize, } diff --git a/massa-execution-exports/src/test_exports/config.rs b/massa-execution-exports/src/test_exports/config.rs index 7b644abab83..daac50eff03 100644 --- a/massa-execution-exports/src/test_exports/config.rs +++ b/massa-execution-exports/src/test_exports/config.rs @@ -3,6 +3,7 @@ //! This file defines testing tools related to the configuration use crate::{ExecutionConfig, StorageCostsConstants}; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_models::config::*; use massa_sc_runtime::{CondomLimits, GasCosts}; use massa_time::MassaTime; @@ -27,6 +28,28 @@ impl Default for ExecutionConfig { let block_dump_folder_path = TempDir::new().unwrap().path().to_path_buf(); std::fs::create_dir_all(block_dump_folder_path.clone()).unwrap(); + #[cfg(feature = "gas_calibration")] + let limits = CondomLimits::default(); + + #[cfg(not(feature = "gas_calibration"))] + let limits = CondomLimits { + max_exports: Some(100), + max_functions: Some(100), + max_signature_len: Some(100), + max_name_len: Some(100), + max_imports_len: Some(100), + max_table_initializers_len: Some(100), + max_passive_elements_len: Some(100), + max_passive_data_len: Some(100), + max_global_initializers_len: Some(100), + max_function_names_len: Some(100), + max_tables_count: Some(16), + max_memories_len: Some(1), + max_globals_len: Some(100), + max_custom_sections_len: Some(100), + max_custom_sections_data_len: Some(1_000_000), + }; + Self { readonly_queue_length: 100, max_final_events: 1000, @@ -78,23 +101,8 @@ impl Default for ExecutionConfig { max_execution_traces_slot_limit: 320, block_dump_folder_path, max_recursive_calls_depth: 25, - condom_limits: CondomLimits { - max_exports: Some(100), - max_functions: Some(100), - max_signature_len: Some(100), - max_name_len: Some(100), - max_imports_len: Some(100), - max_table_initializers_len: Some(100), - max_passive_elements_len: Some(100), - max_passive_data_len: Some(100), - max_global_initializers_len: Some(100), - max_function_names_len: Some(100), - max_tables_count: Some(16), - max_memories_len: Some(1), - max_globals_len: Some(100), - max_custom_sections_len: Some(100), - max_custom_sections_data_len: Some(1_000_000), - }, + condom_limits: limits, + deferred_calls_config: DeferredCallsConfig::default(), } } } diff --git a/massa-execution-exports/src/types.rs b/massa-execution-exports/src/types.rs index dee597eb67d..ce92ad62aab 100644 --- a/massa-execution-exports/src/types.rs +++ b/massa-execution-exports/src/types.rs @@ -4,11 +4,13 @@ use crate::error::ExecutionQueryError; use crate::event_store::EventStore; +use massa_deferred_calls::DeferredCall; use massa_final_state::StateChanges; use massa_hash::Hash; use massa_models::block_id::BlockId; use massa_models::bytecode::Bytecode; use massa_models::datastore::Datastore; +use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::DenunciationIndex; use massa_models::execution::EventFilter; use massa_models::operation::OperationId; @@ -99,6 +101,21 @@ pub enum ExecutionQueryRequestItem { OpExecutionStatusCandidate(OperationId), /// gets the execution status (final) for an operation, returns ExecutionQueryResponseItem::ExecutionStatus(status) OpExecutionStatusFinal(OperationId), + + /// gets the deferred call quote (candidate) for a slot, returns ExecutionQueryResponseItem::DeferredCallQuote(available, price) + DeferredCallQuote { + /// slot to query + target_slot: Slot, + /// gas request + max_gas_request: u64, + /// params size + params_size: u64, + }, + /// get info of deferred calls + DeferredCallInfo(DeferredCallId), + /// retrieves the deferred call for given slot + DeferredCallsBySlot(Slot), + /// gets the execution status (candidate) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status) DenunciationExecutionStatusCandidate(DenunciationIndex), /// gets the execution status (final) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status) @@ -139,6 +156,12 @@ pub enum ExecutionQueryResponseItem { DatastoreValue(Vec), /// list of keys KeyList(BTreeSet>), + /// deferred call quote (target_slot, gas_request, available, price) + DeferredCallQuote(Slot, u64, bool, Amount), + /// deferred call info value + DeferredCallInfo(DeferredCallId, DeferredCall), + /// deferred call slot calls value + DeferredCallsBySlot(Slot, Vec), /// deferred credits value DeferredCredits(BTreeMap), /// execution status value diff --git a/massa-execution-exports/src/types_trace_info.rs b/massa-execution-exports/src/types_trace_info.rs index 36b09d9d578..c37888157bf 100644 --- a/massa-execution-exports/src/types_trace_info.rs +++ b/massa-execution-exports/src/types_trace_info.rs @@ -23,6 +23,8 @@ pub struct SlotAbiCallStack { pub slot: Slot, /// asc call stacks pub asc_call_stacks: Vec>, + /// deferred call stacks + pub deferred_call_stacks: Vec>, /// operation call stacks pub operation_call_stacks: PreHashMap>, } diff --git a/massa-execution-worker/Cargo.toml b/massa-execution-worker/Cargo.toml index 92f8403686d..f2b6a3e6361 100644 --- a/massa-execution-worker/Cargo.toml +++ b/massa-execution-worker/Cargo.toml @@ -69,6 +69,7 @@ criterion = { workspace = true, "optional" = true } massa_pos_worker = { workspace = true, "optional" = true } massa_async_pool = { workspace = true } massa_channel = { workspace = true } +massa_deferred_calls = { workspace = true } massa_executed_ops = { workspace = true } massa_execution_exports = { workspace = true } massa_models = { workspace = true } diff --git a/massa-execution-worker/src/active_history.rs b/massa-execution-worker/src/active_history.rs index c632a2405be..3c3763bddbf 100644 --- a/massa-execution-worker/src/active_history.rs +++ b/massa-execution-worker/src/active_history.rs @@ -1,10 +1,9 @@ use massa_async_pool::{AsyncMessage, AsyncMessageId, AsyncMessageUpdate}; use massa_execution_exports::ExecutionOutput; -use massa_ledger_exports::{ - Applicable, LedgerEntry, LedgerEntryUpdate, SetOrDelete, SetOrKeep, SetUpdateOrDelete, -}; +use massa_ledger_exports::{LedgerEntry, LedgerEntryUpdate}; use massa_models::denunciation::DenunciationIndex; use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet}; +use massa_models::types::{Applicable, SetOrDelete, SetOrKeep, SetUpdateOrDelete}; use massa_models::{ address::Address, amount::Amount, bytecode::Bytecode, operation::OperationId, slot::Slot, }; diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 54f65417f60..bdb857b99bb 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -9,12 +9,15 @@ use crate::active_history::HistorySearchResult; use crate::speculative_async_pool::SpeculativeAsyncPool; +use crate::speculative_deferred_calls::SpeculativeDeferredCallRegistry; use crate::speculative_executed_denunciations::SpeculativeExecutedDenunciations; use crate::speculative_executed_ops::SpeculativeExecutedOps; use crate::speculative_ledger::SpeculativeLedger; use crate::{active_history::ActiveHistory, speculative_roll_state::SpeculativeRollState}; use massa_async_pool::{AsyncMessage, AsyncPoolChanges}; use massa_async_pool::{AsyncMessageId, AsyncMessageInfo}; +use massa_deferred_calls::registry_changes::DeferredCallRegistryChanges; +use massa_deferred_calls::{DeferredCall, DeferredSlotCalls}; use massa_executed_ops::{ExecutedDenunciationsChanges, ExecutedOpsChanges}; use massa_execution_exports::{ EventStore, ExecutedBlockInfo, ExecutionConfig, ExecutionError, ExecutionOutput, @@ -22,12 +25,14 @@ use massa_execution_exports::{ }; use massa_final_state::{FinalStateController, StateChanges}; use massa_hash::Hash; -use massa_ledger_exports::{LedgerChanges, SetOrKeep}; +use massa_ledger_exports::LedgerChanges; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::block_id::BlockIdSerializer; use massa_models::bytecode::Bytecode; +use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::DenunciationIndex; use massa_models::timeslots::get_block_slot_timestamp; +use massa_models::types::SetOrKeep; use massa_models::{ address::Address, amount::Amount, @@ -58,6 +63,9 @@ pub struct ExecutionContextSnapshot { /// speculative asynchronous pool messages emitted so far in the context pub async_pool_changes: AsyncPoolChanges, + /// speculative deferred calls changes + pub deferred_calls_changes: DeferredCallRegistryChanges, + /// the associated message infos for the speculative async pool pub message_infos: BTreeMap, @@ -126,6 +134,9 @@ pub struct ExecutionContext { /// as seen after everything that happened so far in the context speculative_async_pool: SpeculativeAsyncPool, + /// speculative deferred calls state, + speculative_deferred_calls: SpeculativeDeferredCallRegistry, + /// speculative roll state, /// as seen after everything that happened so far in the context speculative_roll_state: SpeculativeRollState, @@ -223,6 +234,11 @@ impl ExecutionContext { final_state.clone(), active_history.clone(), ), + speculative_deferred_calls: SpeculativeDeferredCallRegistry::new( + final_state.clone(), + active_history.clone(), + config.deferred_calls_config, + ), speculative_roll_state: SpeculativeRollState::new( final_state.clone(), active_history.clone(), @@ -263,6 +279,7 @@ impl ExecutionContext { ExecutionContextSnapshot { ledger_changes: self.speculative_ledger.get_snapshot(), async_pool_changes, + deferred_calls_changes: self.speculative_deferred_calls.get_snapshot(), message_infos, pos_changes: self.speculative_roll_state.get_snapshot(), executed_ops: self.speculative_executed_ops.get_snapshot(), @@ -286,11 +303,20 @@ impl ExecutionContext { /// * `snapshot`: a saved snapshot to be restored /// * `error`: an execution error to emit as an event conserved after snapshot reset. pub fn reset_to_snapshot(&mut self, snapshot: ExecutionContextSnapshot, error: ExecutionError) { + // Emit the error event. + // Note that the context event counter is properly handled by event_emit (see doc). + self.event_emit(self.event_create( + serde_json::json!({ "massa_execution_error": format!("{}", error) }).to_string(), + true, + )); + // Reset context to snapshot. self.speculative_ledger .reset_to_snapshot(snapshot.ledger_changes); self.speculative_async_pool .reset_to_snapshot((snapshot.async_pool_changes, snapshot.message_infos)); + self.speculative_deferred_calls + .reset_to_snapshot(snapshot.deferred_calls_changes); self.speculative_roll_state .reset_to_snapshot(snapshot.pos_changes); self.speculative_executed_ops @@ -309,13 +335,6 @@ impl ExecutionContext { for event in self.events.0.range_mut(snapshot.event_count..) { event.context.is_error = true; } - - // Emit the error event. - // Note that the context event counter is properly handled by event_emit (see doc). - self.event_emit(self.event_create( - serde_json::json!({ "massa_execution_error": format!("{}", error) }).to_string(), - true, - )); } /// Create a new `ExecutionContext` for read-only execution @@ -950,6 +969,7 @@ impl ExecutionContext { let state_changes = StateChanges { ledger_changes: self.speculative_ledger.take(), async_pool_changes: self.speculative_async_pool.take(), + deferred_call_changes: self.speculative_deferred_calls.take(), pos_changes: self.speculative_roll_state.take(), executed_ops_changes: self.speculative_executed_ops.take(), executed_denunciations_changes: self.speculative_executed_denunciations.take(), @@ -1129,6 +1149,123 @@ impl ExecutionContext { ))), } } + + pub fn deferred_calls_advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { + self.speculative_deferred_calls.advance_slot(current_slot) + } + + /// Get the price it would cost to reserve "gas" with params at target slot "slot". + pub fn deferred_calls_compute_call_fee( + &self, + target_slot: Slot, + max_gas_request: u64, + current_slot: Slot, + params_size: u64, + ) -> Result { + self.speculative_deferred_calls.compute_call_fee( + target_slot, + max_gas_request, + current_slot, + params_size, + ) + } + + pub fn deferred_call_register( + &mut self, + call: DeferredCall, + ) -> Result { + self.speculative_deferred_calls + .register_call(call, self.execution_trail_hash) + } + + /// Check if a deferred call exists + /// If it exists, check if it has been cancelled + /// If it has been cancelled, return false + pub fn deferred_call_exists(&self, call_id: &DeferredCallId) -> bool { + if let Some(call) = self.speculative_deferred_calls.get_call(call_id) { + return !call.cancelled; + } + false + } + + /// Get a deferred call by its id + pub fn get_deferred_call(&self, call_id: &DeferredCallId) -> Option { + self.speculative_deferred_calls.get_call(call_id) + } + + /// when a deferred call execution fails we need to refund the coins to the caller + pub fn deferred_call_fail_exec( + &mut self, + id: &DeferredCallId, + call: &DeferredCall, + ) -> Option<(Address, Result)> { + #[allow(unused_assignments, unused_mut)] + let mut result = None; + + let transfer_result = + self.transfer_coins(None, Some(call.sender_address), call.coins, false); + if let Err(e) = transfer_result.as_ref() { + debug!( + "deferred call cancel: reimbursement of {} failed: {}", + call.sender_address, e + ); + } + + let event = self.event_create(format!("DeferredCall execution fail call_id:{}", id), true); + self.event_emit(event); + + #[cfg(feature = "execution-info")] + if let Err(e) = transfer_result { + result = Some((call.sender_address, Err(e.to_string()))) + } else { + result = Some((call.sender_address, Ok(call.coins))); + } + + result + } + + /// when a deferred call is cancelled we need to refund the coins to the caller + pub fn deferred_call_cancel( + &mut self, + call_id: &DeferredCallId, + caller_address: Address, + ) -> Result<(), ExecutionError> { + match self.speculative_deferred_calls.get_call(call_id) { + Some(call) => { + // check that the caller is the one who registered the deferred call + if call.sender_address != caller_address { + return Err(ExecutionError::DeferredCallsError(format!( + "only the caller {} can cancel the deferred call", + call.sender_address + ))); + } + + let (address, amount) = self.speculative_deferred_calls.cancel_call(call_id)?; + + // refund the coins to the caller + let transfer_result = self.transfer_coins(None, Some(address), amount, false); + if let Err(e) = transfer_result.as_ref() { + debug!( + "deferred call cancel: reimbursement of {} failed: {}", + address, e + ); + } + + Ok(()) + } + _ => Err(ExecutionError::DeferredCallsError(format!( + "deferred call {} does not exist", + call_id + )))?, + } + } + + /// find the deferred calls for a given slot + pub fn get_deferred_calls_by_slot(&self, slot: Slot) -> BTreeMap { + self.speculative_deferred_calls + .get_calls_by_slot(slot) + .slot_calls + } } /// Generate the execution trail hash diff --git a/massa-execution-worker/src/controller.rs b/massa-execution-worker/src/controller.rs index 08b749e928d..1ce76c3a84e 100644 --- a/massa-execution-worker/src/controller.rs +++ b/massa-execution-worker/src/controller.rs @@ -331,6 +331,35 @@ impl ExecutionController for ExecutionControllerImpl { execution_lock.get_filtered_sc_output_event(filter), )) } + ExecutionQueryRequestItem::DeferredCallQuote { + target_slot, + max_gas_request, + params_size, + } => { + let result = execution_lock.deferred_call_quote( + target_slot, + max_gas_request, + params_size, + ); + Ok(ExecutionQueryResponseItem::DeferredCallQuote( + result.0, result.1, result.2, result.3, + )) + } + ExecutionQueryRequestItem::DeferredCallInfo(deferred_call_id) => execution_lock + .deferred_call_info(&deferred_call_id) + .ok_or_else(|| { + ExecutionQueryError::NotFound(format!( + "Deferred call id {}", + deferred_call_id + )) + }) + .map(|call| { + ExecutionQueryResponseItem::DeferredCallInfo(deferred_call_id, call) + }), + ExecutionQueryRequestItem::DeferredCallsBySlot(slot) => { + let res = execution_lock.get_deferred_calls_by_slot(slot); + Ok(ExecutionQueryResponseItem::DeferredCallsBySlot(slot, res)) + } }; resp.responses.push(resp_item); } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 1da3f12b680..8fffb05d7c6 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -15,6 +15,7 @@ use crate::stats::ExecutionStatsCounter; #[cfg(feature = "dump-block")] use crate::storage_backend::StorageBackend; use massa_async_pool::AsyncMessage; +use massa_deferred_calls::DeferredCall; use massa_execution_exports::{ EventStore, ExecutedBlockInfo, ExecutionBlockMetadata, ExecutionChannels, ExecutionConfig, ExecutionError, ExecutionOutput, ExecutionQueryCycleInfos, ExecutionQueryStakerInfo, @@ -22,12 +23,13 @@ use massa_execution_exports::{ ReadOnlyExecutionTarget, SlotExecutionOutput, }; use massa_final_state::FinalStateController; -use massa_ledger_exports::{SetOrDelete, SetUpdateOrDelete}; use massa_metrics::MassaMetrics; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::bytecode::Bytecode; +use massa_models::types::{SetOrDelete, SetUpdateOrDelete}; use massa_models::datastore::get_prefix_bounds; +use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::{Denunciation, DenunciationIndex}; use massa_models::execution::EventFilter; use massa_models::output_event::SCOutputEvent; @@ -51,7 +53,9 @@ use std::collections::{BTreeMap, BTreeSet}; use std::sync::Arc; use tracing::{debug, info, trace, warn}; -use crate::execution_info::{AsyncMessageExecutionResult, DenunciationResult}; +use crate::execution_info::{ + AsyncMessageExecutionResult, DeferredCallExecutionResult, DenunciationResult, +}; #[cfg(feature = "execution-info")] use crate::execution_info::{ExecutionInfo, ExecutionInfoForSlot, OperationInfo}; #[cfg(feature = "execution-trace")] @@ -1236,6 +1240,146 @@ impl ExecutionState { } } + fn execute_deferred_call( + &self, + id: &DeferredCallId, + call: DeferredCall, + ) -> Result { + let mut result = DeferredCallExecutionResult::new(&call); + + let snapshot = { + let mut context = context_guard!(self); + + // refund the sender for the storage costs + let amount = DeferredCall::get_storage_cost( + self.config.storage_costs_constants.ledger_cost_per_byte, + call.parameters.len() as u64, + self.config.max_function_length, + ); + context + .transfer_coins(None, Some(call.sender_address), amount, false) + .expect("Error refunding storage costs"); + + context.get_snapshot() + }; + + if call.cancelled { + Ok(result) + } else { + let deferred_call_execution = || { + let bytecode = { + // acquire write access to the context + let mut context = context_guard!(self); + + // Set the call stack + // This needs to be defined before anything can fail, so that the emitted event contains the right stack + context.stack = vec![ + ExecutionStackElement { + address: call.sender_address, + coins: Default::default(), + owned_addresses: vec![call.sender_address], + operation_datastore: None, + }, + ExecutionStackElement { + address: call.target_address, + coins: call.coins, + owned_addresses: vec![call.target_address], + operation_datastore: None, + }, + ]; + + // Ensure that the target address is an SC address + // Ensure that the target address exists + context.check_target_sc_address(call.target_address)?; + + // credit coins to the target address + if let Err(err) = + context.transfer_coins(None, Some(call.target_address), call.coins, false) + { + // coin crediting failed: reset context to snapshot and reimburse sender + return Err(ExecutionError::DeferredCallsError(format!( + "could not credit coins to target of deferred call execution: {}", + err + ))); + } + + // quit if there is no function to be called + if call.target_function.is_empty() { + return Err(ExecutionError::DeferredCallsError( + "no function to call in the deferred call".to_string(), + )); + } + + // Load bytecode. Assume empty bytecode if not found. + context + .get_bytecode(&call.target_address) + .ok_or(ExecutionError::DeferredCallsError( + "no bytecode found".to_string(), + ))? + .0 + }; + + let module = self.module_cache.write().load_module( + &bytecode, + call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), + )?; + let response = massa_sc_runtime::run_function( + &*self.execution_interface, + module, + &call.target_function, + &call.parameters, + call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), + self.config.gas_costs.clone(), + self.config.condom_limits.clone(), + ); + + match response { + Ok(res) => { + self.module_cache + .write() + .set_init_cost(&bytecode, res.init_gas_cost); + #[cfg(feature = "execution-trace")] + { + result.traces = + Some((res.trace.into_iter().map(|t| t.into()).collect(), true)); + } + // #[cfg(feature = "execution-info")] + // { + // result.success = true; + // } + result.success = true; + Ok(result) + } + Err(error) => { + if let VMError::ExecutionError { init_gas_cost, .. } = error { + self.module_cache + .write() + .set_init_cost(&bytecode, init_gas_cost); + } + // execution failed: reset context to snapshot and reimburse sender + Err(ExecutionError::VMError { + context: "Deferred Call".to_string(), + error, + }) + } + } + }; + + // execute the deferred call + let execution_result = deferred_call_execution(); + + // if the execution failed, reset the context to the snapshot + if let Err(err) = &execution_result { + let mut context = context_guard!(self); + context.reset_to_snapshot(snapshot, err.clone()); + context.deferred_call_fail_exec(id, &call); + self.massa_metrics.inc_deferred_calls_failed(); + } else { + self.massa_metrics.inc_deferred_calls_executed(); + } + execution_result + } + } /// Executes a full slot (with or without a block inside) without causing any changes to the state, /// just yielding the execution output. /// @@ -1257,6 +1401,7 @@ impl ExecutionState { slot: *slot, operation_call_stacks: PreHashMap::default(), asc_call_stacks: vec![], + deferred_call_stacks: vec![], }; #[cfg(feature = "execution-trace")] let mut transfers = vec![]; @@ -1275,42 +1420,42 @@ impl ExecutionState { self.mip_store.clone(), ); - // Get asynchronous messages to execute - let messages = execution_context.take_async_batch( - self.config.max_async_gas, - self.config.async_msg_cst_gas_cost, - ); + // Deferred calls + let calls = execution_context.deferred_calls_advance_slot(*slot); // Apply the created execution context for slot execution *context_guard!(self) = execution_context; - // Try executing asynchronous messages. - // Effects are cancelled on failure and the sender is reimbursed. - for (_message_id, message) in messages { - let opt_bytecode = context_guard!(self).get_bytecode(&message.destination); - - match self.execute_async_message(message, opt_bytecode) { - Ok(_message_return) => { + for (id, call) in calls.slot_calls { + let cancelled = call.cancelled; + match self.execute_deferred_call(&id, call) { + Ok(_exec) => { + if cancelled { + continue; + } + info!("executed deferred call: {:?}", id); cfg_if::cfg_if! { if #[cfg(feature = "execution-trace")] { // Safe to unwrap - slot_trace.asc_call_stacks.push(_message_return.traces.unwrap().0); + slot_trace.deferred_call_stacks.push(_exec.traces.unwrap().0); } else if #[cfg(feature = "execution-info")] { - slot_trace.asc_call_stacks.push(_message_return.traces.clone().unwrap().0); - exec_info.async_messages.push(Ok(_message_return)); + slot_trace.deferred_call_stacks.push(_exec.traces.clone().unwrap().0); + exec_info.deferred_calls_messages.push(Ok(_exec)); } } } Err(err) => { - let msg = format!("failed executing async message: {}", err); + let msg = format!("failed executing deferred call: {}", err); #[cfg(feature = "execution-info")] - exec_info.async_messages.push(Err(msg.clone())); - debug!(msg); + exec_info.deferred_calls_messages.push(Err(msg.clone())); + dbg!(msg); } } } let mut block_info: Option = None; + // Set block gas (max_gas_per_block - gas used by deferred calls) + let mut remaining_block_gas = self.config.max_gas_per_block; // Check if there is a block at this slot if let Some((block_id, block_metadata)) = exec_target { @@ -1362,9 +1507,6 @@ impl ExecutionState { .same_thread_parent_creator .expect("same thread parent creator missing"); - // Set remaining block gas - let mut remaining_block_gas = self.config.max_gas_per_block; - // Block credits count every operation fee, denunciation slash and endorsement reward. // We initialize the block credits with the block reward to stimulate block production // even in the absence of operations and denunciations. @@ -1584,6 +1726,41 @@ impl ExecutionState { context_guard!(self).update_production_stats(&producer_addr, *slot, None); } + // Get asynchronous messages to execute + // The gas available for async messages is the remaining block gas + async remaining gas (max_async - gas used by deferred calls) + let async_msg_gas_available = self + .config + .max_async_gas + .saturating_sub(calls.effective_slot_gas) + .saturating_add(remaining_block_gas); + let messages = context_guard!(self) + .take_async_batch(async_msg_gas_available, self.config.async_msg_cst_gas_cost); + + // Try executing asynchronous messages. + // Effects are cancelled on failure and the sender is reimbursed. + for (_message_id, message) in messages { + let opt_bytecode = context_guard!(self).get_bytecode(&message.destination); + match self.execute_async_message(message, opt_bytecode) { + Ok(_message_return) => { + cfg_if::cfg_if! { + if #[cfg(feature = "execution-trace")] { + // Safe to unwrap + slot_trace.asc_call_stacks.push(_message_return.traces.unwrap().0); + } else if #[cfg(feature = "execution-info")] { + slot_trace.asc_call_stacks.push(_message_return.traces.clone().unwrap().0); + exec_info.async_messages.push(Ok(_message_return)); + } + } + } + Err(err) => { + let msg = format!("failed executing async message: {}", err); + #[cfg(feature = "execution-info")] + exec_info.async_messages.push(Err(msg.clone())); + debug!(msg); + } + } + } + #[cfg(feature = "execution-trace")] self.trace_history .write() @@ -2308,4 +2485,37 @@ impl ExecutionState { .map(|i| (i.current_version, i.announced_version)), ); } + + pub fn deferred_call_quote( + &self, + target_slot: Slot, + max_request_gas: u64, + params_size: u64, + ) -> (Slot, u64, bool, Amount) { + let gas_request = + max_request_gas.saturating_add(self.config.deferred_calls_config.call_cst_gas_cost); + let context = context_guard!(self); + + match context.deferred_calls_compute_call_fee( + target_slot, + gas_request, + context.slot, + params_size, + ) { + Ok(fee) => (target_slot, gas_request, true, fee), + Err(_) => (target_slot, gas_request, false, Amount::zero()), + } + } + + pub fn deferred_call_info(&self, call_id: &DeferredCallId) -> Option { + let context = context_guard!(self); + context.get_deferred_call(call_id) + } + + pub fn get_deferred_calls_by_slot(&self, slot: Slot) -> Vec { + context_guard!(self) + .get_deferred_calls_by_slot(slot) + .into_keys() + .collect() + } } diff --git a/massa-execution-worker/src/execution_info.rs b/massa-execution-worker/src/execution_info.rs index aaac0da631d..35994b25a68 100644 --- a/massa-execution-worker/src/execution_info.rs +++ b/massa-execution-worker/src/execution_info.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; +use massa_deferred_calls::DeferredCall; use schnellru::{ByLength, LruMap}; // use massa_execution_exports::Transfer; @@ -40,6 +41,7 @@ pub struct ExecutionInfoForSlot { pub(crate) denunciations: Vec>, pub(crate) operations: Vec, pub(crate) async_messages: Vec>, + pub(crate) deferred_calls_messages: Vec>, /// Deferred credits execution (empty if execution-info feature is NOT enabled) pub deferred_credits_execution: Vec<(Address, Result)>, /// Cancel async message execution (empty if execution-info feature is NOT enabled) @@ -57,6 +59,7 @@ impl ExecutionInfoForSlot { denunciations: Default::default(), operations: Default::default(), async_messages: Default::default(), + deferred_calls_messages: Default::default(), deferred_credits_execution: vec![], cancel_async_message_execution: vec![], auto_sell_execution: vec![], @@ -94,3 +97,25 @@ impl AsyncMessageExecutionResult { } } } + +pub struct DeferredCallExecutionResult { + pub(crate) success: bool, + pub(crate) sender: Address, + pub(crate) target_address: Address, + pub(crate) target_function: String, + pub(crate) coins: Amount, + pub(crate) traces: Option, +} + +impl DeferredCallExecutionResult { + pub fn new(call: &DeferredCall) -> Self { + Self { + success: false, + sender: call.sender_address, + target_address: call.target_address, + target_function: call.target_function.clone(), + coins: call.coins, + traces: None, + } + } +} diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 127c0da9189..07e106bee0b 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -8,10 +8,12 @@ use crate::context::ExecutionContext; use anyhow::{anyhow, bail, Result}; use massa_async_pool::{AsyncMessage, AsyncMessageTrigger}; +use massa_deferred_calls::DeferredCall; use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; use massa_models::bytecode::Bytecode; use massa_models::datastore::get_prefix_bounds; +use massa_models::deferred_calls::DeferredCallId; use massa_models::{ address::{Address, SCAddress, UserAddress}, amount::Amount, @@ -93,8 +95,9 @@ impl InterfaceImpl { use massa_db_exports::{MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; use massa_final_state::test_exports::get_sample_state; - use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete}; + use massa_ledger_exports::LedgerEntry; use massa_models::config::{MIP_STORE_STATS_BLOCK_CONSIDERED, THREAD_COUNT}; + use massa_models::types::SetUpdateOrDelete; use massa_module_cache::{config::ModuleCacheConfig, controller::ModuleCache}; use massa_pos_exports::SelectorConfig; use massa_pos_worker::start_selector_worker; @@ -1447,6 +1450,147 @@ impl Interface for InterfaceImpl { Ok(blake3::hash(bytes).into()) } + /// Get the number of fees needed to reserve space in the target slot + /// + /// # Arguments + /// * target_slot: tuple containing the period and thread of the target slot + /// * gas_limit: the gas limit for the call + /// + /// # Returns + /// A tuple containing a boolean indicating if the call is possible and the amount of fees needed + fn get_deferred_call_quote( + &self, + target_slot: (u64, u8), + gas_limit: u64, + params_size: u64, + ) -> Result<(bool, u64)> { + // write-lock context + + let context = context_guard!(self); + + let current_slot = context.slot; + + let target_slot = Slot::new(target_slot.0, target_slot.1); + + let gas_request = + gas_limit.saturating_add(self.config.deferred_calls_config.call_cst_gas_cost); + + match context.deferred_calls_compute_call_fee( + target_slot, + gas_request, + current_slot, + params_size, + ) { + Ok(fee) => Ok((true, fee.to_raw())), + Err(_) => Ok((false, 0)), + } + } + + /// Register deferred call + /// + /// # Arguments + /// * target_addr: string representation of the target address + /// * target_func: string representation of the target function + /// * target_slot: tuple containing the period and thread of the target slot + /// * max_gas: the gas limit for the call + /// * coins: the amount of coins to send + /// * params: byte array of the parameters + /// + /// # Returns + /// The id of the call + fn deferred_call_register( + &self, + target_addr: &str, + target_func: &str, + target_slot: (u64, u8), + max_gas: u64, + params: &[u8], + coins: u64, + ) -> Result { + // This function spends coins + deferred_call_quote(target_slot, max_gas).unwrap() from the caller, fails if the balance is insufficient or if the quote would return None. + + let target_addr = Address::from_str(target_addr)?; + + // check that the target address is an SC address + if !matches!(target_addr, Address::SC(..)) { + bail!("target address is not a smart contract address") + } + + // Length verifications + if target_func.len() > self.config.max_function_length as usize { + bail!("Function name is too large"); + } + if params.len() > self.config.max_parameter_length as usize { + bail!("Parameter size is too large"); + } + + // check fee, slot, gas + let (available, fee_raw) = + self.get_deferred_call_quote(target_slot, max_gas, params.len() as u64)?; + if !available { + bail!("The Deferred call cannot be registered. Ensure that the target slot is not before/at the current slot nor too far in the future, and that it has at least max_gas available gas."); + } + let fee = Amount::from_raw(fee_raw); + let coins = Amount::from_raw(coins); + + // write-lock context + let mut context = context_guard!(self); + + // get caller address + let sender_address = context.get_current_address()?; + + // make sender pay coins + fee + // coins + cost for booking the deferred call + context.transfer_coins(Some(sender_address), None, coins.saturating_add(fee), true)?; + + let call = DeferredCall::new( + sender_address, + Slot::new(target_slot.0, target_slot.1), + target_addr, + target_func.to_string(), + params.to_vec(), + coins, + max_gas, + fee, + false, + ); + + let call_id = context.deferred_call_register(call)?; + Ok(call_id.to_string()) + } + + /// Check if an deferred call exists + /// + /// # Arguments + /// * id: the id of the call + /// + /// # Returns + /// true if the call exists, false otherwise + fn deferred_call_exists(&self, id: &str) -> Result { + // write-lock context + let call_id = DeferredCallId::from_str(id)?; + let context = context_guard!(self); + Ok(context.deferred_call_exists(&call_id)) + } + + /// Cancel a deferred call + /// + /// # Arguments + /// * id: the id of the call + fn deferred_call_cancel(&self, id: &str) -> Result<()> { + // Reimburses coins to the sender but not the deferred call fee to avoid spam. Cancelled items are not removed from storage to avoid manipulation, just ignored when it is their turn to be executed. + + let mut context = context_guard!(self); + + // Can only be called by the creator of the deferred call. + let caller = context.get_current_address()?; + + let call_id = DeferredCallId::from_str(id)?; + + context.deferred_call_cancel(&call_id, caller)?; + Ok(()) + } + #[allow(unused_variables)] fn init_call_wasmv1(&self, address: &str, raw_coins: NativeAmount) -> Result> { // get target address diff --git a/massa-execution-worker/src/lib.rs b/massa-execution-worker/src/lib.rs index 66515da3101..e8c2264b4fa 100644 --- a/massa-execution-worker/src/lib.rs +++ b/massa-execution-worker/src/lib.rs @@ -87,6 +87,7 @@ mod interface_impl; mod request_queue; mod slot_sequencer; mod speculative_async_pool; +mod speculative_deferred_calls; mod speculative_executed_denunciations; mod speculative_executed_ops; mod speculative_ledger; diff --git a/massa-execution-worker/src/speculative_async_pool.rs b/massa-execution-worker/src/speculative_async_pool.rs index 082ed2fb362..816bd7fcb3a 100644 --- a/massa-execution-worker/src/speculative_async_pool.rs +++ b/massa-execution-worker/src/speculative_async_pool.rs @@ -9,8 +9,9 @@ use massa_async_pool::{ AsyncPoolChanges, }; use massa_final_state::FinalStateController; -use massa_ledger_exports::{Applicable, LedgerChanges, SetUpdateOrDelete}; +use massa_ledger_exports::LedgerChanges; use massa_models::slot::Slot; +use massa_models::types::{Applicable, SetUpdateOrDelete}; use parking_lot::RwLock; use std::{ collections::{BTreeMap, HashMap}, diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs new file mode 100644 index 00000000000..7bcb3b1bfcb --- /dev/null +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -0,0 +1,727 @@ +//! Speculative async call registry. + +use crate::active_history::ActiveHistory; +use massa_deferred_calls::{ + config::DeferredCallsConfig, registry_changes::DeferredCallRegistryChanges, DeferredCall, + DeferredSlotCalls, +}; +use massa_execution_exports::ExecutionError; +use massa_final_state::FinalStateController; +use massa_models::{ + address::Address, amount::Amount, config::MAX_ASYNC_GAS, deferred_calls::DeferredCallId, + slot::Slot, +}; +use parking_lot::RwLock; +use std::{ + cmp::{max, min}, + sync::Arc, +}; + +const TARGET_BOOKING: u128 = (MAX_ASYNC_GAS / 2) as u128; + +pub(crate) struct SpeculativeDeferredCallRegistry { + final_state: Arc>, + active_history: Arc>, + // current speculative registry changes + deferred_calls_changes: DeferredCallRegistryChanges, + config: DeferredCallsConfig, +} + +impl SpeculativeDeferredCallRegistry { + /// Creates a new `SpeculativeDeferredCallRegistry` + /// + /// # Arguments + pub fn new( + final_state: Arc>, + active_history: Arc>, + config: DeferredCallsConfig, + ) -> Self { + SpeculativeDeferredCallRegistry { + final_state, + active_history, + deferred_calls_changes: Default::default(), + config, + } + } + + /// Takes a snapshot (clone) of the message states + pub fn get_snapshot(&self) -> DeferredCallRegistryChanges { + self.deferred_calls_changes.clone() + } + + /// Resets the `SpeculativeDeferredCallRegistry` to a snapshot (see `get_snapshot` method) + pub fn reset_to_snapshot(&mut self, snapshot: DeferredCallRegistryChanges) { + self.deferred_calls_changes = snapshot; + } + + /// Add a new call to the list of changes of this `SpeculativeDeferredCallRegistry` + pub fn push_new_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.deferred_calls_changes.set_call(id, call); + } + + pub fn get_total_calls_registered(&self) -> u64 { + if let Some(v) = self.deferred_calls_changes.get_total_calls_registered() { + return v; + } + + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_total_calls_registered() + { + return v; + } + } + } + + return self + .final_state + .read() + .get_deferred_call_registry() + .get_nb_call_registered(); + } + + pub fn get_effective_total_gas(&self) -> u128 { + // get total gas from current changes + if let Some(v) = self.deferred_calls_changes.get_effective_total_gas() { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_effective_total_gas() + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_deferred_call_registry() + .get_total_gas(); + } + + pub fn get_effective_slot_gas(&self, slot: &Slot) -> u64 { + // get slot gas from current changes + if let Some(v) = self.deferred_calls_changes.get_effective_slot_gas(slot) { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_effective_slot_gas(slot) + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_gas(slot); + } + + pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { + // get slot base fee from current changes + if let Some(v) = self.deferred_calls_changes.get_slot_base_fee(slot) { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_slot_base_fee(slot) + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_base_fee(slot); + } + + /// Consumes and deletes the current slot, prepares a new slot in the future + /// and returns the calls that need to be executed in the current slot + pub fn advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { + // get the state of the current slot + let mut slot_calls = self.get_calls_by_slot(current_slot); + let total_booked_gas_before = self.get_effective_total_gas(); + + // get the previous average booking rate per slot + let avg_booked_gas = + total_booked_gas_before.saturating_div(self.config.max_future_slots as u128); + // select the slot that is newly made available and set its base fee + let new_slot = current_slot + .skip(self.config.max_future_slots, self.config.thread_count) + .expect("could not skip enough slots"); + + let prev_slot = new_slot + .get_prev_slot(self.config.thread_count) + .expect("cannot get prev slot"); + + let prev_slot_base_fee = { + let temp_slot_fee = self.get_slot_base_fee(&prev_slot); + if temp_slot_fee.eq(&Amount::zero()) { + Amount::from_raw(self.config.min_gas_cost) + } else { + temp_slot_fee + } + }; + + let new_slot_base_fee = match avg_booked_gas.cmp(&TARGET_BOOKING) { + // the previous booking rate was exactly the expected one: do not adjust the base fee + std::cmp::Ordering::Equal => prev_slot_base_fee, + // more gas was booked than expected: increase the base fee + std::cmp::Ordering::Greater => { + let gas_used_delta = avg_booked_gas.saturating_sub(TARGET_BOOKING) as u64; + + let raw_v = prev_slot_base_fee.to_raw().saturating_add(max( + gas_used_delta + .saturating_div(self.config.base_fee_max_max_change_denominator as u64), + self.config.min_gas_increment, + )); + + Amount::from_raw(min(1_000_000_000, raw_v)) + } + // less gas was booked than expected: decrease the base fee + std::cmp::Ordering::Less => { + let gas_used_delta = TARGET_BOOKING.saturating_sub(avg_booked_gas) as u64; + + let raw_v = max( + prev_slot_base_fee + .to_raw() + .saturating_sub(gas_used_delta.saturating_div( + self.config.base_fee_max_max_change_denominator as u64, + )), + self.config.min_gas_cost, + ); + + Amount::from_raw(min(1_000_000_000, raw_v)) + } + }; + + self.deferred_calls_changes + .set_slot_base_fee(new_slot, new_slot_base_fee); + + // subtract the current slot gas from the total gas + // cancelled call gas is already decremented from the effective slot gas + let total_gas_after = + total_booked_gas_before.saturating_sub(slot_calls.effective_slot_gas.into()); + if !total_gas_after.eq(&total_booked_gas_before) { + self.deferred_calls_changes + .set_effective_total_gas(total_gas_after); + } + + slot_calls.effective_total_gas = total_gas_after; + + massa_metrics::set_deferred_calls_total_gas(slot_calls.effective_total_gas); + + // delete call in the current slot + let mut nb_call_to_execute = 0; + for (id, call) in &slot_calls.slot_calls { + // cancelled call is already decremented from the total calls registered + if !call.cancelled { + nb_call_to_execute += 1; + } + self.delete_call(id, current_slot); + } + + if nb_call_to_execute > 0 { + let total_calls_registered = self.get_total_calls_registered(); + let new_call_registered = total_calls_registered.saturating_sub(nb_call_to_execute); + self.set_total_calls_registered(new_call_registered); + } + + slot_calls + } + + pub fn get_calls_by_slot(&self, slot: Slot) -> DeferredSlotCalls { + let mut slot_calls: DeferredSlotCalls = self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_calls(slot); + for hist_item in self.active_history.read().0.iter() { + slot_calls.apply_changes(&hist_item.state_changes.deferred_call_changes); + } + slot_calls.apply_changes(&self.deferred_calls_changes); + slot_calls + } + + pub fn get_call(&self, id: &DeferredCallId) -> Option { + let slot = match id.get_slot() { + Ok(slot) => slot, + Err(_) => return None, + }; + + // check from latest to earliest changes + + // check in current changes + if let Some(v) = self.deferred_calls_changes.get_call(&slot, id) { + return Some(v.clone()); + } + + // check history from the most recent to the oldest item + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_call(&slot, id) + { + return Some(v.clone()); + } + } + } + + // check final state + { + let final_state = self.final_state.read(); + // if let Some(v) = final_state.get_deferred_call_registry().get_call(&slot, id) { + if let Some(v) = final_state.get_deferred_call_registry().get_call(&slot, id) { + return Some(v.clone()); + } + } + + None + } + + pub fn delete_call(&mut self, id: &DeferredCallId, slot: Slot) { + self.deferred_calls_changes.delete_call(slot, id) + } + + /// Cancel a call + /// Returns the sender address and the amount of coins to reimburse them + pub fn cancel_call( + &mut self, + id: &DeferredCallId, + ) -> Result<(Address, Amount), ExecutionError> { + // get call, fail if it does not exist + let Some(mut call) = self.get_call(id) else { + return Err(ExecutionError::DeferredCallsError( + "Call ID does not exist.".into(), + )); + }; + + // check if the call is already cancelled + if call.cancelled { + return Err(ExecutionError::DeferredCallsError( + "Call ID is already cancelled.".into(), + )); + } + + // set call as cancelled + call.cancelled = true; + + // we need to reimburse coins to the sender + let res: (Address, Amount) = (call.sender_address, call.coins); + + // Add a cancellation to the current changes + self.deferred_calls_changes + .set_call(id.clone(), call.clone()); + + let current_gas = self.get_effective_slot_gas(&call.target_slot); + + // set slot gas + // slot_gas = current_gas - (call_gas + call_cst_gas_cost (vm allocation cost)) + self.deferred_calls_changes.set_effective_slot_gas( + call.target_slot, + current_gas.saturating_sub(call.get_effective_gas(self.config.call_cst_gas_cost)), + ); + + let effective_gas_call = call.get_effective_gas(self.config.call_cst_gas_cost) as u128; + // set total gas + self.deferred_calls_changes.set_effective_total_gas( + self.get_effective_total_gas() + .saturating_sub(effective_gas_call), + ); + + let new_total_calls_registered = self.get_total_calls_registered().saturating_sub(1); + self.set_total_calls_registered(new_total_calls_registered); + + Ok(res) + } + + // This function assumes that we have a resource with a total supply `resource_supply`. + // Below a certain target occupancy `target_occupancy` of that resource, the overbooking penalty for using a unit of the resource is zero. + // Above the target, the resource unit cost grows linearly with occupancy. + // The linear fee growth is chosen so that if someone occupies all the resource, they incur a `max_penalty` cost. + fn overbooking_fee( + resource_supply: u128, + target_occupancy: u128, + current_occupancy: u128, + resource_request: u128, + max_penalty: Amount, + ) -> Result { + // linear part of the occupancy before booking the requested amount + let relu_occupancy_before = current_occupancy.saturating_sub(target_occupancy); + + // linear part of the occupancy after booking the requested amount + let relu_occupancy_after = std::cmp::max( + current_occupancy.saturating_add(resource_request), + target_occupancy, + ) + .saturating_sub(target_occupancy); + + // denominator for the linear fee + let denominator = resource_supply.checked_sub(target_occupancy).ok_or( + ExecutionError::DeferredCallsError("Error with denominator on overbooking fee".into()), + )?; + + if denominator.eq(&0) { + // TODO : check if this is correct + return Err(ExecutionError::DeferredCallsError( + "Denominator is zero on overbooking fee".into(), + )); + } + + // compute using the raw fee and u128 to avoid u64 overflows + let raw_max_penalty = max_penalty.to_raw() as u128; + + let raw_fee = (raw_max_penalty.saturating_mul( + (relu_occupancy_after.saturating_mul(relu_occupancy_after)) + .saturating_sub(relu_occupancy_before.saturating_mul(relu_occupancy_before)), + )) + .saturating_div(denominator.saturating_mul(denominator)); + + Ok(Amount::from_raw(min(raw_fee, u64::MAX as u128) as u64)) + } + + /// Compute call fee + pub fn compute_call_fee( + &self, + target_slot: Slot, + max_gas_request: u64, + current_slot: Slot, + params_size: u64, + ) -> Result { + // Check that the slot is not in the past + if target_slot <= current_slot { + return Err(ExecutionError::DeferredCallsError( + "Target slot is in the past.".into(), + )); + } + + // Check that the slot is not in the future + if target_slot + .slots_since(¤t_slot, self.config.thread_count) + .unwrap_or(u64::MAX) + > self.config.max_future_slots + { + // note: the current slot is not counted + return Err(ExecutionError::DeferredCallsError( + "Target slot is too far in the future.".into(), + )); + } + + // Check that the gas is not too high for the target slot + let slot_occupancy = self.get_effective_slot_gas(&target_slot); + if slot_occupancy.saturating_add(max_gas_request) > self.config.max_gas { + return Err(ExecutionError::DeferredCallsError( + "Not enough gas available in the target slot.".into(), + )); + } + + if params_size > self.config.max_parameter_size.into() { + return Err(ExecutionError::DeferredCallsError( + "Parameters size is too big.".into(), + )); + } + + // We perform Dynamic Pricing of slot gas booking using a Proportional-Integral controller (https://en.wikipedia.org/wiki/Proportional–integral–derivative_controller). + // It regulates the average slot async gas usage towards `target_async_gas` by adjusting fees. + + // Constant part of the fee: directly depends on the base async gas cost for the target slot. + // This is the "Integral" part of the Proportional-Integral controller. + // When a new slot `S` is made available for booking, the `S.base_async_gas_cost` is increased or decreased compared to `(S-1).base_async_gas_cost` depending on the average gas usage over the `deferred_call_max_future_slots` slots before `S`. + + // Integral fee + let integral_fee = self + .get_slot_base_fee(&target_slot) + .saturating_mul_u64(max_gas_request); + + // The integral fee is not enough to respond to quick demand surges within the long booking period `deferred_call_max_future_slots`. Proportional regulation is also necessary. + + // A fee that linearly depends on the total load over `deferred_call_max_future_slots` slots but only when the average load is above `target_async_gas` to not penalize normal use. Booking all the gas from all slots within the booking period requires using the whole initial coin supply. + + // Global overbooking fee + let global_occupancy = self.get_effective_total_gas(); + let global_overbooking_fee = Self::overbooking_fee( + (self.config.max_gas as u128).saturating_mul(self.config.max_future_slots as u128), // total available async gas during the booking period + (self.config.max_future_slots as u128).saturating_mul(TARGET_BOOKING), // target a 50% async gas usage over the booking period + global_occupancy, // total amount of async gas currently booked in the booking period + max_gas_request as u128, // amount of gas to book + self.config.global_overbooking_penalty, // fully booking all slots of the booking period requires spending the whole initial supply of coins + )?; + + // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. + // Slot overbooking fee + let slot_overbooking_fee = Self::overbooking_fee( + self.config.max_gas as u128, // total available async gas during the target slot + TARGET_BOOKING, // target a 50% async gas usage during the target slot + slot_occupancy as u128, // total amount of async gas currently booked in the target slot + max_gas_request as u128, // amount of gas to book in the target slot + self.config.slot_overbooking_penalty, // total_initial_coin_supply/10000 + )?; + + // Storage cost for the parameters + let storage_cost = DeferredCall::get_storage_cost( + self.config.ledger_cost_per_byte, + params_size, + self.config.max_function_name_length, + ); + + // return the fee + Ok(integral_fee + .saturating_add(global_overbooking_fee) + .saturating_add(slot_overbooking_fee) + .saturating_add(storage_cost)) + } + + /// Register a new call + /// Returns the call id + /// # Arguments + /// * `call` - The call to register + /// * `trail_hash` - The hash of the execution trail hash + pub fn register_call( + &mut self, + call: DeferredCall, + trail_hash: massa_hash::Hash, + ) -> Result { + let mut index = 0; + + if let Some(val) = self + .deferred_calls_changes + .slots_change + .get(&call.target_slot) + { + index += val.calls_len(); + } + + { + // final state + let slots_call = self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_calls(call.target_slot); + index += slots_call.slot_calls.len(); + } + + let id = DeferredCallId::new(0, call.target_slot, index as u64, trail_hash.to_bytes())?; + + self.push_new_call(id.clone(), call.clone()); + + let current_gas = self.get_effective_slot_gas(&call.target_slot); + + // set slot gas for the target slot + // effective_slot_gas = current_gas + (call_gas + call_cst_gas_cost (vm allocation cost)) + self.deferred_calls_changes.set_effective_slot_gas( + call.target_slot, + current_gas.saturating_add(call.get_effective_gas(self.config.call_cst_gas_cost)), + ); + + // set total effective gas + let effective_total_gas = self.get_effective_total_gas(); + let call_effective_gas = call.get_effective_gas(self.config.call_cst_gas_cost) as u128; + self.deferred_calls_changes + .set_effective_total_gas(effective_total_gas.saturating_add(call_effective_gas)); + + // increment total calls registered + let new_total_calls_registered = self.get_total_calls_registered().saturating_add(1); + self.set_total_calls_registered(new_total_calls_registered); + + Ok(id) + } + + /// Take the deferred registry slot changes + pub(crate) fn take(&mut self) -> DeferredCallRegistryChanges { + std::mem::take(&mut self.deferred_calls_changes) + } + + fn set_total_calls_registered(&mut self, nb_calls: u64) { + massa_metrics::set_deferred_calls_registered(nb_calls as usize); + self.deferred_calls_changes + .set_total_calls_registered(nb_calls); + } +} + +#[cfg(test)] +mod tests { + use std::{str::FromStr, sync::Arc}; + + use massa_db_exports::{MassaDBConfig, MassaDBController}; + use massa_db_worker::MassaDB; + use massa_deferred_calls::{config::DeferredCallsConfig, DeferredCallRegistry}; + use massa_final_state::MockFinalStateController; + use massa_models::{amount::Amount, config::THREAD_COUNT, slot::Slot}; + use parking_lot::RwLock; + use tempfile::TempDir; + + use super::SpeculativeDeferredCallRegistry; + + #[test] + fn test_compute_call_fee() { + let disk_ledger = TempDir::new().expect("cannot create temp directory"); + let db_config = MassaDBConfig { + path: disk_ledger.path().to_path_buf(), + max_history_length: 10, + max_final_state_elements_size: 100_000, + max_versioning_elements_size: 100_000, + thread_count: THREAD_COUNT, + max_ledger_backups: 10, + }; + + let db = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> + )); + let mock_final_state = Arc::new(RwLock::new(MockFinalStateController::new())); + + let deferred_call_registry = + DeferredCallRegistry::new(db.clone(), DeferredCallsConfig::default()); + + mock_final_state + .write() + .expect_get_deferred_call_registry() + .return_const(deferred_call_registry); + let config = DeferredCallsConfig::default(); + + let mut speculative = SpeculativeDeferredCallRegistry::new( + mock_final_state, + Arc::new(Default::default()), + config, + ); + + let max_period = config.max_future_slots / THREAD_COUNT as u64; + + let slot_too_far = Slot { + period: max_period + 2, + thread: 1, + }; + + let good_slot = Slot { + period: 10, + thread: 1, + }; + + // slot to far in the future + assert!(speculative + .compute_call_fee( + slot_too_far, + 1_000_000, + Slot { + period: 1, + thread: 1, + }, + 1_000 + ) + .is_err()); + + // slot is in the past + assert!(speculative + .compute_call_fee( + Slot { + period: 2, + thread: 1, + }, + 1_000_000, + Slot { + period: 5, + thread: 1, + }, + 1000 + ) + .is_err()); + + // gas too high + speculative + .deferred_calls_changes + .set_effective_slot_gas(good_slot, 999_000_000); + + assert!(speculative + .compute_call_fee( + good_slot, + 1_100_000, + Slot { + period: 1, + thread: 1, + }, + 1000 + ) + .is_err()); + + // params too big + assert!(speculative + .compute_call_fee( + good_slot, + 1_000_000, + Slot { + period: 1, + thread: 1, + }, + 50_000_000 + ) + .is_err()); + + // no params + assert_eq!( + speculative + .compute_call_fee( + good_slot, + 200_000, + Slot { + period: 1, + thread: 1, + }, + 0, + ) + .unwrap(), + Amount::from_str("0.036600079").unwrap() + ); + + // 10Ko params size + assert_eq!( + speculative + .compute_call_fee( + good_slot, + 200_000, + Slot { + period: 1, + thread: 1, + }, + 10_000, + ) + .unwrap(), + Amount::from_str("1.036600079").unwrap() + ); + } +} diff --git a/massa-execution-worker/src/speculative_ledger.rs b/massa-execution-worker/src/speculative_ledger.rs index 238d3128321..654219da8c1 100644 --- a/massa-execution-worker/src/speculative_ledger.rs +++ b/massa-execution-worker/src/speculative_ledger.rs @@ -9,9 +9,10 @@ use crate::active_history::{ActiveHistory, HistorySearchResult}; use massa_execution_exports::ExecutionError; use massa_execution_exports::StorageCostsConstants; use massa_final_state::FinalStateController; -use massa_ledger_exports::{Applicable, LedgerChanges, SetOrDelete, SetUpdateOrDelete}; +use massa_ledger_exports::LedgerChanges; use massa_models::bytecode::Bytecode; use massa_models::datastore::get_prefix_bounds; +use massa_models::types::{Applicable, SetOrDelete, SetUpdateOrDelete}; use massa_models::{address::Address, amount::Amount}; use parking_lot::RwLock; use std::cmp::Ordering; diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 67dce6469d1..e26e387a47b 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -2,6 +2,10 @@ use massa_async_pool::{AsyncMessage, AsyncPool, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, ShareableMassaDBController}; +use massa_deferred_calls::config::DeferredCallsConfig; +use massa_deferred_calls::registry_changes::DeferredCallRegistryChanges; +use massa_deferred_calls::slot_changes::DeferredRegistrySlotChanges; +use massa_deferred_calls::{DeferredCall, DeferredCallRegistry}; use massa_executed_ops::{ExecutedDenunciations, ExecutedDenunciationsConfig}; use massa_execution_exports::{ ExecutionConfig, ExecutionQueryRequest, ExecutionQueryRequestItem, ExecutionStackElement, @@ -10,15 +14,15 @@ use massa_execution_exports::{ use massa_final_state::test_exports::get_initials; use massa_final_state::MockFinalStateController; use massa_hash::Hash; -use massa_ledger_exports::{ - LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrKeep, SetUpdateOrDelete, -}; +use massa_ledger_exports::{LedgerEntryUpdate, MockLedgerControllerWrapper}; use massa_models::bytecode::Bytecode; use massa_models::config::{ CHAINID, ENDORSEMENT_COUNT, GENESIS_KEY, LEDGER_ENTRY_DATASTORE_BASE_SIZE, THREAD_COUNT, }; +use massa_models::deferred_calls::DeferredCallId; use massa_models::prehash::PreHashMap; use massa_models::test_exports::gen_endorsements_for_denunciation; +use massa_models::types::{SetOrDelete, SetOrKeep, SetUpdateOrDelete}; use massa_models::{address::Address, amount::Amount, slot::Slot}; use massa_models::{ denunciation::Denunciation, @@ -60,6 +64,7 @@ const TEST_SK_2: &str = "S1FpYC4ugG9ivZZbLVrTwWtF9diSRiAwwrVX5Gx1ANSRLfouUjq"; const TEST_SK_3: &str = "S1LgXhWLEgAgCX3nm6y8PVPzpybmsYpi6yg6ZySwu5Z4ERnD7Bu"; const BLOCK_CREDIT_PART_COUNT: u64 = 3 * (1 + ENDORSEMENT_COUNT as u64); +#[allow(clippy::too_many_arguments)] fn final_state_boilerplate( mock_final_state: &mut Arc>, db: ShareableMassaDBController, @@ -68,6 +73,7 @@ fn final_state_boilerplate( saved_bytecode: Option>>>, custom_async_pool: Option, custom_pos_state: Option, + custom_deferred_call_registry: Option, ) { mock_final_state .write() @@ -141,6 +147,14 @@ fn final_state_boilerplate( }, db.clone(), )); + + let deferred_call_registry = custom_deferred_call_registry + .unwrap_or_else(|| DeferredCallRegistry::new(db.clone(), DeferredCallsConfig::default())); + + mock_final_state + .write() + .expect_get_deferred_call_registry() + .return_const(deferred_call_registry); } fn expect_finalize_deploy_and_call_blocks( @@ -208,6 +222,7 @@ fn test_execution_shutdown() { None, None, None, + None, ); ExecutionTestUniverse::new(foreign_controllers, ExecutionConfig::default()); } @@ -224,6 +239,7 @@ fn test_sending_command() { None, None, None, + None, ); let universe = ExecutionTestUniverse::new(foreign_controllers, ExecutionConfig::default()); universe.module_controller.update_blockclique_status( @@ -269,6 +285,7 @@ fn test_readonly_execution() { None, None, None, + None, ); let universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -297,8 +314,8 @@ fn test_readonly_execution() { assert_eq!( res.out.state_changes.ledger_changes.0.get(&addr).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(Amount::from_str("60").unwrap()), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: massa_models::types::SetOrKeep::Set(Amount::from_str("60").unwrap()), + bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) ); @@ -343,8 +360,8 @@ fn test_readonly_execution() { assert_eq!( res2.out.state_changes.ledger_changes.0.get(&addr).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(Amount::from_str("50").unwrap()), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: massa_models::types::SetOrKeep::Set(Amount::from_str("50").unwrap()), + bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) ); @@ -397,6 +414,7 @@ fn test_nested_call_gas_usage() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -496,6 +514,7 @@ fn test_nested_call_recursion_limit_reached() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -586,6 +605,7 @@ fn test_nested_call_recursion_limit_not_reached() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -676,6 +696,7 @@ fn test_get_call_coins() { Some(saved_bytecode), None, None, + None, ); foreign_controllers .final_state @@ -846,7 +867,7 @@ fn send_and_receive_async_message() { println!("changes: {:?}", changes.async_pool_changes.0); assert_eq!( changes.async_pool_changes.0.first_key_value().unwrap().1, - &massa_ledger_exports::SetUpdateOrDelete::Set(message_cloned.clone()) + &massa_models::types::SetUpdateOrDelete::Set(message_cloned.clone()) ); assert_eq!( changes.async_pool_changes.0.first_key_value().unwrap().0, @@ -895,7 +916,7 @@ fn send_and_receive_async_message() { }, 0, ), - massa_ledger_exports::SetUpdateOrDelete::Set(message), + massa_models::types::SetUpdateOrDelete::Set(message), ); let mut db_batch = DBBatch::default(); async_pool.apply_changes_to_batch(&AsyncPoolChanges(changes), &mut db_batch); @@ -911,6 +932,7 @@ fn send_and_receive_async_message() { Some(saved_bytecode), Some(async_pool), None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1003,6 +1025,7 @@ fn send_and_receive_async_message_expired() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1091,6 +1114,7 @@ fn send_and_receive_async_message_expired_2() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1155,10 +1179,903 @@ fn send_and_receive_async_message_without_init_gas() { .expect_entry_exists() .returning(move |_| true); }); - let saved_bytecode = Arc::new(RwLock::new(None)); - let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + let saved_bytecode = Arc::new(RwLock::new(None)); + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + + // Expected message from SC: send_message.ts (see massa unit tests src repo) + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + assert_eq!( + changes.async_pool_changes, + AsyncPoolChanges(BTreeMap::new()) + ); + finalized_waitpoint_trigger_handle.trigger(); + }); + + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + None, + ); + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); + + // load bytecodes + universe.deploy_bytecode_block( + &KeyPair::from_str(TEST_SK_1).unwrap(), + Slot::new(1, 0), + include_bytes!("./wasm/send_message.wasm"), + include_bytes!("./wasm/receive_message.wasm"), + ); + println!("waiting for finalized"); + finalized_waitpoint.wait(); + + // retrieve events emitted by smart contracts + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + start: Some(Slot::new(1, 0)), + end: Some(Slot::new(1, 1)), + ..Default::default() + }); + // match the events + assert!(events.len() == 1, "One event was expected"); + assert!(events[0] + .data + .contains("max gas is lower than the minimum instance cost")); +} + +#[test] +fn cancel_async_message() { + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + selector_boilerplate(&mut foreign_controllers.selector_controller); + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + let saved_bytecode = Arc::new(RwLock::new(None)); + let saved_bytecode_edit = saved_bytecode.clone(); + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + let sender_addr = + Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi").unwrap(); + let message = AsyncMessage { + emission_slot: Slot { + period: 1, + thread: 0, + }, + emission_index: 0, + sender: sender_addr, + destination: Address::from_str("AU12mzL2UWroPV7zzHpwHnnF74op9Gtw7H55fAmXMnCuVZTFSjZCA") + .unwrap(), + function: String::from("receive"), + max_gas: 3000000, + fee: Amount::from_raw(1), + coins: Amount::from_raw(100), + validity_start: Slot { + period: 1, + thread: 1, + }, + validity_end: Slot { + period: 20, + thread: 20, + }, + function_params: vec![42, 42, 42, 42], + trigger: None, + can_be_executed: true, + }; + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + { + let mut saved_bytecode = saved_bytecode_edit.write(); + *saved_bytecode = Some(changes.ledger_changes.get_bytecode_updates()[0].clone()); + } + assert_eq!( + changes.ledger_changes.0.get(&sender_addr).unwrap(), + &SetUpdateOrDelete::Update(LedgerEntryUpdate { + balance: SetOrKeep::Set(Amount::from_str("90.298635211").unwrap()), + bytecode: massa_models::types::SetOrKeep::Keep, + datastore: BTreeMap::new() + }) + ); + + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + match changes.ledger_changes.0.get(&sender_addr).unwrap() { + // at slot (1,1) msg was canceled so sender has received the coins (0.0000001) + // sender has received the coins (0.0000001) + SetUpdateOrDelete::Update(change_sender_update) => { + assert_eq!( + change_sender_update.balance, + SetOrKeep::Set(Amount::from_str("100.0000001").unwrap()) + ); + } + _ => panic!("wrong change type"), + } + + match changes.async_pool_changes.0.first_key_value().unwrap().1 { + SetUpdateOrDelete::Delete => { + // msg was deleted + } + _ => panic!("wrong change type"), + } + + finalized_waitpoint_trigger_handle2.trigger(); + }); + + let mut async_pool = AsyncPool::new(AsyncPoolConfig::default(), foreign_controllers.db.clone()); + let mut changes = BTreeMap::default(); + changes.insert( + ( + Reverse(Ratio::new(1, 100000)), + Slot { + period: 1, + thread: 0, + }, + 0, + ), + massa_models::types::SetUpdateOrDelete::Set(message), + ); + let mut db_batch = DBBatch::default(); + async_pool.apply_changes_to_batch(&AsyncPoolChanges(changes), &mut db_batch); + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + Some(async_pool), + None, + None, + ); + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); + + // load bytecodes + universe.deploy_bytecode_block( + &KeyPair::from_str(TEST_SK_1).unwrap(), + Slot::new(1, 0), + include_bytes!("./wasm/send_message.wasm"), + include_bytes!("./wasm/receive_message.wasm"), + ); + finalized_waitpoint.wait(); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block, None); + finalized_waitpoint.wait(); + + // Sleep to wait (1,1) candidate slot to be executed. We don't have a mock to waitpoint on or empty block + std::thread::sleep(Duration::from_millis(exec_cfg.t0.as_millis())); + // retrieve events emitted by smart contracts + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + start: Some(Slot::new(1, 1)), + end: Some(Slot::new(20, 1)), + ..Default::default() + }); + assert!(events[0].data.contains(" is not a smart contract address")); +} + +#[test] +fn deferred_calls() { + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + selector_boilerplate(&mut foreign_controllers.selector_controller); + // TODO: add some context for this override + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + foreign_controllers + .ledger_controller + .set_expectations(|ledger_controller| { + ledger_controller + .expect_get_balance() + .returning(move |_| Some(Amount::from_str("100").unwrap())); + + ledger_controller + .expect_entry_exists() + .times(2) + .returning(move |_| false); + + ledger_controller + .expect_entry_exists() + .returning(move |_| true); + }); + let saved_bytecode = Arc::new(RwLock::new(None)); + let saved_bytecode_edit = saved_bytecode.clone(); + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + + let destination = match *CHAINID { + 77 => Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV").unwrap(), + 77658366 => { + Address::from_str("AS12DSPbsNvvdP1ScCivmKpbQfcJJ3tCQFkNb8ewkRuNjsgoL2AeQ").unwrap() + } + 77658377 => { + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap() + } + _ => panic!("CHAINID not supported"), + }; + + let target_slot = Slot { + period: 1, + thread: 1, + }; + + let call = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot, + target_address: destination, + target_function: "receive".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 2_300_000, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call2 = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot: Slot { + period: 8, + thread: 1, + }, + target_address: destination, + target_function: "tata".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 700_000, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call_id = + DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); + + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + { + let mut saved_bytecode = saved_bytecode_edit.write(); + *saved_bytecode = Some(changes.ledger_changes.get_bytecode_updates()[0].clone()); + } + + println!("changes: {:?}", changes.deferred_call_changes.slots_change); + assert_eq!(changes.deferred_call_changes.slots_change.len(), 1); + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + match changes.ledger_changes.0.get(&destination).unwrap() { + // sc has received the coins (0.0000001) + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("100.0000001").unwrap()) + ); + } + _ => panic!("wrong change type"), + } + + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + let (_slot, slot_change) = changes + .deferred_call_changes + .slots_change + .first_key_value() + .unwrap(); + + let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + // call was executed and then deleted + assert_eq!(set_delete, &SetOrDelete::Delete); + + // // total gas was set to 700_000 (call2.max_gas) + assert_eq!( + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(700_000) + ); + finalized_waitpoint_trigger_handle2.trigger(); + }); + + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas), + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + + let call_id2 = DeferredCallId::new( + 0, + Slot { + period: 8, + thread: 1, + }, + 0, + "trail_hash".to_string().as_bytes(), + ) + .unwrap(); + + let mut defer_reg_slot_changes2 = defer_reg_slot_changes.clone(); + defer_reg_slot_changes2.set_effective_slot_gas(call2.max_gas); + defer_reg_slot_changes2.set_call(call_id2, call2.clone()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert(target_slot, defer_reg_slot_changes); + + slot_changes.insert( + Slot { + period: 8, + thread: 1, + }, + defer_reg_slot_changes2, + ); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredCallRegistryChanges { + slots_change: slot_changes, + effective_total_gas: SetOrKeep::Set(call.max_gas.saturating_add(call2.max_gas).into()), + total_calls_registered: SetOrKeep::Set(2), + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(registry), + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); + + // load bytecodes + universe.deploy_bytecode_block( + &KeyPair::from_str(TEST_SK_1).unwrap(), + Slot::new(1, 0), + include_bytes!("./wasm/send_message.wasm"), + include_bytes!("./wasm/receive_message.wasm"), + ); + finalized_waitpoint.wait(); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block, None); + finalized_waitpoint.wait(); + // retrieve events emitted by smart contracts + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + start: Some(Slot::new(1, 1)), + end: Some(Slot::new(20, 1)), + ..Default::default() + }); + + // match the events + assert!(events.len() == 1, "One event was expected"); + assert_eq!(events[0].data, "message correctly received: 42,42,42,42"); +} + +#[test] +fn deferred_call_register() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + let keypair = KeyPair::from_str(TEST_SK_1).unwrap(); + let keypair2 = KeyPair::from_str(TEST_SK_3).unwrap(); + let saved_bytecode = Arc::new(RwLock::new(None)); + + let db_lock = foreign_controllers.db.clone(); + + let sender_addr = + Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi").unwrap(); + + let sender_addr_clone = sender_addr; + + dbg!(Address::from_public_key(&keypair2.get_public_key()).to_string()); + + selector_boilerplate(&mut foreign_controllers.selector_controller); + + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + foreign_controllers + .ledger_controller + .set_expectations(|ledger_controller| { + ledger_controller + .expect_get_balance() + .returning(move |_| Some(Amount::from_str("100").unwrap())); + }); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + // assert sender was debited ( -10 coins) and -5.2866 for fees + match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("75.361635312").unwrap()) + ); + } + _ => panic!("wrong change type"), + }; + + { + // manually write the deferred call to the db + // then in the next slot (1,1) we will find and execute it + let reg = + DeferredCallRegistry::new(db_lock.clone(), DeferredCallsConfig::default()); + let mut batch = DBBatch::default(); + reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); + db_lock + .write() + .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); + } + + let slot_changes = changes + .deferred_call_changes + .slots_change + .get(&Slot::new(1, 1)) + .unwrap(); + let _call = slot_changes.calls.first_key_value().unwrap().1; + + // assert total gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + assert_eq!( + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(1050000) + ); + + //gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + assert_eq!(slot_changes.get_effective_slot_gas().unwrap(), 1050000); + + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + match changes + .ledger_changes + .0 + .get( + &Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + ) + .unwrap() + { + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("110.1111").unwrap()) + ); + } + _ => panic!("wrong change type"), + } + + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + let (_slot, slot_change) = changes + .deferred_call_changes + .slots_change + .first_key_value() + .unwrap(); + + let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + + // call was executed and then deleted + assert_eq!(set_delete, &SetOrDelete::Delete); + + // assert total gas was set to 0 + assert_eq!( + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(0) + ); + finalized_waitpoint_trigger_handle2.trigger(); + }); + + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Keep, + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_base_fee(Amount::from_str("0.000005").unwrap()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert( + Slot { + period: 1, + thread: 1, + }, + defer_reg_slot_changes, + ); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredCallRegistryChanges { + slots_change: slot_changes, + effective_total_gas: SetOrKeep::Keep, + total_calls_registered: SetOrKeep::Set(0), + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + )), + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + // abi call to register a deferred call + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 0), + include_bytes!("./wasm/deferred_call_register.wasm"), + //unused + include_bytes!("./wasm/use_builtins.wasm"), + ); + finalized_waitpoint.wait(); + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter::default()); + + assert_eq!(events[0].data, "Deferred call registered"); + + // call id in the register event + let callid_event: String = events[1].data.clone(); + + let _call_id = DeferredCallId::from_str(&callid_event).unwrap(); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block, None); + // match the events + finalized_waitpoint.wait(); +} + +#[test] +fn deferred_call_register_fail() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + let saved_bytecode = Arc::new(RwLock::new(None)); + let target_slot = Slot { + period: 1, + thread: 10, + }; + + selector_boilerplate(&mut foreign_controllers.selector_controller); + + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + assert_eq!(changes.deferred_call_changes.slots_change.len(), 1); + // deferred call was not register + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); + + finalized_waitpoint_trigger_handle2.trigger(); + }); + + let call = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot, + target_address: Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV") + .unwrap(), + target_function: "toto".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 500, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call_id = + DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Set(500), + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert(target_slot, defer_reg_slot_changes); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredCallRegistryChanges { + slots_change: slot_changes, + effective_total_gas: SetOrKeep::Set(2000), + total_calls_registered: SetOrKeep::Set(1), + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(registry), + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block, None); + + finalized_waitpoint.wait(); + + // abi call to register a deferred call + // the call want to book max_async_gas 1_000_000_000 so it fail because we already have a call at this slot with 500 gas + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 1), + include_bytes!("./wasm/deferred_call_register_fail.wasm"), + //unused + include_bytes!("./wasm/use_builtins.wasm"), + ); + finalized_waitpoint.wait(); + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + start: Some(Slot::new(1, 1)), + end: Some(Slot::new(20, 1)), + ..Default::default() + }); + + let ev = events[1].clone(); + assert!(ev.context.is_error); + assert!(ev.data.contains("The Deferred call cannot be registered. Ensure that the target slot is not before/at the current slot nor too far in the future, and that it has at least max_gas available gas")); + + // // update base fee at slot 1,10 + // defer_reg_slot_changes.set_base_fee(Amount::from_str("0.0005").unwrap()); + + // slot_changes.insert(target_slot, defer_reg_slot_changes); + + // let mut db_batch = DBBatch::default(); + + // // reset total slot gas + // registry.apply_changes_to_batch( + // DeferredRegistryChanges { + // slots_change: slot_changes, + // total_gas: SetOrKeep::Set(0), + // }, + // &mut db_batch, + // ); + + // foreign_controllers + // .db + // .write() + // .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 1))); + + // universe.deploy_bytecode_block( + // &keypair, + // Slot::new(1, 2), + // include_bytes!("./wasm/deferred_call_register_fail.wasm"), + // //unused + // include_bytes!("./wasm/use_builtins.wasm"), + // ); + + // let events = universe + // .module_controller + // .get_filtered_sc_output_event(EventFilter { + // start: Some(Slot::new(1, 1)), + // end: Some(Slot::new(20, 1)), + // ..Default::default() + // }); + + // dbg!(&events); + + // let ev = events[1].clone(); +} + +#[test] +fn deferred_call_exists() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + let target_slot = Slot { + period: 10, + thread: 1, + }; + + foreign_controllers + .ledger_controller + .set_expectations(|ledger_controller| { + ledger_controller + .expect_get_balance() + .returning(move |_| Some(Amount::from_str("100").unwrap())); + + ledger_controller + .expect_entry_exists() + .times(2) + .returning(move |_| false); + + ledger_controller + .expect_entry_exists() + .times(1) + .returning(move |_| true); + }); - // Expected message from SC: send_message.ts (see massa unit tests src repo) + selector_boilerplate(&mut foreign_controllers.selector_controller); + + let saved_bytecode = expect_finalize_deploy_and_call_blocks( + Slot::new(1, 1), + Some(Slot::new(1, 2)), + finalized_waitpoint.get_trigger_handle(), + &mut foreign_controllers.final_state, + ); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); foreign_controllers .final_state .write() @@ -1166,13 +2083,58 @@ fn send_and_receive_async_message_without_init_gas() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - assert_eq!( - changes.async_pool_changes, - AsyncPoolChanges(BTreeMap::new()) - ); + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); finalized_waitpoint_trigger_handle.trigger(); }); + let call = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot, + target_address: Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV") + .unwrap(), + target_function: "toto".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 1000000, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call_id = + DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Set(500), + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert(target_slot, defer_reg_slot_changes); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredCallRegistryChanges { + slots_change: slot_changes, + effective_total_gas: SetOrKeep::Set(2000), + total_calls_registered: SetOrKeep::Set(1), + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + final_state_boilerplate( &mut foreign_controllers.final_state, foreign_controllers.db.clone(), @@ -1181,81 +2143,77 @@ fn send_and_receive_async_message_without_init_gas() { Some(saved_bytecode), None, None, + Some(registry), ); - let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); - // load bytecodes + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block, None); + + finalized_waitpoint.wait(); + + // block 1,1 universe.deploy_bytecode_block( - &KeyPair::from_str(TEST_SK_1).unwrap(), - Slot::new(1, 0), - include_bytes!("./wasm/send_message.wasm"), - include_bytes!("./wasm/receive_message.wasm"), + &keypair, + Slot::new(1, 1), + include_bytes!("./wasm/deferred_call_exists.wasm"), + include_bytes!("./wasm/deferred_call_exists.wasm"), ); - println!("waiting for finalized"); finalized_waitpoint.wait(); + let address_sc = universe.get_address_sc_deployed(Slot::new(1, 1)); - // retrieve events emitted by smart contracts + // block 1,2 + let operation = ExecutionTestUniverse::create_call_sc_operation( + &KeyPair::from_str(TEST_SK_3).unwrap(), + 10000000, + Amount::from_str("0.01").unwrap(), + Amount::from_str("20").unwrap(), + Address::from_str(&address_sc).unwrap(), + String::from("exists"), + call_id.to_string().as_bytes().to_vec(), + ) + .unwrap(); + + universe.call_sc_block( + &KeyPair::from_str(TEST_SK_3).unwrap(), + Slot { + period: 1, + thread: 2, + }, + operation, + ); + finalized_waitpoint.wait(); let events = universe .module_controller .get_filtered_sc_output_event(EventFilter { - start: Some(Slot::new(1, 0)), - end: Some(Slot::new(1, 1)), + emitter_address: Some(Address::from_str(&address_sc).unwrap()), ..Default::default() }); - // match the events - assert!(events.len() == 1, "One event was expected"); - assert!(events[0] - .data - .contains("max gas is lower than the minimum instance cost")); + + assert_eq!(events[1].data, "true"); } #[test] -fn cancel_async_message() { +fn deferred_call_quote() { + // setup the period duration let exec_cfg = ExecutionConfig::default(); let finalized_waitpoint = WaitPoint::new(); let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + selector_boilerplate(&mut foreign_controllers.selector_controller); - foreign_controllers - .selector_controller - .set_expectations(|selector_controller| { - selector_controller - .expect_get_producer() - .returning(move |_| { - Ok(Address::from_public_key( - &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), - )) - }); - }); - let saved_bytecode = Arc::new(RwLock::new(None)); - let saved_bytecode_edit = saved_bytecode.clone(); + + let saved_bytecode = expect_finalize_deploy_and_call_blocks( + Slot::new(1, 1), + None, + finalized_waitpoint.get_trigger_handle(), + &mut foreign_controllers.final_state, + ); + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); - let sender_addr = - Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi").unwrap(); - let message = AsyncMessage { - emission_slot: Slot { - period: 1, - thread: 0, - }, - emission_index: 0, - sender: sender_addr, - destination: Address::from_str("AU12mzL2UWroPV7zzHpwHnnF74op9Gtw7H55fAmXMnCuVZTFSjZCA") - .unwrap(), - function: String::from("receive"), - max_gas: 3000000, - fee: Amount::from_raw(1), - coins: Amount::from_raw(100), - validity_start: Slot { - period: 1, - thread: 1, - }, - validity_end: Slot { - period: 20, - thread: 20, - }, - function_params: vec![42, 42, 42, 42], - trigger: None, - can_be_executed: true, - }; foreign_controllers .final_state .write() @@ -1263,111 +2221,44 @@ fn cancel_async_message() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - { - let mut saved_bytecode = saved_bytecode_edit.write(); - *saved_bytecode = Some(changes.ledger_changes.get_bytecode_updates()[0].clone()); - } - assert_eq!( - changes.ledger_changes.0.get(&sender_addr).unwrap(), - &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set( - Amount::from_str("90.298635211").unwrap() - ), - bytecode: massa_ledger_exports::SetOrKeep::Keep, - datastore: BTreeMap::new() - }) - ); - + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); finalized_waitpoint_trigger_handle.trigger(); }); - let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); - foreign_controllers - .final_state - .write() - .expect_finalize() - .times(1) - .with(predicate::eq(Slot::new(1, 1)), predicate::always()) - .returning(move |_, changes| { - match changes.ledger_changes.0.get(&sender_addr).unwrap() { - // at slot (1,1) msg was canceled so sender has received the coins (0.0000001) - // sender has received the coins (0.0000001) - SetUpdateOrDelete::Update(change_sender_update) => { - assert_eq!( - change_sender_update.balance, - SetOrKeep::Set(Amount::from_str("100.0000001").unwrap()) - ); - } - _ => panic!("wrong change type"), - } - - match changes.async_pool_changes.0.first_key_value().unwrap().1 { - SetUpdateOrDelete::Delete => { - // msg was deleted - } - _ => panic!("wrong change type"), - } - - finalized_waitpoint_trigger_handle2.trigger(); - }); - - let mut async_pool = AsyncPool::new(AsyncPoolConfig::default(), foreign_controllers.db.clone()); - let mut changes = BTreeMap::default(); - changes.insert( - ( - Reverse(Ratio::new(1, 100000)), - Slot { - period: 1, - thread: 0, - }, - 0, - ), - massa_ledger_exports::SetUpdateOrDelete::Set(message), - ); - let mut db_batch = DBBatch::default(); - async_pool.apply_changes_to_batch(&AsyncPoolChanges(changes), &mut db_batch); - foreign_controllers - .db - .write() - .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); final_state_boilerplate( &mut foreign_controllers.final_state, foreign_controllers.db.clone(), &foreign_controllers.selector_controller, &mut foreign_controllers.ledger_controller, Some(saved_bytecode), - Some(async_pool), + None, + None, None, ); - let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); - // load bytecodes - universe.deploy_bytecode_block( - &KeyPair::from_str(TEST_SK_1).unwrap(), - Slot::new(1, 0), - include_bytes!("./wasm/send_message.wasm"), - include_bytes!("./wasm/receive_message.wasm"), - ); - finalized_waitpoint.wait(); + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); let block = - ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); universe.send_and_finalize(&keypair, block, None); + finalized_waitpoint.wait(); - // Sleep to wait (1,1) candidate slot to be executed. We don't have a mock to waitpoint on or empty block - std::thread::sleep(Duration::from_millis(exec_cfg.t0.as_millis())); - // retrieve events emitted by smart contracts + // block 1,1 + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 1), + include_bytes!("./wasm/deferred_call_quote.wasm"), + include_bytes!("./wasm/deferred_call_quote.wasm"), + ); + finalized_waitpoint.wait(); let events = universe .module_controller - .get_filtered_sc_output_event(EventFilter { - start: Some(Slot::new(1, 1)), - end: Some(Slot::new(20, 1)), - ..Default::default() - }); - assert!(events[0].data.contains(" is not a smart contract address")); + .get_filtered_sc_output_event(EventFilter::default()); + + assert_eq!(events[0].data, "136600000"); } /// Context @@ -1408,6 +2299,7 @@ fn local_execution() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecodes @@ -1487,6 +2379,7 @@ fn sc_deployment() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecodes @@ -1571,6 +2464,7 @@ fn send_and_receive_async_message_with_trigger() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); // load bytecode @@ -1685,6 +2579,7 @@ fn send_and_receive_transaction() { None, None, None, + None, ); foreign_controllers .final_state @@ -1772,6 +2667,7 @@ fn roll_buy() { None, None, None, + None, ); foreign_controllers .final_state @@ -1799,8 +2695,8 @@ fn roll_buy() { assert_eq!( changes.ledger_changes.0.get(&address).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(rewards_for_block_creator), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: SetOrKeep::Set(rewards_for_block_creator), + bytecode: SetOrKeep::Keep, datastore: BTreeMap::new() }) ); @@ -1882,6 +2778,7 @@ fn roll_sell() { None, None, Some(pos_final_state), + None, ); foreign_controllers .final_state @@ -2052,6 +2949,7 @@ fn auto_sell_on_missed_blocks() { None, None, Some(pos_final_state.clone()), + None, ); foreign_controllers @@ -2181,6 +3079,7 @@ fn roll_slash() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -2310,6 +3209,7 @@ fn roll_slash_2() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -2373,6 +3273,7 @@ fn sc_execution_error() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecode @@ -2431,6 +3332,7 @@ fn sc_datastore() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecode @@ -2485,6 +3387,7 @@ fn set_bytecode_error() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecodes @@ -2564,6 +3467,7 @@ fn datastore_manipulations() { None, None, None, + None, ); foreign_controllers .final_state @@ -2754,6 +3658,7 @@ fn events_from_switching_blockclique() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -2805,6 +3710,7 @@ fn not_enough_instance_gas() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -2871,6 +3777,7 @@ fn sc_builtins() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); universe.deploy_bytecode_block( @@ -2918,6 +3825,7 @@ fn validate_address() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); universe.deploy_bytecode_block( @@ -2969,6 +3877,7 @@ fn test_rewards() { None, None, None, + None, ); foreign_controllers .final_state @@ -3121,6 +4030,7 @@ fn chain_id() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); universe.deploy_bytecode_block( @@ -3165,6 +4075,7 @@ fn execution_trace() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -3287,6 +4198,7 @@ fn execution_trace_nested() { None, None, None, + None, ); // let rt = tokio::runtime::Runtime::new().unwrap(); @@ -3409,6 +4321,7 @@ fn test_dump_block() { None, None, None, + None, ); foreign_controllers .final_state diff --git a/massa-execution-worker/src/tests/tests_active_history.rs b/massa-execution-worker/src/tests/tests_active_history.rs index 9826502b069..67838ce5809 100644 --- a/massa-execution-worker/src/tests/tests_active_history.rs +++ b/massa-execution-worker/src/tests/tests_active_history.rs @@ -43,6 +43,7 @@ fn test_active_history_deferred_credits() { state_changes: StateChanges { ledger_changes: Default::default(), async_pool_changes: Default::default(), + deferred_call_changes: Default::default(), pos_changes: PoSChanges { seed_bits: Default::default(), roll_changes: Default::default(), diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_exists.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_exists.wasm new file mode 100644 index 00000000000..eb6ce3d0076 Binary files /dev/null and b/massa-execution-worker/src/tests/wasm/deferred_call_exists.wasm differ diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_quote.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_quote.wasm new file mode 100644 index 00000000000..5db659087ea Binary files /dev/null and b/massa-execution-worker/src/tests/wasm/deferred_call_quote.wasm differ diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm new file mode 100644 index 00000000000..523f6a86a5b Binary files /dev/null and b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm differ diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm new file mode 100644 index 00000000000..c8189911c8c Binary files /dev/null and b/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm differ diff --git a/massa-final-state/Cargo.toml b/massa-final-state/Cargo.toml index 3ad078100cc..7e8b1f6ef8e 100644 --- a/massa-final-state/Cargo.toml +++ b/massa-final-state/Cargo.toml @@ -42,6 +42,7 @@ massa-proto-rs = { workspace = true, "features" = ["tonic"] } massa_versioning = { workspace = true } massa_time = { workspace = true } massa_hash = { workspace = true } +massa_deferred_calls = { workspace = true } serde_json = { workspace = true, optional = true } parking_lot = { workspace = true, "features" = [ diff --git a/massa-final-state/src/config.rs b/massa-final-state/src/config.rs index 49396734a91..0895734a439 100644 --- a/massa-final-state/src/config.rs +++ b/massa-final-state/src/config.rs @@ -3,6 +3,7 @@ //! This file defines a configuration structure containing all settings for final state management use massa_async_pool::AsyncPoolConfig; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_ledger_exports::LedgerConfig; use massa_pos_exports::PoSConfig; @@ -16,6 +17,8 @@ pub struct FinalStateConfig { pub ledger_config: LedgerConfig, /// asynchronous pool configuration pub async_pool_config: AsyncPoolConfig, + /// config for deferred calls + pub deferred_calls_config: DeferredCallsConfig, /// proof-of-stake configuration pub pos_config: PoSConfig, /// executed operations configuration diff --git a/massa-final-state/src/controller_trait.rs b/massa-final-state/src/controller_trait.rs index fd32c400695..52506c90454 100644 --- a/massa-final-state/src/controller_trait.rs +++ b/massa-final-state/src/controller_trait.rs @@ -1,5 +1,6 @@ use massa_async_pool::AsyncPool; use massa_db_exports::{DBBatch, ShareableMassaDBController}; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::ExecutedDenunciations; use massa_hash::Hash; use massa_ledger_exports::LedgerController; @@ -90,4 +91,7 @@ pub trait FinalStateController: Send + Sync { /// Get mutable reference to MIP Store fn get_mip_store_mut(&mut self) -> &mut MipStore; + + /// Get deferred call registry + fn get_deferred_call_registry(&self) -> &DeferredCallRegistry; } diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index 0396a663764..faf31b34953 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -16,14 +16,15 @@ use massa_db_exports::{ EXECUTED_OPS_PREFIX, LEDGER_PREFIX, MIP_STORE_PREFIX, STATE_CF, }; use massa_db_exports::{EXECUTION_TRAIL_HASH_PREFIX, MIP_STORE_STATS_PREFIX, VERSIONING_CF}; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::ExecutedDenunciations; use massa_executed_ops::ExecutedOps; use massa_hash::Hash; use massa_ledger_exports::LedgerController; -use massa_ledger_exports::SetOrKeep; use massa_models::operation::OperationId; use massa_models::slot::Slot; use massa_models::timeslots::get_block_slot_timestamp; +use massa_models::types::SetOrKeep; use massa_pos_exports::{PoSFinalState, SelectorController}; use massa_versioning::versioning::MipStore; use tracing::{debug, info, warn}; @@ -36,6 +37,8 @@ pub struct FinalState { pub ledger: Box, /// asynchronous pool containing messages sorted by priority and their data pub async_pool: AsyncPool, + /// deferred calls + pub deferred_call_registry: DeferredCallRegistry, /// proof of stake state containing cycle history and deferred credits pub pos_state: PoSFinalState, /// executed operations @@ -106,9 +109,13 @@ impl FinalState { let executed_denunciations = ExecutedDenunciations::new(config.executed_denunciations_config.clone(), db.clone()); + let deferred_call_registry = + DeferredCallRegistry::new(db.clone(), config.deferred_calls_config); + let mut final_state = FinalState { ledger, async_pool, + deferred_call_registry, pos_state, config, executed_ops, @@ -454,6 +461,9 @@ impl FinalState { self.executed_ops .apply_changes_to_batch(changes.executed_ops_changes, slot, &mut db_batch); + self.deferred_call_registry + .apply_changes_to_batch(changes.deferred_call_changes, &mut db_batch); + self.executed_denunciations.apply_changes_to_batch( changes.executed_denunciations_changes, slot, @@ -917,6 +927,10 @@ impl FinalStateController for FinalState { fn get_mip_store(&self) -> &MipStore { &self.mip_store } + + fn get_deferred_call_registry(&self) -> &DeferredCallRegistry { + &self.deferred_call_registry + } } #[cfg(test)] @@ -926,6 +940,7 @@ mod test { use std::str::FromStr; use std::sync::Arc; + use massa_deferred_calls::config::DeferredCallsConfig; use num::rational::Ratio; use parking_lot::RwLock; use tempfile::tempdir; @@ -935,11 +950,12 @@ mod test { use massa_db_worker::MassaDB; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_hash::Hash; - use massa_ledger_exports::{LedgerChanges, LedgerConfig, LedgerEntryUpdate, SetUpdateOrDelete}; + use massa_ledger_exports::{LedgerChanges, LedgerConfig, LedgerEntryUpdate}; use massa_ledger_worker::FinalLedger; use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; + use massa_models::types::SetUpdateOrDelete; use massa_models::config::{ DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, @@ -995,9 +1011,11 @@ mod test { keep_executed_history_extra_periods: KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, }; + let deferred_calls_config = DeferredCallsConfig::default(); let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), async_pool_config, + deferred_calls_config, pos_config, executed_ops_config, executed_denunciations_config, diff --git a/massa-final-state/src/mapping_grpc.rs b/massa-final-state/src/mapping_grpc.rs index 1f42bf4f402..5c45b997634 100644 --- a/massa-final-state/src/mapping_grpc.rs +++ b/massa-final-state/src/mapping_grpc.rs @@ -2,7 +2,7 @@ use crate::StateChanges; use massa_async_pool::AsyncMessageId; -use massa_ledger_exports::{SetOrKeep, SetUpdateOrDelete}; +use massa_models::types::{SetOrKeep, SetUpdateOrDelete}; use massa_proto_rs::massa::model::v1 as grpc_model; impl From for grpc_model::StateChanges { diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index c524c7882d1..ce1b02746a0 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -5,16 +5,21 @@ use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; +use massa_deferred_calls::{ + config::DeferredCallsConfig, + registry_changes::{ + DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, + DeferredRegistryChangesSerializer, + }, +}; use massa_executed_ops::{ ExecutedDenunciationsChanges, ExecutedDenunciationsChangesDeserializer, ExecutedDenunciationsChangesSerializer, ExecutedOpsChanges, ExecutedOpsChangesDeserializer, ExecutedOpsChangesSerializer, }; use massa_hash::{HashDeserializer, HashSerializer}; -use massa_ledger_exports::{ - LedgerChanges, LedgerChangesDeserializer, LedgerChangesSerializer, SetOrKeep, - SetOrKeepDeserializer, SetOrKeepSerializer, -}; +use massa_ledger_exports::{LedgerChanges, LedgerChangesDeserializer, LedgerChangesSerializer}; +use massa_models::types::{SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_pos_exports::{PoSChanges, PoSChangesDeserializer, PoSChangesSerializer}; use massa_serialization::{Deserializer, SerializeError, Serializer}; use nom::{ @@ -31,6 +36,8 @@ pub struct StateChanges { pub ledger_changes: LedgerChanges, /// asynchronous pool changes pub async_pool_changes: AsyncPoolChanges, + /// deferred call changes + pub deferred_call_changes: DeferredCallRegistryChanges, /// roll state changes pub pos_changes: PoSChanges, /// executed operations changes @@ -45,6 +52,7 @@ pub struct StateChanges { pub struct StateChangesSerializer { ledger_changes_serializer: LedgerChangesSerializer, async_pool_changes_serializer: AsyncPoolChangesSerializer, + deferred_call_changes_serializer: DeferredRegistryChangesSerializer, pos_changes_serializer: PoSChangesSerializer, ops_changes_serializer: ExecutedOpsChangesSerializer, de_changes_serializer: ExecutedDenunciationsChangesSerializer, @@ -63,6 +71,7 @@ impl StateChangesSerializer { Self { ledger_changes_serializer: LedgerChangesSerializer::new(), async_pool_changes_serializer: AsyncPoolChangesSerializer::new(), + deferred_call_changes_serializer: DeferredRegistryChangesSerializer::new(), pos_changes_serializer: PoSChangesSerializer::new(), ops_changes_serializer: ExecutedOpsChangesSerializer::new(), de_changes_serializer: ExecutedDenunciationsChangesSerializer::new(), @@ -77,6 +86,8 @@ impl Serializer for StateChangesSerializer { .serialize(&value.ledger_changes, buffer)?; self.async_pool_changes_serializer .serialize(&value.async_pool_changes, buffer)?; + self.deferred_call_changes_serializer + .serialize(&value.deferred_call_changes, buffer)?; self.pos_changes_serializer .serialize(&value.pos_changes, buffer)?; self.ops_changes_serializer @@ -93,6 +104,7 @@ impl Serializer for StateChangesSerializer { pub struct StateChangesDeserializer { ledger_changes_deserializer: LedgerChangesDeserializer, async_pool_changes_deserializer: AsyncPoolChangesDeserializer, + deferred_call_changes_deserializer: DeferredRegistryChangesDeserializer, pos_changes_deserializer: PoSChangesDeserializer, ops_changes_deserializer: ExecutedOpsChangesDeserializer, de_changes_deserializer: ExecutedDenunciationsChangesDeserializer, @@ -118,6 +130,7 @@ impl StateChangesDeserializer { max_ops_changes_length: u64, endorsement_count: u32, max_de_changes_length: u64, + deferred_calls_config: DeferredCallsConfig, ) -> Self { Self { ledger_changes_deserializer: LedgerChangesDeserializer::new( @@ -133,6 +146,10 @@ impl StateChangesDeserializer { max_function_params_length, max_datastore_key_length as u32, ), + // todo max gas + deferred_call_changes_deserializer: DeferredRegistryChangesDeserializer::new( + deferred_calls_config, + ), pos_changes_deserializer: PoSChangesDeserializer::new( thread_count, max_rolls_length, @@ -169,6 +186,9 @@ impl Deserializer for StateChangesDeserializer { context("Failed async_pool_changes deserialization", |input| { self.async_pool_changes_deserializer.deserialize(input) }), + context("Failed deferred_call_changes deserialization", |input| { + self.deferred_call_changes_deserializer.deserialize(input) + }), context("Failed roll_state_changes deserialization", |input| { self.pos_changes_deserializer.deserialize(input) }), @@ -191,6 +211,7 @@ impl Deserializer for StateChangesDeserializer { |( ledger_changes, async_pool_changes, + deferred_call_changes, pos_changes, executed_ops_changes, executed_denunciations_changes, @@ -198,6 +219,7 @@ impl Deserializer for StateChangesDeserializer { )| StateChanges { ledger_changes, async_pool_changes, + deferred_call_changes, pos_changes, executed_ops_changes, executed_denunciations_changes, @@ -211,7 +233,8 @@ impl Deserializer for StateChangesDeserializer { impl StateChanges { /// extends the current `StateChanges` with another one pub fn apply(&mut self, changes: StateChanges) { - use massa_ledger_exports::Applicable; + // TODO deferred_call_changes ? + use massa_models::types::Applicable; self.ledger_changes.apply(changes.ledger_changes); self.async_pool_changes.apply(changes.async_pool_changes); self.pos_changes.extend(changes.pos_changes); @@ -230,11 +253,13 @@ mod test { use std::str::FromStr; use massa_async_pool::AsyncMessage; - use massa_ledger_exports::{LedgerEntryUpdate, SetUpdateOrDelete}; + use massa_deferred_calls::config::DeferredCallsConfig; + use massa_ledger_exports::LedgerEntryUpdate; use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; use massa_models::slot::Slot; + use massa_models::types::SetUpdateOrDelete; use massa_serialization::DeserializeError; use massa_models::config::{ @@ -319,6 +344,7 @@ mod test { MAX_EXECUTED_OPS_CHANGES_LENGTH, ENDORSEMENT_COUNT, MAX_DENUNCIATION_CHANGES_LENGTH, + DeferredCallsConfig::default(), ) .deserialize::(&serialized) .unwrap(); @@ -355,7 +381,7 @@ mod test { let mut datastore = BTreeMap::new(); datastore.insert( b"hello".to_vec(), - massa_ledger_exports::SetOrDelete::Set(b"world".to_vec()), + massa_models::types::SetOrDelete::Set(b"world".to_vec()), ); let ledger_entry = LedgerEntryUpdate { balance: SetOrKeep::Set(amount), diff --git a/massa-final-state/src/test_exports/config.rs b/massa-final-state/src/test_exports/config.rs index 5321441ef96..068db07a3ad 100644 --- a/massa-final-state/src/test_exports/config.rs +++ b/massa-final-state/src/test_exports/config.rs @@ -4,11 +4,13 @@ use std::path::PathBuf; +use massa_deferred_calls::config::DeferredCallsConfig; use num::rational::Ratio; use crate::{FinalState, FinalStateConfig}; use massa_async_pool::{AsyncPool, AsyncPoolConfig}; use massa_db_exports::ShareableMassaDBController; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::{ ExecutedDenunciations, ExecutedDenunciationsConfig, ExecutedOps, ExecutedOpsConfig, }; @@ -34,6 +36,10 @@ impl FinalState { FinalState { ledger: Box::new(FinalLedger::new(config.ledger_config.clone(), db.clone())), async_pool: AsyncPool::new(config.async_pool_config.clone(), db.clone()), + deferred_call_registry: DeferredCallRegistry::new( + db.clone(), + config.deferred_calls_config, + ), pos_state, executed_ops: ExecutedOps::new(config.executed_ops_config.clone(), db.clone()), executed_denunciations: ExecutedDenunciations::new( @@ -62,6 +68,7 @@ impl Default for FinalStateConfig { FinalStateConfig { ledger_config: LedgerConfig::default(), async_pool_config: AsyncPoolConfig::default(), + deferred_calls_config: DeferredCallsConfig::default(), executed_ops_config: ExecutedOpsConfig { thread_count: THREAD_COUNT, keep_executed_history_extra_periods: KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, diff --git a/massa-final-state/src/test_exports/mock.rs b/massa-final-state/src/test_exports/mock.rs index 741a2f27589..349820152e8 100644 --- a/massa-final-state/src/test_exports/mock.rs +++ b/massa-final-state/src/test_exports/mock.rs @@ -9,10 +9,12 @@ use std::{ sync::Arc, }; +use crate::{controller_trait::FinalStateController, FinalState, FinalStateConfig}; use massa_async_pool::AsyncPool; use massa_db_exports::{ DBBatch, MassaIteratorMode, ShareableMassaDBController, METADATA_CF, STATE_CF, STATE_HASH_KEY, }; +use massa_deferred_calls::{config::DeferredCallsConfig, DeferredCallRegistry}; use massa_executed_ops::{ExecutedDenunciations, ExecutedOps}; use massa_ledger_exports::{LedgerConfig, LedgerController, LedgerEntry, LedgerError}; use massa_ledger_worker::FinalLedger; @@ -27,14 +29,13 @@ use massa_versioning::versioning::MipStore; use parking_lot::RwLock; use tempfile::NamedTempFile; -use crate::{controller_trait::FinalStateController, FinalState, FinalStateConfig}; - #[allow(clippy::too_many_arguments)] /// Create a `FinalState` from pre-set values pub fn create_final_state( config: FinalStateConfig, ledger: Box, async_pool: AsyncPool, + deferred_call_registry: DeferredCallRegistry, pos_state: PoSFinalState, executed_ops: ExecutedOps, executed_denunciations: ExecutedDenunciations, @@ -45,6 +46,7 @@ pub fn create_final_state( config, ledger, async_pool, + deferred_call_registry, pos_state, executed_ops, executed_denunciations, @@ -202,6 +204,7 @@ pub fn get_sample_state( t0: T0, genesis_timestamp: *GENESIS_TIMESTAMP, ledger_backup_periods_interval: 10, + deferred_calls_config: DeferredCallsConfig::default(), }; let mut final_state = if last_start_period > 0 { diff --git a/massa-final-state/src/tests/scenarios.rs b/massa-final-state/src/tests/scenarios.rs index 0d862e30dd9..35b3ca8b53d 100644 --- a/massa-final-state/src/tests/scenarios.rs +++ b/massa-final-state/src/tests/scenarios.rs @@ -8,10 +8,9 @@ use crate::{ use massa_async_pool::{AsyncMessage, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; -use massa_ledger_exports::{ - LedgerChanges, LedgerConfig, LedgerEntryUpdate, SetOrKeep, SetUpdateOrDelete, -}; +use massa_ledger_exports::{LedgerChanges, LedgerConfig, LedgerEntryUpdate}; use massa_ledger_worker::FinalLedger; use massa_models::address::Address; use massa_models::amount::Amount; @@ -22,6 +21,7 @@ use massa_models::config::{ MAX_DEFERRED_CREDITS_LENGTH, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH, POS_SAVED_CYCLES, T0, }; +use massa_models::types::{SetOrKeep, SetUpdateOrDelete}; use massa_models::{config::MAX_DATASTORE_VALUE_LENGTH, slot::Slot}; use massa_pos_exports::{PoSConfig, SelectorConfig}; use massa_pos_worker::start_selector_worker; @@ -94,6 +94,7 @@ fn create_final_state(temp_dir: &TempDir, reset_final_state: bool) -> Arc grpc.grpc_config.max_query_items_per_request { - return Err(GrpcError::InvalidArgument(format!("too many query items received. Only a maximum of {} operations are accepted per request", grpc.grpc_config.max_operation_ids_per_request))); + return Err(GrpcError::InvalidArgument(format!("too many query items received. Only a maximum of {} operations are accepted per request", grpc.grpc_config.max_query_items_per_request))); } let response = grpc diff --git a/massa-ledger-exports/src/ledger_changes.rs b/massa-ledger-exports/src/ledger_changes.rs index 790c4f91122..829d205e949 100644 --- a/massa-ledger-exports/src/ledger_changes.rs +++ b/massa-ledger-exports/src/ledger_changes.rs @@ -3,16 +3,16 @@ //! This file provides structures representing changes to ledger entries use crate::ledger_entry::{LedgerEntry, LedgerEntryDeserializer, LedgerEntrySerializer}; -use crate::types::{ - Applicable, SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, - SetOrKeepDeserializer, SetOrKeepSerializer, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, - SetUpdateOrDeleteSerializer, -}; use massa_models::address::{Address, AddressDeserializer, AddressSerializer}; use massa_models::amount::{Amount, AmountDeserializer, AmountSerializer}; use massa_models::bytecode::{Bytecode, BytecodeDeserializer, BytecodeSerializer}; use massa_models::prehash::PreHashMap; use massa_models::serialization::{VecU8Deserializer, VecU8Serializer}; +use massa_models::types::{ + Applicable, SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, + SetOrKeepDeserializer, SetOrKeepSerializer, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, + SetUpdateOrDeleteSerializer, +}; use massa_serialization::{ Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, }; @@ -66,8 +66,9 @@ impl Serializer, SetOrDelete>>> for DatastoreUpdateSeri /// ## Example /// ```rust /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{DatastoreUpdateSerializer, SetOrDelete}; + /// use massa_ledger_exports::{DatastoreUpdateSerializer}; /// use massa_serialization::Serializer; + /// use massa_models::types::SetOrDelete; /// /// let serializer = DatastoreUpdateSerializer::new(); /// let mut buffer = Vec::new(); @@ -131,8 +132,9 @@ impl Deserializer, SetOrDelete>>> for DatastoreUpdateDe /// ## Example /// ```rust /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{DatastoreUpdateDeserializer, DatastoreUpdateSerializer, SetOrDelete}; + /// use massa_ledger_exports::{DatastoreUpdateDeserializer, DatastoreUpdateSerializer}; /// use massa_serialization::{Serializer, Deserializer, DeserializeError}; + /// use massa_models::types::SetOrDelete; /// /// let serializer = DatastoreUpdateSerializer::new(); /// let deserializer = DatastoreUpdateDeserializer::new(255, 255, 255); @@ -203,7 +205,8 @@ impl Serializer for LedgerEntryUpdateSerializer { /// use massa_models::{prehash::PreHashMap, address::Address, amount::Amount, bytecode::Bytecode}; /// use std::str::FromStr; /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{SetOrDelete, SetOrKeep, LedgerEntryUpdate, LedgerEntryUpdateSerializer}; + /// use massa_models::types::{SetOrDelete, SetOrKeep}; + /// use massa_ledger_exports::{LedgerEntryUpdate, LedgerEntryUpdateSerializer}; /// /// let key = "hello world".as_bytes().to_vec(); /// let mut datastore = BTreeMap::default(); @@ -270,8 +273,9 @@ impl Deserializer for LedgerEntryUpdateDeserializer { /// use massa_serialization::{Deserializer, Serializer, DeserializeError}; /// use massa_models::{prehash::PreHashMap, address::Address, amount::Amount, bytecode::Bytecode}; /// use std::str::FromStr; + /// use massa_models::types::{SetOrDelete, SetOrKeep}; /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{SetOrDelete, SetOrKeep, LedgerEntryUpdate, LedgerEntryUpdateSerializer, LedgerEntryUpdateDeserializer}; + /// use massa_ledger_exports::{LedgerEntryUpdate, LedgerEntryUpdateSerializer, LedgerEntryUpdateDeserializer}; /// /// let key = "hello world".as_bytes().to_vec(); /// let mut datastore = BTreeMap::default(); @@ -369,8 +373,9 @@ impl Serializer for LedgerChangesSerializer { /// ## Example /// ``` /// use massa_serialization::Serializer; - /// use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete, LedgerChanges, LedgerChangesSerializer}; + /// use massa_ledger_exports::{LedgerEntry, LedgerChanges, LedgerChangesSerializer}; /// use std::str::FromStr; + /// use massa_models::types::{SetUpdateOrDelete}; /// use std::collections::BTreeMap; /// use massa_models::{amount::Amount, address::Address, bytecode::Bytecode}; /// @@ -451,9 +456,10 @@ impl Deserializer for LedgerChangesDeserializer { /// ## Example /// ``` /// use massa_serialization::{Deserializer, Serializer, DeserializeError}; - /// use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete, LedgerChanges, LedgerChangesSerializer, LedgerChangesDeserializer}; + /// use massa_ledger_exports::{LedgerEntry, LedgerChanges, LedgerChangesSerializer, LedgerChangesDeserializer}; /// use std::str::FromStr; /// use std::collections::BTreeMap; + /// use massa_models::types::{SetUpdateOrDelete}; /// use massa_models::{amount::Amount, address::Address, bytecode::Bytecode}; /// /// let key = "hello world".as_bytes().to_vec(); diff --git a/massa-ledger-exports/src/ledger_entry.rs b/massa-ledger-exports/src/ledger_entry.rs index abac9332072..52f4064d5e0 100644 --- a/massa-ledger-exports/src/ledger_entry.rs +++ b/massa-ledger-exports/src/ledger_entry.rs @@ -3,10 +3,10 @@ //! This file defines the structure representing an entry in the `FinalLedger` use crate::ledger_changes::LedgerEntryUpdate; -use crate::types::{Applicable, SetOrDelete}; use massa_models::amount::{Amount, AmountDeserializer, AmountSerializer}; use massa_models::bytecode::{Bytecode, BytecodeDeserializer, BytecodeSerializer}; use massa_models::datastore::{Datastore, DatastoreDeserializer, DatastoreSerializer}; +use massa_models::types::{Applicable, SetOrDelete}; use massa_serialization::{Deserializer, SerializeError, Serializer}; use nom::error::{context, ContextError, ParseError}; use nom::sequence::tuple; diff --git a/massa-ledger-exports/src/lib.rs b/massa-ledger-exports/src/lib.rs index 9a2dadd65eb..67a099a9c5e 100644 --- a/massa-ledger-exports/src/lib.rs +++ b/massa-ledger-exports/src/lib.rs @@ -9,7 +9,6 @@ mod key; mod ledger_changes; mod ledger_entry; mod mapping_grpc; -mod types; pub use config::LedgerConfig; pub use controller::LedgerController; @@ -24,10 +23,6 @@ pub use ledger_changes::{ LedgerEntryUpdateDeserializer, LedgerEntryUpdateSerializer, }; pub use ledger_entry::{LedgerEntry, LedgerEntryDeserializer, LedgerEntrySerializer}; -pub use types::{ - Applicable, SetOrDelete, SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer, - SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, SetUpdateOrDeleteSerializer, -}; #[cfg(feature = "test-exports")] pub mod test_exports; diff --git a/massa-ledger-exports/src/mapping_grpc.rs b/massa-ledger-exports/src/mapping_grpc.rs index 04aa055dd51..48b9f015dfd 100644 --- a/massa-ledger-exports/src/mapping_grpc.rs +++ b/massa-ledger-exports/src/mapping_grpc.rs @@ -1,6 +1,8 @@ // Copyright (c) 2023 MASSA LABS -use crate::{LedgerEntry, LedgerEntryUpdate, SetOrDelete, SetOrKeep}; +use crate::{LedgerEntry, LedgerEntryUpdate}; + +use massa_models::types::{SetOrDelete, SetOrKeep}; use massa_proto_rs::massa::model::v1 as grpc_model; impl From for grpc_model::LedgerEntry { diff --git a/massa-ledger-worker/src/ledger_db.rs b/massa-ledger-worker/src/ledger_db.rs index 8dca6c1c74b..a2e517d6f05 100644 --- a/massa-ledger-worker/src/ledger_db.rs +++ b/massa-ledger-worker/src/ledger_db.rs @@ -10,6 +10,7 @@ use massa_ledger_exports::*; use massa_models::amount::AmountDeserializer; use massa_models::bytecode::BytecodeDeserializer; use massa_models::datastore::get_prefix_bounds; +use massa_models::types::{SetOrDelete, SetOrKeep, SetUpdateOrDelete}; use massa_models::{ address::Address, amount::AmountSerializer, bytecode::BytecodeSerializer, slot::Slot, }; @@ -575,7 +576,8 @@ mod tests { use massa_db_exports::{MassaDBConfig, MassaDBController, STATE_HASH_INITIAL_BYTES}; use massa_db_worker::MassaDB; use massa_hash::HashXof; - use massa_ledger_exports::{LedgerEntry, LedgerEntryUpdate, SetOrKeep}; + use massa_ledger_exports::{LedgerEntry, LedgerEntryUpdate}; + use massa_models::types::SetOrKeep; use massa_models::{ address::Address, amount::{Amount, AmountDeserializer}, diff --git a/massa-metrics/src/lib.rs b/massa-metrics/src/lib.rs index fb591833d1e..6e8c6909df5 100644 --- a/massa-metrics/src/lib.rs +++ b/massa-metrics/src/lib.rs @@ -30,6 +30,33 @@ lazy_static! { register_int_gauge!("blocks_storage_counter", "blocks storage counter len").unwrap(); static ref ENDORSEMENTS_COUNTER: IntGauge = register_int_gauge!("endorsements_storage_counter", "endorsements storage counter len").unwrap(); + + static ref DEFERRED_CALL_REGISTERED: IntGauge = register_int_gauge!( + "deferred_calls_registered", "number of deferred calls registered" ).unwrap(); + + static ref DEFERRED_CALLS_TOTAL_GAS: IntGauge = register_int_gauge!( + "deferred_calls_total_gas", "total gas used by deferred calls" ).unwrap(); + +} + +pub fn dec_deferred_calls_registered() { + DEFERRED_CALL_REGISTERED.dec(); +} + +pub fn inc_deferred_calls_registered() { + DEFERRED_CALL_REGISTERED.inc(); +} + +pub fn set_deferred_calls_registered(val: usize) { + DEFERRED_CALL_REGISTERED.set(val as i64); +} + +pub fn set_deferred_calls_total_gas(val: u128) { + DEFERRED_CALLS_TOTAL_GAS.set(val as i64); +} + +pub fn get_deferred_calls_registered() -> i64 { + DEFERRED_CALL_REGISTERED.get() } pub fn set_blocks_counter(val: usize) { @@ -173,6 +200,10 @@ pub struct MassaMetrics { peers_bandwidth: Arc>>, pub tick_delay: Duration, + + // deferred calls metrics + deferred_calls_executed: IntCounter, + deferred_calls_failed: IntCounter, } impl MassaMetrics { @@ -199,6 +230,8 @@ impl MassaMetrics { consensus_vec.push(gauge); } + set_deferred_calls_registered(0); + // set available processors let process_available_processors = IntGauge::new("process_available_processors", "number of processors") @@ -406,6 +439,15 @@ impl MassaMetrics { ) .unwrap(); + let deferred_calls_executed = IntCounter::new( + "deferred_calls_executed", + "number of deferred calls executed", + ) + .unwrap(); + + let deferred_calls_failed = + IntCounter::new("deferred_calls_failed", "number of deferred calls failed").unwrap(); + let mut stopper = MetricsStopper::default(); if enabled { @@ -458,6 +500,8 @@ impl MassaMetrics { let _ = prometheus::register(Box::new(current_time_period.clone())); let _ = prometheus::register(Box::new(current_time_thread.clone())); let _ = prometheus::register(Box::new(block_slot_delay.clone())); + let _ = prometheus::register(Box::new(deferred_calls_executed.clone())); + let _ = prometheus::register(Box::new(deferred_calls_failed.clone())); stopper = server::bind_metrics(addr); } @@ -514,6 +558,8 @@ impl MassaMetrics { final_cursor_period, peers_bandwidth: Arc::new(RwLock::new(HashMap::new())), tick_delay, + deferred_calls_executed, + deferred_calls_failed, }, stopper, ) @@ -702,6 +748,14 @@ impl MassaMetrics { self.block_slot_delay.observe(delay); } + pub fn inc_deferred_calls_executed(&self) { + self.deferred_calls_executed.inc(); + } + + pub fn inc_deferred_calls_failed(&self) { + self.deferred_calls_failed.inc(); + } + /// Update the bandwidth metrics for all peers /// HashMap pub fn update_peers_tx_rx(&self, data: HashMap) { diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 92de08cbe69..97130583c0b 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -196,7 +196,7 @@ pub const MAX_DATASTORE_ENTRY_COUNT: u64 = u64::MAX; /// Maximum number of key/values in the datastore of a `ExecuteSC` operation pub const MAX_OPERATION_DATASTORE_ENTRY_COUNT: u64 = 128; /// Maximum length function name in call SC -pub const MAX_FUNCTION_NAME_LENGTH: u16 = u16::MAX; +pub const MAX_FUNCTION_NAME_LENGTH: u16 = 255; /// Maximum size of parameters in call SC pub const MAX_PARAMETERS_SIZE: u32 = 10_000_000; /// Maximum length of `rng_seed` in thread cycle @@ -391,6 +391,26 @@ pub const MAX_DENUNCIATIONS_PER_BLOCK_HEADER: u32 = 128; pub const ROLL_COUNT_TO_SLASH_ON_DENUNCIATION: u64 = 1; /// Maximum size of executed denunciations pub const MAX_DENUNCIATION_CHANGES_LENGTH: u64 = 1_000; +/// Maximum size of deferred call pool changes +// TODO define this value +// TODO: set to a reasonable value max pool changes +pub const DEFERRED_CALL_MAX_POOL_CHANGES: u64 = 100_000; +/// Maximum size of deferred call future slots (1 week) +pub const DEFERRED_CALL_MAX_FUTURE_SLOTS: u64 = 1209600; +/// maximum gas for deferred call +pub const DEFERRED_CALL_MAX_ASYNC_GAS: u64 = MAX_ASYNC_GAS; +/// max change denominator +pub const DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR: usize = 8; +/// deferred call min gas increment (1 nanomassa) +pub const DEFERRED_CALL_MIN_GAS_INCREMENT: u64 = 1; +/// deferred call min gas cost (10 nanomassa) +pub const DEFERRED_CALL_MIN_GAS_COST: u64 = 10; +/// deferred call global overbooking penalty +pub const DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000); +/// deferred call slot overbooking penalty +pub const DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000 / 10_000); +/// deferred call call gas cost +pub const DEFERRED_CALL_CST_GAS_COST: u64 = 750_000; // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] diff --git a/massa-models/src/deferred_calls.rs b/massa-models/src/deferred_calls.rs new file mode 100644 index 00000000000..c9c0a29536b --- /dev/null +++ b/massa-models/src/deferred_calls.rs @@ -0,0 +1,328 @@ +#![allow(unused_macros)] + +use std::{fmt::Debug, ops::Bound, str::FromStr}; + +use massa_serialization::{ + DeserializeError, Deserializer, SerializeError, Serializer, U64VarIntDeserializer, + U64VarIntSerializer, +}; +use nom::{ + error::{ContextError, ParseError}, + IResult, +}; +use transition::Versioned; + +use crate::{ + config::THREAD_COUNT, + error::ModelsError, + serialization::{VecU8Deserializer, VecU8Serializer}, + slot::{Slot, SlotDeserializer, SlotSerializer}, +}; + +const DEFERRED_CALL_ID_PREFIX: &str = "D"; + +#[allow(missing_docs)] +#[transition::versioned(versions("0"))] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct DeferredCallId(Vec); + +/// Serializer for `DeferredCallId` +#[derive(Default, Clone)] +pub struct DeferredCallIdSerializer { + bytes_serializer: VecU8Serializer, +} + +impl DeferredCallIdSerializer { + /// Serializes an `DeferredCallId` into a `Vec` + pub fn new() -> Self { + Self { + bytes_serializer: VecU8Serializer::new(), + } + } +} + +impl Serializer for DeferredCallIdSerializer { + fn serialize( + &self, + value: &DeferredCallId, + buffer: &mut Vec, + ) -> Result<(), SerializeError> { + match value { + DeferredCallId::DeferredCallIdV0(id) => { + self.bytes_serializer.serialize(&id.0, buffer)?; + } + } + Ok(()) + } +} + +/// Deserializer for `DeferredCallId` +#[derive(Clone)] +pub struct DeferredCallIdDeserializer { + bytes_deserializer: VecU8Deserializer, +} + +impl DeferredCallIdDeserializer { + /// Deserializes a `Vec` into an `DeferredCallId` + pub fn new() -> Self { + Self { + bytes_deserializer: VecU8Deserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(128), + ), + } + } +} + +impl Default for DeferredCallIdDeserializer { + fn default() -> Self { + Self::new() + } +} + +impl Deserializer for DeferredCallIdDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredCallId, E> { + let (rest, bytes) = self.bytes_deserializer.deserialize(buffer)?; + Ok(( + rest, + DeferredCallId::DeferredCallIdV0(DeferredCallIdV0(bytes)), + )) + } +} + +impl FromStr for DeferredCallId { + type Err = ModelsError; + + fn from_str(s: &str) -> Result { + if !s.starts_with(DEFERRED_CALL_ID_PREFIX) { + return Err(ModelsError::DeserializeError(format!( + "Invalid prefix for DeferredCallId: {}", + s + ))); + } + let s = &s[DEFERRED_CALL_ID_PREFIX.len()..]; + let bytes = bs58::decode(s).with_check(None).into_vec().map_err(|_| { + ModelsError::DeserializeError(format!( + "Invalid base58 string for DeferredCallId: {}", + s + )) + })?; + DeferredCallId::from_bytes(&bytes) + } +} + +impl std::fmt::Display for DeferredCallId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}{}", + DEFERRED_CALL_ID_PREFIX, + bs58::encode(self.as_bytes()).with_check().into_string() + ) + } +} + +impl ::serde::Serialize for DeferredCallId { + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + if serializer.is_human_readable() { + serializer.collect_str(&self.to_string()) + } else { + serializer.serialize_bytes(self.as_bytes()) + } + } +} + +impl<'de> ::serde::Deserialize<'de> for DeferredCallId { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + struct DeferredCallIdVisitor; + + impl<'de> ::serde::de::Visitor<'de> for DeferredCallIdVisitor { + type Value = DeferredCallId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("ASC + base58::encode(bytes)") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + if let Ok(v_str) = std::str::from_utf8(v) { + DeferredCallId::from_str(v_str).map_err(E::custom) + } else { + Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) + } + } + + fn visit_str(self, v: &str) -> Result + where + E: ::serde::de::Error, + { + DeferredCallId::from_str(v).map_err(E::custom) + } + } + d.deserialize_str(DeferredCallIdVisitor) + } else { + struct BytesVisitor; + + impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { + type Value = DeferredCallId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("[u64varint-of-addr-variant][u64varint-of-version][bytes]") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + DeferredCallId::from_bytes(v).map_err(E::custom) + } + } + + d.deserialize_bytes(BytesVisitor) + } + } +} + +impl DeferredCallId { + /// Return the slot of the `DeferredCallId` + pub fn get_slot(&self) -> Result { + let version_deserializer = U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(u64::MAX), + ); + + let slot_deser = SlotDeserializer::new( + (Bound::Included(0), Bound::Included(u64::MAX)), + (Bound::Included(0), Bound::Excluded(THREAD_COUNT)), + ); + + let (rest, _version) = version_deserializer + .deserialize::(self.as_bytes()) + .map_err(|_e| ModelsError::DeferredCallIdParseError)?; + let (_rest, slot) = slot_deser + .deserialize::(rest) + .map_err(|_e| ModelsError::DeferredCallIdParseError)?; + Ok(slot) + } + + /// Create a new `DeferredCallId` + pub fn new( + version: u64, + target_slot: Slot, + index: u64, + trail_hash: &[u8], + ) -> Result { + let mut id: Vec = Vec::new(); + match version { + 0 => { + let version_serializer = U64VarIntSerializer::new(); + let slot_serializer = SlotSerializer::new(); + version_serializer.serialize(&version, &mut id)?; + slot_serializer.serialize(&target_slot, &mut id)?; + id.extend(index.to_be_bytes()); + id.extend(trail_hash); + Ok(DeferredCallId::DeferredCallIdV0(DeferredCallIdV0(id))) + } + _ => Err(ModelsError::InvalidVersionError(format!( + "Invalid version to create an DeferredCallId: {}", + version + ))), + } + } + + /// Return the version of the `DeferredCallId` as bytes + pub fn as_bytes(&self) -> &[u8] { + match self { + DeferredCallId::DeferredCallIdV0(block_id) => block_id.as_bytes(), + } + } + + /// Create an `DeferredCallId` from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.is_empty() { + return Err(ModelsError::SerializeError("Empty bytes".to_string())); + } + let version = U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(u64::MAX), + ); + let (_, version) = version.deserialize(bytes)?; + match version { + 0 => { + let id = DeferredCallIdV0::from_bytes(bytes)?; + Ok(DeferredCallId::DeferredCallIdV0(id)) + } + _ => Err(ModelsError::InvalidVersionError(format!( + "Invalid version to create an DeferredCallId: {}", + version + ))), + } + } +} + +#[transition::impl_version(versions("0"))] +impl DeferredCallId { + /// Return the version of the `DeferredCallId` as bytes + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } + + /// Create an `DeferredCallId` from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(DeferredCallId(bytes.to_vec())) + } +} + +#[cfg(test)] +mod tests { + use massa_serialization::DeserializeError; + + use super::*; + use crate::slot::Slot; + + #[test] + fn test_deferred_call_id_ser_deser() { + let slot = Slot::new(1, 2); + let index = 3; + let trail_hash = [4, 5, 6]; + let id = DeferredCallId::new(0, slot, index, &trail_hash).unwrap(); + let serializer = DeferredCallIdSerializer::new(); + let mut buffer = Vec::new(); + serializer.serialize(&id, &mut buffer).unwrap(); + let deserializer = DeferredCallIdDeserializer::new(); + let (rest, deserialized_id) = deserializer + .deserialize::(&buffer) + .unwrap(); + assert_eq!(deserialized_id, id); + assert!(rest.is_empty()); + } + + #[test] + fn test_deferred_call_id_from_str() { + let slot = Slot::new(1, 2); + let index = 3; + let trail_hash = [4, 5, 6]; + let id = DeferredCallId::new(0, slot, index, &trail_hash).unwrap(); + let id_str = id.to_string(); + let deserialized_id = DeferredCallId::from_str(&id_str).unwrap(); + assert_eq!(deserialized_id, id); + } + + #[test] + fn test_get_slot() { + let slot = Slot::new(1, 2); + let index = 3; + let trail_hash = [4, 5, 6]; + let id = DeferredCallId::new(0, slot, index, &trail_hash).unwrap(); + assert_eq!(id.get_slot().unwrap(), slot); + } +} diff --git a/massa-models/src/error.rs b/massa-models/src/error.rs index ba4a6b8b069..213672c9ba5 100644 --- a/massa-models/src/error.rs +++ b/massa-models/src/error.rs @@ -62,6 +62,8 @@ pub enum ModelsError { OutdatedBootstrapCursor, /// Error raised {0} ErrorRaised(String), + /// deferred call id parsing error + DeferredCallIdParseError, } impl From>> for ModelsError { diff --git a/massa-models/src/lib.rs b/massa-models/src/lib.rs index ba80ecf5b4d..da5bcf81293 100644 --- a/massa-models/src/lib.rs +++ b/massa-models/src/lib.rs @@ -28,6 +28,8 @@ pub mod composite; pub mod config; /// datastore serialization / deserialization pub mod datastore; +/// deferred call id +pub mod deferred_calls; /// denunciation pub mod denunciation; /// endorsements @@ -62,6 +64,8 @@ pub mod stats; pub mod streaming_step; /// management of the relation between time and slots pub mod timeslots; +/// types +pub mod types; /// versions pub mod version; diff --git a/massa-models/src/slot.rs b/massa-models/src/slot.rs index 65b1015a611..c5de3031d82 100644 --- a/massa-models/src/slot.rs +++ b/massa-models/src/slot.rs @@ -325,6 +325,33 @@ impl Slot { .ok_or(ModelsError::PeriodOverflowError)? .saturating_sub(s.thread as u64)) } + + /// Returns the n-th slot after the current one + /// + /// ## Example + /// ```rust + /// # use massa_models::slot::Slot; + /// let slot = Slot::new(10,3); + /// assert_eq!(slot.skip(62, 32).unwrap(), Slot::new(12, 1)); + /// ``` + pub fn skip(&self, n: u64, thread_count: u8) -> Result { + let mut res_period = self + .period + .checked_add(n / (thread_count as u64)) + .ok_or(ModelsError::PeriodOverflowError)?; + let mut res_thread = (self.thread as u64) + .checked_add(n % (thread_count as u64)) + .ok_or(ModelsError::ThreadOverflowError)?; + + if res_thread >= thread_count as u64 { + res_period = res_period + .checked_add(1) + .ok_or(ModelsError::PeriodOverflowError)?; + res_thread -= thread_count as u64; + } + + Ok(Slot::new(res_period, res_thread as u8)) + } } /// When an address is drawn to create an endorsement it is selected for a specific index diff --git a/massa-ledger-exports/src/types.rs b/massa-models/src/types.rs similarity index 99% rename from massa-ledger-exports/src/types.rs rename to massa-models/src/types.rs index 38749edd91f..3f4485552a3 100644 --- a/massa-ledger-exports/src/types.rs +++ b/massa-models/src/types.rs @@ -1,6 +1,6 @@ // Copyright (c) 2022 MASSA LABS -//! Provides various tools to manipulate ledger entries and changes happening on them. +#![allow(missing_docs)] use massa_serialization::{Deserializer, SerializeError, Serializer}; use nom::bytes::complete::take; diff --git a/massa-node/Cargo.toml b/massa-node/Cargo.toml index b534505c50d..aadb5cd6682 100644 --- a/massa-node/Cargo.toml +++ b/massa-node/Cargo.toml @@ -35,9 +35,7 @@ dump-block = [ ] db_storage_backend = [] file_storage_backend = [] -execution-info = [ - "execution-trace" -] +execution-info = ["execution-trace"] [dependencies] crossbeam-channel = { workspace = true } # BOM UPGRADE Revert to "0.5.6" if problem @@ -64,6 +62,7 @@ massa_bootstrap = { workspace = true } massa_channel = { workspace = true } massa_consensus_exports = { workspace = true } massa_consensus_worker = { workspace = true } +massa_deferred_calls = { workspace = true } massa_executed_ops = { workspace = true } massa_execution_exports = { workspace = true } massa_execution_worker = { workspace = true } diff --git a/massa-node/base_config/gas_costs/abi_gas_costs.json b/massa-node/base_config/gas_costs/abi_gas_costs.json index 3d35aa5cfdb..a15f6458938 100644 --- a/massa-node/base_config/gas_costs/abi_gas_costs.json +++ b/massa-node/base_config/gas_costs/abi_gas_costs.json @@ -12,6 +12,10 @@ "assembly_script_date_now": 71, "assembly_script_delete_data": 196, "assembly_script_delete_data_for": 220, + "assembly_script_deferred_call_cancel": 11, + "assembly_script_deferred_call_exists": 11, + "assembly_script_get_deferred_call_quote": 11, + "assembly_script_deferred_call_register": 11, "assembly_script_function_exists": 575, "assembly_script_generate_event": 172, "assembly_script_get_balance": 149, diff --git a/massa-node/base_config/openrpc.json b/massa-node/base_config/openrpc.json index 9de375c5d02..ffae6260a5a 100644 --- a/massa-node/base_config/openrpc.json +++ b/massa-node/base_config/openrpc.json @@ -489,6 +489,105 @@ "summary": "Summary of the current state", "description": "Summary of the current state: time, last final blocks (hash, thread, slot, timestamp), clique count, connected nodes count." }, + { + "tags": [ + { + "name": "public", + "description": "Massa public api" + } + ], + "params": [ + { + "name": "req", + "description": "Deferred calls quote request", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallsQuoteRequest" + } + }, + "required": true + } + ], + "result": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallsQuoteResponse" + } + }, + "name": "DeferredCallsQuoteResponse" + }, + "name": "get_deferred_call_quote", + "summary": "Get deferred call quote", + "description": "Returns if slot is available and the price to book the requested gas." + }, + { + "tags": [ + { + "name": "public", + "description": "Massa public api" + } + ], + "params": [ + { + "name": "arg", + "description": "Deferred calls ids", + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "required": true + } + ], + "result": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallResponse" + } + }, + "name": "DeferredCallResponse" + }, + "name": "get_deferred_call_info", + "summary": "Get deferred calls information", + "description": "Returns information about deferred calls." + }, + { + "tags": [ + { + "name": "public", + "description": "Massa public api" + } + ], + "params": [ + { + "name": "slots", + "description": "Deferred calls ids", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Slot" + } + }, + "required": true + } + ], + "result": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallsSlotResponse" + } + }, + "name": "DeferredCallResponse" + }, + "name": "get_deferred_call_ids_by_slot", + "summary": "List deferred call ids by slot", + "description": "Returns deferred calls list for given slots." + }, { "tags": [ { @@ -2006,6 +2105,123 @@ }, "additionalProperties": false }, + "DeferredCall": { + "type": "object", + "required": [ + "sender_address", + "target_slot", + "target_address", + "target_function", + "parameters", + "coins", + "max_gas", + "fee", + "cancelled" + ], + "properties": { + "sender_address": { + "$ref": "#/components/schemas/Address" + }, + "target_slot": { + "$ref": "#/components/schemas/Slot" + }, + "target_address": { + "$ref": "#/components/schemas/Address" + }, + "target_function": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "number" + } + }, + "coins": { + "type": "number" + }, + "max_gas": { + "type": "number" + }, + "fee": { + "type": "number" + }, + "cancelled": { + "type": "boolean" + } + } + }, + "DeferredCallsQuoteRequest": { + "type": "object", + "required": [ + "target_slot", + "max_gas_request", + "params_size" + ], + "properties": { + "target_slot": { + "$ref": "#/components/schemas/Slot" + }, + "max_gas_request": { + "type": "number" + }, + "params_size": { + "type": "number" + } + } + }, + "DeferredCallsQuoteResponse": { + "type": "object", + "required": [ + "target_slot", + "max_gas_request", + "available", + "price" + ], + "properties": { + "target_slot": { + "$ref": "#/components/schemas/Slot" + }, + "max_gas_request": { + "type": "number" + }, + "available": { + "type": "boolean" + }, + "price": { + "type": "number" + } + } + }, + "DeferredCallResponse": { + "type": "object", + "required": [ + "call_id", + "call" + ], + "properties": { + "call_id": { + "type": "string" + }, + "call": { + "$ref": "#/components/schemas/DeferredCall" + } + } + }, + "DeferredCallsSlotResponse": { + "type": "object", + "properties": { + "slot": { + "$ref": "#/components/schemas/Slot" + }, + "call_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "Denunciation": { "oneOf": [ { @@ -3310,6 +3526,7 @@ "required": [ "async_pool_changes", "executed_ops_changes", + "deferred_call_changes", "ledger_changes", "pos_changes", "executed_denunciations_changes", @@ -3336,6 +3553,10 @@ "description": "executed operations changes", "type": "object" }, + "deferred_call_changes": { + "description": "deferred call changes", + "type": "object" + }, "executed_denunciations_changes": { "description": "executed denunciation changes", "type": "object" diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 91385776f2c..dec4a7745e2 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -31,6 +31,7 @@ use massa_consensus_exports::{ use massa_consensus_worker::start_consensus_worker; use massa_db_exports::{MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_execution_exports::{ CondomLimits, ExecutionChannels, ExecutionConfig, ExecutionManager, GasCosts, @@ -59,21 +60,21 @@ use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::config::constants::{ ASYNC_MSG_CST_GAS_COST, BLOCK_REWARD, BOOTSTRAP_RANDOMNESS_SIZE_BYTES, CHANNEL_SIZE, - CONSENSUS_BOOTSTRAP_PART_SIZE, DELTA_F0, DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, - END_TIMESTAMP, GENESIS_KEY, GENESIS_TIMESTAMP, INITIAL_DRAW_SEED, LEDGER_COST_PER_BYTE, - LEDGER_ENTRY_BASE_COST, LEDGER_ENTRY_DATASTORE_BASE_SIZE, MAX_ADVERTISE_LENGTH, MAX_ASYNC_GAS, - MAX_ASYNC_POOL_LENGTH, MAX_BLOCK_SIZE, MAX_BOOTSTRAP_BLOCKS, MAX_BOOTSTRAP_ERROR_LENGTH, - MAX_BYTECODE_LENGTH, MAX_CONSENSUS_BLOCKS_IDS, MAX_DATASTORE_ENTRY_COUNT, - MAX_DATASTORE_KEY_LENGTH, MAX_DATASTORE_VALUE_LENGTH, MAX_DEFERRED_CREDITS_LENGTH, - MAX_DENUNCIATIONS_PER_BLOCK_HEADER, MAX_DENUNCIATION_CHANGES_LENGTH, - MAX_ENDORSEMENTS_PER_MESSAGE, MAX_EXECUTED_OPS_CHANGES_LENGTH, MAX_EXECUTED_OPS_LENGTH, - MAX_FUNCTION_NAME_LENGTH, MAX_GAS_PER_BLOCK, MAX_LEDGER_CHANGES_COUNT, MAX_LISTENERS_PER_PEER, - MAX_OPERATIONS_PER_BLOCK, MAX_OPERATIONS_PER_MESSAGE, MAX_OPERATION_DATASTORE_ENTRY_COUNT, - MAX_OPERATION_DATASTORE_KEY_LENGTH, MAX_OPERATION_DATASTORE_VALUE_LENGTH, - MAX_OPERATION_STORAGE_TIME, MAX_PARAMETERS_SIZE, MAX_PEERS_IN_ANNOUNCEMENT_LIST, - MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH, MAX_SIZE_CHANNEL_COMMANDS_CONNECTIVITY, - MAX_SIZE_CHANNEL_COMMANDS_PEERS, MAX_SIZE_CHANNEL_COMMANDS_PEER_TESTERS, - MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_BLOCKS, + CONSENSUS_BOOTSTRAP_PART_SIZE, DEFERRED_CALL_MAX_FUTURE_SLOTS, DELTA_F0, + DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, END_TIMESTAMP, GENESIS_KEY, GENESIS_TIMESTAMP, + INITIAL_DRAW_SEED, LEDGER_COST_PER_BYTE, LEDGER_ENTRY_BASE_COST, + LEDGER_ENTRY_DATASTORE_BASE_SIZE, MAX_ADVERTISE_LENGTH, MAX_ASYNC_GAS, MAX_ASYNC_POOL_LENGTH, + MAX_BLOCK_SIZE, MAX_BOOTSTRAP_BLOCKS, MAX_BOOTSTRAP_ERROR_LENGTH, MAX_BYTECODE_LENGTH, + MAX_CONSENSUS_BLOCKS_IDS, MAX_DATASTORE_ENTRY_COUNT, MAX_DATASTORE_KEY_LENGTH, + MAX_DATASTORE_VALUE_LENGTH, MAX_DEFERRED_CREDITS_LENGTH, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, + MAX_DENUNCIATION_CHANGES_LENGTH, MAX_ENDORSEMENTS_PER_MESSAGE, MAX_EXECUTED_OPS_CHANGES_LENGTH, + MAX_EXECUTED_OPS_LENGTH, MAX_FUNCTION_NAME_LENGTH, MAX_GAS_PER_BLOCK, MAX_LEDGER_CHANGES_COUNT, + MAX_LISTENERS_PER_PEER, MAX_OPERATIONS_PER_BLOCK, MAX_OPERATIONS_PER_MESSAGE, + MAX_OPERATION_DATASTORE_ENTRY_COUNT, MAX_OPERATION_DATASTORE_KEY_LENGTH, + MAX_OPERATION_DATASTORE_VALUE_LENGTH, MAX_OPERATION_STORAGE_TIME, MAX_PARAMETERS_SIZE, + MAX_PEERS_IN_ANNOUNCEMENT_LIST, MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH, + MAX_SIZE_CHANNEL_COMMANDS_CONNECTIVITY, MAX_SIZE_CHANNEL_COMMANDS_PEERS, + MAX_SIZE_CHANNEL_COMMANDS_PEER_TESTERS, MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_BLOCKS, MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_ENDORSEMENTS, MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_OPERATIONS, MAX_SIZE_CHANNEL_COMMANDS_RETRIEVAL_BLOCKS, MAX_SIZE_CHANNEL_COMMANDS_RETRIEVAL_ENDORSEMENTS, @@ -86,11 +87,15 @@ use massa_models::config::constants::{ VERSION, }; use massa_models::config::{ - BASE_OPERATION_GAS_COST, CHAINID, KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, - MAX_BOOTSTRAP_FINAL_STATE_PARTS_SIZE, MAX_BOOTSTRAP_VERSIONING_ELEMENTS_SIZE, - MAX_EVENT_DATA_SIZE, MAX_EVENT_PER_OPERATION, MAX_MESSAGE_SIZE, MAX_RECURSIVE_CALLS_DEPTH, - MAX_RUNTIME_MODULE_CUSTOM_SECTION_DATA_LEN, MAX_RUNTIME_MODULE_CUSTOM_SECTION_LEN, - MAX_RUNTIME_MODULE_EXPORTS, MAX_RUNTIME_MODULE_FUNCTIONS, MAX_RUNTIME_MODULE_FUNCTION_NAME_LEN, + BASE_OPERATION_GAS_COST, CHAINID, DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, + DEFERRED_CALL_CST_GAS_COST, DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + DEFERRED_CALL_MAX_ASYNC_GAS, DEFERRED_CALL_MAX_POOL_CHANGES, DEFERRED_CALL_MIN_GAS_COST, + DEFERRED_CALL_MIN_GAS_INCREMENT, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, + KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, MAX_BOOTSTRAP_FINAL_STATE_PARTS_SIZE, + MAX_BOOTSTRAP_VERSIONING_ELEMENTS_SIZE, MAX_EVENT_DATA_SIZE, MAX_EVENT_PER_OPERATION, + MAX_MESSAGE_SIZE, MAX_RECURSIVE_CALLS_DEPTH, MAX_RUNTIME_MODULE_CUSTOM_SECTION_DATA_LEN, + MAX_RUNTIME_MODULE_CUSTOM_SECTION_LEN, MAX_RUNTIME_MODULE_EXPORTS, + MAX_RUNTIME_MODULE_FUNCTIONS, MAX_RUNTIME_MODULE_FUNCTION_NAME_LEN, MAX_RUNTIME_MODULE_GLOBAL_INITIALIZER, MAX_RUNTIME_MODULE_IMPORTS, MAX_RUNTIME_MODULE_MEMORIES, MAX_RUNTIME_MODULE_NAME_LEN, MAX_RUNTIME_MODULE_PASSIVE_DATA, MAX_RUNTIME_MODULE_PASSIVE_ELEMENT, MAX_RUNTIME_MODULE_SIGNATURE_LEN, MAX_RUNTIME_MODULE_TABLE, @@ -197,9 +202,25 @@ async fn launch( endorsement_count: ENDORSEMENT_COUNT, keep_executed_history_extra_periods: KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, }; + let deferred_calls_config = DeferredCallsConfig { + thread_count: THREAD_COUNT, + max_function_name_length: MAX_FUNCTION_NAME_LENGTH, + max_parameter_size: MAX_PARAMETERS_SIZE, + max_pool_changes: DEFERRED_CALL_MAX_POOL_CHANGES, + max_gas: DEFERRED_CALL_MAX_ASYNC_GAS, + max_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, + base_fee_max_max_change_denominator: DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, + min_gas_increment: DEFERRED_CALL_MIN_GAS_INCREMENT, + min_gas_cost: DEFERRED_CALL_MIN_GAS_COST, + global_overbooking_penalty: DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + slot_overbooking_penalty: DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, + call_cst_gas_cost: DEFERRED_CALL_CST_GAS_COST, + ledger_cost_per_byte: LEDGER_COST_PER_BYTE, + }; let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), async_pool_config, + deferred_calls_config, pos_config, executed_ops_config, executed_denunciations_config, @@ -543,6 +564,7 @@ async fn launch( block_dump_folder_path, max_recursive_calls_depth: MAX_RECURSIVE_CALLS_DEPTH, condom_limits, + deferred_calls_config, max_event_per_operation: MAX_EVENT_PER_OPERATION, }; @@ -905,6 +927,7 @@ async fn launch( chain_id: *CHAINID, deferred_credits_delta: SETTINGS.api.deferred_credits_delta, minimal_fees: SETTINGS.pool.minimal_fees, + deferred_calls_config, }; // spawn Massa API diff --git a/massa-serialization/src/lib.rs b/massa-serialization/src/lib.rs index 46179b8f08c..5d06985663c 100644 --- a/massa-serialization/src/lib.rs +++ b/massa-serialization/src/lib.rs @@ -252,7 +252,8 @@ macro_rules! gen_varint { gen_varint! { u16, U16VarIntSerializer, u16_buffer, U16VarIntDeserializer, "`u16`"; u32, U32VarIntSerializer, u32_buffer, U32VarIntDeserializer, "`u32`"; -u64, U64VarIntSerializer, u64_buffer, U64VarIntDeserializer, "`u64`" +u64, U64VarIntSerializer, u64_buffer, U64VarIntDeserializer, "`u64`"; +u128, U128VarIntSerializer, u128_buffer, U128VarIntDeserializer, "`u128`" } #[derive(Clone)]