diff --git a/CHANGELOG.md b/CHANGELOG.md index 47aa8f63fa..26678dce37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - Implement user-facing bech32 encoding for `AccountId`s (#1185). - Implemented `execute_tx_view_script` procedure for the `TransactionExecutor` (#1197). - Enabled nested FPI calls (#1227). +- Implement `check_notes_consumability` procedure for the `TransactionExecutor` (#1269). ### Changes diff --git a/Cargo.lock b/Cargo.lock index 88dc4979d3..2269faf4ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,17 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.15", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.11" @@ -138,9 +127,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" dependencies = [ "backtrace", ] @@ -415,9 +404,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7" +checksum = "389a099b34312839e16420d499a9cad9650541715937ffbdd40d36f49e77eeb3" dependencies = [ "arrayref", "arrayvec", @@ -488,9 +477,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.17" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "jobserver", "libc", @@ -558,9 +547,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.32" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive 4.5.32", @@ -568,9 +557,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.32" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", @@ -682,7 +671,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.32", + "clap 4.5.36", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -711,9 +700,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -904,9 +893,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -944,9 +933,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "libz-ng-sys", @@ -1146,9 +1135,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "h2" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" dependencies = [ "atomic-waker", "bytes", @@ -1156,7 +1145,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.8.0", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -1165,9 +1154,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -1178,9 +1167,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" @@ -1352,9 +1338,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" dependencies = [ "bytes", "futures-channel", @@ -1362,6 +1348,7 @@ dependencies = [ "http", "http-body", "hyper", + "libc", "pin-project-lite", "socket2", "tokio", @@ -1410,9 +1397,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -1434,9 +1421,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -1455,9 +1442,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -1526,9 +1513,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1540,8 +1527,8 @@ version = "0.11.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88" dependencies = [ - "ahash 0.8.11", - "indexmap 2.8.0", + "ahash", + "indexmap 2.9.0", "is-terminal", "itoa", "log", @@ -1616,10 +1603,11 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] @@ -1721,9 +1709,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -1743,9 +1731,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "logos" @@ -1795,9 +1783,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198" dependencies = [ "hashbrown 0.15.2", ] @@ -1855,9 +1843,9 @@ dependencies = [ [[package]] name = "miden-air" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72269e041e915d6c34325a8906f08a8ff6ec9b92c79ae07f3a0de8c3588694b5" +checksum = "00e2e77c57ae798e02553af158c04d467f6479ab798a8c84459d343a89ff9c50" dependencies = [ "miden-core", "thiserror 2.0.12", @@ -1867,9 +1855,9 @@ dependencies = [ [[package]] name = "miden-assembly" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5680a0e75470389b65cc00900422ad7e1aa7972477c75ff88f63c3a01671e9" +checksum = "75d1cb02d807c2481f365feca966bedb74c66c765923d04c3c23ea678afaf148" dependencies = [ "aho-corasick", "lalrpop", @@ -1913,9 +1901,9 @@ dependencies = [ [[package]] name = "miden-core" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ba125a31e9ec0e732f47e639525c753973e553126cfc46cc63674049ea4134" +checksum = "d7d408e01421b5df2e4cfaf1a91efefe3fb5b729f1c99b668d3a69eec0044a6b" dependencies = [ "lock_api", "loom", @@ -2046,9 +2034,9 @@ dependencies = [ [[package]] name = "miden-processor" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5f362138a7bfe6c20246de651e848566843a0d5062cc4a7a8ebff6bd14668d" +checksum = "d4e70b053c587014396d06be3502e3952777923bee11729b7514c060fdc0d2c8" dependencies = [ "miden-air", "miden-core", @@ -2059,9 +2047,9 @@ dependencies = [ [[package]] name = "miden-prover" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6531711c8f3e25be9c607f82fc456594aba061acd3cde1df5d23eed88579340" +checksum = "2baa571449e7811e934dae919285dfea4854fb867f6d20d757d60b0601ef0140" dependencies = [ "miden-air", "miden-processor", @@ -2077,7 +2065,7 @@ dependencies = [ "async-trait", "axum 0.8.3", "bytes", - "clap 4.5.32", + "clap 4.5.36", "miden-block-prover", "miden-lib", "miden-objects", @@ -2135,9 +2123,9 @@ dependencies = [ [[package]] name = "miden-stdlib" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "116d30a8db5167f88944509007b8bb7aad4fa0d9d03f2610b4e80be3a198ad37" +checksum = "77e59c4dd1079bffe8407694b386ae781feaf1f7acb9d1cefa858578bc99cad4" dependencies = [ "miden-assembly", "miden-core", @@ -2181,9 +2169,9 @@ dependencies = [ [[package]] name = "miden-verifier" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ae6636d1e7a9d78a973fd59ffcfd87964eee235ecdf3264569add5ff89b0d91" +checksum = "20ae024b022569d7117891a83cf51ccd5bceeda248f30690b394a6dfc4607061" dependencies = [ "miden-air", "miden-core", @@ -2231,9 +2219,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -2417,9 +2405,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" @@ -2429,9 +2417,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ "bitflags 2.9.0", "cfg-if", @@ -2461,9 +2449,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", @@ -2473,9 +2461,9 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768ee97dc5cd695a4dd4a69a0678fb42789666b5a89e8c0af48bb06c6e427120" +checksum = "9e87237e2775f74896f9ad219d26a2081751187eb7c9f5c58dde20a23b95d16c" dependencies = [ "futures-core", "futures-sink", @@ -2617,7 +2605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap 2.8.0", + "indexmap 2.9.0", ] [[package]] @@ -2627,7 +2615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset 0.5.7", - "indexmap 2.8.0", + "indexmap 2.9.0", ] [[package]] @@ -2690,7 +2678,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35ee62f28526d8d484621e77f8d6a1807f1bd07558a06ab5a204b4834d6be056" dependencies = [ - "ahash 0.8.11", + "ahash", "async-trait", "blake2", "bytes", @@ -2725,7 +2713,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d123320b69bd06e897fc16bd1dde962a7b488c4d2ae825683fbca0198fad8669" dependencies = [ - "ahash 0.8.11", + "ahash", "async-trait", "brotli", "bytes", @@ -2816,7 +2804,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfcc8e3afeae5a83bbcd415d8d3bb50bea31d2eda2a91f79220b59abab86dd0f" dependencies = [ - "ahash 0.8.11", + "ahash", ] [[package]] @@ -2848,7 +2836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb50f65f06c4b81ccb3edcceaa54bb9439608506b0b3b8c048798169a64aad8e" dependencies = [ "arrayvec", - "hashbrown 0.12.3", + "hashbrown 0.15.2", "parking_lot", "rand 0.9.0", ] @@ -2990,9 +2978,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", "syn 2.0.100", @@ -3268,9 +3256,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags 2.9.0", ] @@ -3458,9 +3446,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.37.0" +version = "1.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c24af6e7ac43c88a8a458d1139d0246fdce2f6cd2f1ac6cb51eb88b29c978af" +checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" dependencies = [ "arrayvec", "num-traits", @@ -3505,22 +3493,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" dependencies = [ "once_cell", "rustls-pki-types", @@ -3546,9 +3534,9 @@ checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-webpki" -version = "0.103.0" +version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ "ring", "rustls-pki-types", @@ -3697,7 +3685,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "itoa", "memchr", "ryu", @@ -3764,7 +3752,7 @@ version = "0.9.4" source = "git+https://github.com/undef1nd/sfv.git?tag=v0.9.4#e6499d8ce11271dd0a4c1f72445775a58b835a56" dependencies = [ "data-encoding", - "indexmap 2.8.0", + "indexmap 2.9.0", "rust_decimal", ] @@ -3819,9 +3807,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "smawk" @@ -3831,9 +3819,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3859,9 +3847,9 @@ checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" [[package]] name = "string_cache" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", "parking_lot", @@ -3941,9 +3929,9 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "symbolic-common" -version = "12.14.1" +version = "12.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66135c8273581acaab470356f808a1c74a707fe7ec24728af019d7247e089e71" +checksum = "cb426702a1ee7c1d2ebf3b6fac2e67fde84f6d6396e581826e3f055d1bffb2a4" dependencies = [ "debugid", "memmap2", @@ -3953,9 +3941,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.14.1" +version = "12.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bcacd080282a72e795864660b148392af7babd75691d5ae9a3b77e29c98c77" +checksum = "d4671b7ae11875cb9c34348d2df6c5d1edd51f4c98ec45f591acb593ac8af8e0" dependencies = [ "rustc-demangle", "symbolic-common", @@ -4039,7 +4027,7 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -4079,7 +4067,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -4185,9 +4173,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -4296,7 +4284,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -5208,9 +5196,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" dependencies = [ "memchr", ] diff --git a/bin/bench-tx/bench-tx.json b/bin/bench-tx/bench-tx.json index ea7c983c3a..9937b335b4 100644 --- a/bin/bench-tx/bench-tx.json +++ b/bin/bench-tx/bench-tx.json @@ -1,21 +1,21 @@ { "simple": { - "prologue": 4378, - "notes_processing": 2310, + "prologue": 4380, + "notes_processing": 2307, "note_execution": { - "0x21b44377de8dd01d136a70800cb66bb08f0a2e7b70f77a8781fad1719baf145a": 1489, - "0xa7394456a1ba2808b1d27c6f91e9830ccd9d0e3e128bc5fcb632c74cca3d487b": 781 + "0x21b44377de8dd01d136a70800cb66bb08f0a2e7b70f77a8781fad1719baf145a": 1487, + "0xa7394456a1ba2808b1d27c6f91e9830ccd9d0e3e128bc5fcb632c74cca3d487b": 779 }, - "tx_script_processing": 46, - "epilogue": 2383 + "tx_script_processing": 45, + "epilogue": 2385 }, "p2id": { - "prologue": 2653, - "notes_processing": 1279, + "prologue": 2655, + "notes_processing": 1277, "note_execution": { - "0xce602ae68983c400dd1fb71154e6c752174da8809e8c107a0edff6a3a96618a4": 1246 + "0xce602ae68983c400dd1fb71154e6c752174da8809e8c107a0edff6a3a96618a4": 1244 }, - "tx_script_processing": 60872, - "epilogue": 430 + "tx_script_processing": 60871, + "epilogue": 432 } } \ No newline at end of file diff --git a/crates/miden-lib/asm/kernels/transaction/lib/account.masm b/crates/miden-lib/asm/kernels/transaction/lib/account.masm index 2f775f7d8d..031ba18ef8 100644 --- a/crates/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/crates/miden-lib/asm/kernels/transaction/lib/account.masm @@ -10,49 +10,49 @@ use.kernel::memory # ERRORS # ================================================================================================= -# Account nonce cannot be increased by a greater than u32 value +# Account nonce cannot be increased by a greater than u32 value. const.ERR_ACCOUNT_NONCE_INCREASE_MUST_BE_U32=0x0002014a -# Account code must be updatable for it to be possible to set new code +# Account code must be updatable for it to be possible to set new code. const.ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE=0x00020142 -# Anchor block commitment must not be empty +# Anchor block commitment must not be empty. const.ERR_ACCOUNT_ANCHOR_BLOCK_COMMITMENT_MUST_NOT_BE_EMPTY=0x00020140 -# ID of the new account does not match the ID computed from the seed and anchor block commitment +# ID of the new account does not match the ID computed from the seed and anchor block commitment. const.ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH=0x0002014e -# Failed to write an account value item to a non-value storage slot +# Failed to write an account value item to a non-value storage slot. const.ERR_ACCOUNT_SETTING_VALUE_ITEM_ON_NON_VALUE_SLOT=0x00020150 -# Failed to write an account map item to a non-map storage slot +# Failed to write an account map item to a non-map storage slot. const.ERR_ACCOUNT_SETTING_MAP_ITEM_ON_NON_MAP_SLOT=0x0002014f -# Account procedure is not part of the account code +# Account procedure is not part of the account code. const.ERR_ACCOUNT_PROC_NOT_PART_OF_ACCOUNT_CODE=0x0002014c -# Provided procedure index is out of bounds +# Provided procedure index is out of bounds. const.ERR_ACCOUNT_PROC_INDEX_OUT_OF_BOUNDS=0x0002014b -# Provided storage slot index is out of bounds +# Provided storage slot index is out of bounds. const.ERR_ACCOUNT_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS=0x00020152 -# Storage offset is invalid for a faucet account (0 is prohibited as it is the reserved data slot for faucets) +# Storage offset is invalid for a faucet account (0 is prohibited as it is the reserved data slot for faucets). const.ERR_FAUCET_INVALID_STORAGE_OFFSET=0x000201c2 -# Computed account code commitment does not match recorded account code commitment +# Computed account code commitment does not match recorded account code commitment. const.ERR_ACCOUNT_CODE_COMMITMENT_MISMATCH=0x00020141 -# Number of account procedures exceeds the maximum limit of 256 +# Number of account procedures exceeds the maximum limit of 256. const.ERR_ACCOUNT_TOO_MANY_PROCEDURES=0x00020153 -# Number of account storage slots exceeds the maximum limit of 255 +# Number of account storage slots exceeds the maximum limit of 255. const.ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS=0x00020154 -# Computed account storage commitment does not match recorded account storage commitment +# Computed account storage commitment does not match recorded account storage commitment. const.ERR_ACCOUNT_STORAGE_COMMITMENT_MISMATCH=0x00020151 -# Storage offset is invalid for 0 storage size (should be 0) +# Storage offset is invalid for 0 storage size (should be 0). const.ERR_ACCOUNT_INVALID_STORAGE_OFFSET_FOR_SIZE=0x00020147 # ID of the provided foreign account equals zero. @@ -73,7 +73,7 @@ const.ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX=0x00020143 # Unknown account storage mode in account ID. const.ERR_ACCOUNT_ID_UNKNOWN_STORAGE_MODE=0x00020145 -# Failed to read an account map item from a non-map storage slot +# Failed to read an account map item from a non-map storage slot. const.ERR_ACCOUNT_READING_MAP_VALUE_FROM_NON_MAP_SLOT=0x0002014d # CONSTANTS diff --git a/crates/miden-lib/asm/kernels/transaction/main.masm b/crates/miden-lib/asm/kernels/transaction/main.masm index dcafc98e7d..9924034756 100644 --- a/crates/miden-lib/asm/kernels/transaction/main.masm +++ b/crates/miden-lib/asm/kernels/transaction/main.masm @@ -5,33 +5,33 @@ use.kernel::memory use.kernel::note use.kernel::prologue -# TRACES +# EVENTS # ================================================================================================= -# Trace emitted to signal that an execution of the transaction prologue has started. -const.PROLOGUE_START=131072 -# Trace emitted to signal that an execution of the transaction prologue has ended. -const.PROLOGUE_END=131073 +# Event emitted to signal that an execution of the transaction prologue has started. +const.PROLOGUE_START=131088 +# Event emitted to signal that an execution of the transaction prologue has ended. +const.PROLOGUE_END=131089 -# Trace emitted to signal that the notes processing has started. -const.NOTES_PROCESSING_START=131074 -# Trace emitted to signal that the notes processing has ended. -const.NOTES_PROCESSING_END=131075 +# Event emitted to signal that the notes processing has started. +const.NOTES_PROCESSING_START=131090 +# Event emitted to signal that the notes processing has ended. +const.NOTES_PROCESSING_END=131091 -# Trace emitted to signal that the note consuming has started. -const.NOTE_EXECUTION_START=131076 -# Trace emitted to signal that the note consuming has ended. -const.NOTE_EXECUTION_END=131077 +# Event emitted to signal that the note consuming has started. +const.NOTE_EXECUTION_START=131092 +# Event emitted to signal that the note consuming has ended. +const.NOTE_EXECUTION_END=131093 -# Trace emitted to signal that the transaction script processing has started. -const.TX_SCRIPT_PROCESSING_START=131078 -# Trace emitted to signal that the transaction script processing has ended. -const.TX_SCRIPT_PROCESSING_END=131079 +# Event emitted to signal that the transaction script processing has started. +const.TX_SCRIPT_PROCESSING_START=131094 +# Event emitted to signal that the transaction script processing has ended. +const.TX_SCRIPT_PROCESSING_END=131095 -# Trace emitted to signal that an execution of the transaction epilogue has started. -const.EPILOGUE_START=131080 -# Trace emitted to signal that an execution of the transaction epilogue has ended. -const.EPILOGUE_END=131081 +# Event emitted to signal that an execution of the transaction epilogue has started. +const.EPILOGUE_START=131096 +# Event emitted to signal that an execution of the transaction epilogue has ended. +const.EPILOGUE_END=131097 # MAIN # ================================================================================================= @@ -67,23 +67,18 @@ const.EPILOGUE_END=131081 proc.main.1 # Prologue # --------------------------------------------------------------------------------------------- - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.91683607 drop - trace.PROLOGUE_START + + emit.PROLOGUE_START exec.prologue::prepare_transaction # => [] - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.3551582517 drop - trace.PROLOGUE_END + emit.PROLOGUE_END # Note Processing # --------------------------------------------------------------------------------------------- - - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.1597639019 drop - trace.NOTES_PROCESSING_START + + emit.NOTES_PROCESSING_START exec.memory::get_num_input_notes # => [num_input_notes] @@ -96,9 +91,7 @@ proc.main.1 # => [should_loop] while.true - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.1161965828 drop - trace.NOTE_EXECUTION_START + emit.NOTE_EXECUTION_START # => [] exec.note::prepare_note @@ -119,24 +112,18 @@ proc.main.1 loc_load.0 neq # => [should_loop] - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.1680624729 drop - trace.NOTE_EXECUTION_END + emit.NOTE_EXECUTION_END end exec.note::note_processing_teardown # => [] - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.920581323 drop - trace.NOTES_PROCESSING_END + emit.NOTES_PROCESSING_END # Transaction Script Processing # --------------------------------------------------------------------------------------------- - - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.4103684209 drop - trace.TX_SCRIPT_PROCESSING_START + + emit.TX_SCRIPT_PROCESSING_START # get the memory address of the transaction script root and load it to the stack exec.memory::get_tx_script_root_ptr @@ -160,16 +147,12 @@ proc.main.1 # => [] end - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.1155406220 drop - trace.TX_SCRIPT_PROCESSING_END + emit.TX_SCRIPT_PROCESSING_END # Epilogue # --------------------------------------------------------------------------------------------- - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.1887961092 drop - trace.EPILOGUE_START + emit.EPILOGUE_START # execute the transaction epilogue exec.epilogue::finalize_transaction @@ -178,9 +161,7 @@ proc.main.1 # truncate the stack movupw.3 dropw movupw.3 dropw movup.9 drop - # use `push.* drop` instructions before `trace` to make sure that MAST root will be unique - push.3456069754 drop - trace.EPILOGUE_END + emit.EPILOGUE_END # => [OUTPUT_NOTES_COMMITMENT, FINAL_ACCOUNT_COMMITMENT, tx_expiration_block_num] end diff --git a/crates/miden-lib/asm/shared/util/account_id.masm b/crates/miden-lib/asm/shared/util/account_id.masm index 23ffc4f38b..5481f8d5c6 100644 --- a/crates/miden-lib/asm/shared/util/account_id.masm +++ b/crates/miden-lib/asm/shared/util/account_id.masm @@ -13,7 +13,7 @@ const.ERR_ACCOUNT_ID_UNKNOWN_STORAGE_MODE=0x00020145 # Least significant byte of the account ID suffix must be zero. const.ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO=0x00020144 -# Provided storage slot index is out of bounds +# Provided storage slot index is out of bounds. const.ERR_ACCOUNT_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS=0x00020152 # The account ID must have storage mode public if the network flag is set. diff --git a/crates/miden-lib/build.rs b/crates/miden-lib/build.rs index 7aec2f3434..f2919b7aee 100644 --- a/crates/miden-lib/build.rs +++ b/crates/miden-lib/build.rs @@ -54,7 +54,7 @@ const TX_KERNEL_ERROR_CATEGORIES: [TxKernelErrorCategory; 11] = [ TxKernelErrorCategory::ForeignAccount, TxKernelErrorCategory::Faucet, TxKernelErrorCategory::FungibleAsset, - TxKernelErrorCategory::NonFugibleAsset, + TxKernelErrorCategory::NonFungibleAsset, TxKernelErrorCategory::Vault, ]; @@ -839,7 +839,7 @@ enum TxKernelErrorCategory { ForeignAccount, Faucet, FungibleAsset, - NonFugibleAsset, + NonFungibleAsset, Vault, } @@ -855,7 +855,7 @@ impl TxKernelErrorCategory { TxKernelErrorCategory::ForeignAccount => 0x2_0180..0x2_01c0, TxKernelErrorCategory::Faucet => 0x2_01c0..0x2_0200, TxKernelErrorCategory::FungibleAsset => 0x2_0200..0x2_0240, - TxKernelErrorCategory::NonFugibleAsset => 0x2_0240..0x2_0280, + TxKernelErrorCategory::NonFungibleAsset => 0x2_0240..0x2_0280, TxKernelErrorCategory::Vault => 0x2_0280..0x2_02c0, } } @@ -871,7 +871,7 @@ impl TxKernelErrorCategory { TxKernelErrorCategory::ForeignAccount => "FOREIGN_ACCOUNT", TxKernelErrorCategory::Faucet => "FAUCET", TxKernelErrorCategory::FungibleAsset => "FUNGIBLE_ASSET", - TxKernelErrorCategory::NonFugibleAsset => "NON_FUNGIBLE_ASSET", + TxKernelErrorCategory::NonFungibleAsset => "NON_FUNGIBLE_ASSET", TxKernelErrorCategory::Vault => "VAULT", } } diff --git a/crates/miden-lib/src/account/interface/mod.rs b/crates/miden-lib/src/account/interface/mod.rs index a8341de927..a71d9cdf2c 100644 --- a/crates/miden-lib/src/account/interface/mod.rs +++ b/crates/miden-lib/src/account/interface/mod.rs @@ -316,6 +316,8 @@ pub enum NoteAccountCompatibility { /// The account has all necessary procedures of one execution branch of the note script. This /// means the note may be able to be consumed by the account if that branch is executed. Maybe, + /// A note could be successfully executed and consumed by the account. + Yes, } // HELPER FUNCTIONS diff --git a/crates/miden-lib/src/errors/tx_kernel_errors.rs b/crates/miden-lib/src/errors/tx_kernel_errors.rs index fdb97674a4..b01f4db019 100644 --- a/crates/miden-lib/src/errors/tx_kernel_errors.rs +++ b/crates/miden-lib/src/errors/tx_kernel_errors.rs @@ -95,11 +95,11 @@ pub const ERR_NOTE_TAG_MUST_BE_U32: u32 = 0x20109; /// Network execution mode with a specific target can only target network accounts. pub const ERR_NOTE_NETWORK_EXECUTION_DOES_NOT_TARGET_NETWORK_ACCOUNT: u32 = 0x2010a; -/// Anchor block commitment must not be empty +/// Anchor block commitment must not be empty. pub const ERR_ACCOUNT_ANCHOR_BLOCK_COMMITMENT_MUST_NOT_BE_EMPTY: u32 = 0x20140; -/// Computed account code commitment does not match recorded account code commitment +/// Computed account code commitment does not match recorded account code commitment. pub const ERR_ACCOUNT_CODE_COMMITMENT_MISMATCH: u32 = 0x20141; -/// Account code must be updatable for it to be possible to set new code +/// Account code must be updatable for it to be possible to set new code. pub const ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE: u32 = 0x20142; /// Epoch must be less than u16::MAX (0xffff). pub const ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX: u32 = 0x20143; @@ -109,33 +109,33 @@ pub const ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO: u32 = 0x20144; pub const ERR_ACCOUNT_ID_UNKNOWN_STORAGE_MODE: u32 = 0x20145; /// Unknown version in account ID. pub const ERR_ACCOUNT_ID_UNKNOWN_VERSION: u32 = 0x20146; -/// Storage offset is invalid for 0 storage size (should be 0) +/// Storage offset is invalid for 0 storage size (should be 0). pub const ERR_ACCOUNT_INVALID_STORAGE_OFFSET_FOR_SIZE: u32 = 0x20147; /// The current account is not native pub const ERR_ACCOUNT_IS_NOT_NATIVE: u32 = 0x20148; /// Account nonce did not increase after a state changing transaction pub const ERR_ACCOUNT_NONCE_DID_NOT_INCREASE_AFTER_STATE_CHANGE: u32 = 0x20149; -/// Account nonce cannot be increased by a greater than u32 value +/// Account nonce cannot be increased by a greater than u32 value. pub const ERR_ACCOUNT_NONCE_INCREASE_MUST_BE_U32: u32 = 0x2014a; -/// Provided procedure index is out of bounds +/// Provided procedure index is out of bounds. pub const ERR_ACCOUNT_PROC_INDEX_OUT_OF_BOUNDS: u32 = 0x2014b; -/// Account procedure is not part of the account code +/// Account procedure is not part of the account code. pub const ERR_ACCOUNT_PROC_NOT_PART_OF_ACCOUNT_CODE: u32 = 0x2014c; -/// Failed to read an account map item from a non-map storage slot +/// Failed to read an account map item from a non-map storage slot. pub const ERR_ACCOUNT_READING_MAP_VALUE_FROM_NON_MAP_SLOT: u32 = 0x2014d; -/// ID of the new account does not match the ID computed from the seed and anchor block commitment +/// ID of the new account does not match the ID computed from the seed and anchor block commitment. pub const ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH: u32 = 0x2014e; -/// Failed to write an account map item to a non-map storage slot +/// Failed to write an account map item to a non-map storage slot. pub const ERR_ACCOUNT_SETTING_MAP_ITEM_ON_NON_MAP_SLOT: u32 = 0x2014f; -/// Failed to write an account value item to a non-value storage slot +/// Failed to write an account value item to a non-value storage slot. pub const ERR_ACCOUNT_SETTING_VALUE_ITEM_ON_NON_VALUE_SLOT: u32 = 0x20150; -/// Computed account storage commitment does not match recorded account storage commitment +/// Computed account storage commitment does not match recorded account storage commitment. pub const ERR_ACCOUNT_STORAGE_COMMITMENT_MISMATCH: u32 = 0x20151; -/// Provided storage slot index is out of bounds +/// Provided storage slot index is out of bounds. pub const ERR_ACCOUNT_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS: u32 = 0x20152; -/// Number of account procedures exceeds the maximum limit of 256 +/// Number of account procedures exceeds the maximum limit of 256. pub const ERR_ACCOUNT_TOO_MANY_PROCEDURES: u32 = 0x20153; -/// Number of account storage slots exceeds the maximum limit of 255 +/// Number of account storage slots exceeds the maximum limit of 255. pub const ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS: u32 = 0x20154; /// Depth of the nested FPI calls exceeded 64 pub const ERR_ACCOUNT_STACK_OVERFLOW: u32 = 0x20155; @@ -157,7 +157,7 @@ pub const ERR_FOREIGN_ACCOUNT_MAX_NUMBER_EXCEEDED: u32 = 0x20183; pub const ERR_FAUCET_BURN_CANNOT_EXCEED_EXISTING_TOTAL_SUPPLY: u32 = 0x201c0; /// The burn_non_fungible_asset procedure can only be called on a non-fungible faucet pub const ERR_FAUCET_BURN_NON_FUNGIBLE_ASSET_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET: u32 = 0x201c1; -/// Storage offset is invalid for a faucet account (0 is prohibited as it is the reserved data slot for faucets) +/// Storage offset is invalid for a faucet account (0 is prohibited as it is the reserved data slot for faucets). pub const ERR_FAUCET_INVALID_STORAGE_OFFSET: u32 = 0x201c2; /// The faucet_is_non_fungible_asset_issued procedure can only be called on a non-fungible faucet pub const ERR_FAUCET_IS_NF_ASSET_ISSUED_PROC_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET: u32 = 0x201c3; @@ -254,27 +254,27 @@ pub const TX_KERNEL_ERRORS: [(u32, &str); 90] = [ (ERR_NOTE_TAG_MUST_BE_U32, "The note's tag must fit into a u32 so the 32 most significant bits must be zero."), (ERR_NOTE_NETWORK_EXECUTION_DOES_NOT_TARGET_NETWORK_ACCOUNT, "Network execution mode with a specific target can only target network accounts."), - (ERR_ACCOUNT_ANCHOR_BLOCK_COMMITMENT_MUST_NOT_BE_EMPTY, "Anchor block commitment must not be empty"), - (ERR_ACCOUNT_CODE_COMMITMENT_MISMATCH, "Computed account code commitment does not match recorded account code commitment"), - (ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE, "Account code must be updatable for it to be possible to set new code"), + (ERR_ACCOUNT_ANCHOR_BLOCK_COMMITMENT_MUST_NOT_BE_EMPTY, "Anchor block commitment must not be empty."), + (ERR_ACCOUNT_CODE_COMMITMENT_MISMATCH, "Computed account code commitment does not match recorded account code commitment."), + (ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE, "Account code must be updatable for it to be possible to set new code."), (ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX, "Epoch must be less than u16::MAX (0xffff)."), (ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO, "Least significant byte of the account ID suffix must be zero."), (ERR_ACCOUNT_ID_UNKNOWN_STORAGE_MODE, "Unknown account storage mode in account ID."), (ERR_ACCOUNT_ID_UNKNOWN_VERSION, "Unknown version in account ID."), - (ERR_ACCOUNT_INVALID_STORAGE_OFFSET_FOR_SIZE, "Storage offset is invalid for 0 storage size (should be 0)"), + (ERR_ACCOUNT_INVALID_STORAGE_OFFSET_FOR_SIZE, "Storage offset is invalid for 0 storage size (should be 0)."), (ERR_ACCOUNT_IS_NOT_NATIVE, "The current account is not native"), (ERR_ACCOUNT_NONCE_DID_NOT_INCREASE_AFTER_STATE_CHANGE, "Account nonce did not increase after a state changing transaction"), - (ERR_ACCOUNT_NONCE_INCREASE_MUST_BE_U32, "Account nonce cannot be increased by a greater than u32 value"), - (ERR_ACCOUNT_PROC_INDEX_OUT_OF_BOUNDS, "Provided procedure index is out of bounds"), - (ERR_ACCOUNT_PROC_NOT_PART_OF_ACCOUNT_CODE, "Account procedure is not part of the account code"), - (ERR_ACCOUNT_READING_MAP_VALUE_FROM_NON_MAP_SLOT, "Failed to read an account map item from a non-map storage slot"), - (ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH, "ID of the new account does not match the ID computed from the seed and anchor block commitment"), - (ERR_ACCOUNT_SETTING_MAP_ITEM_ON_NON_MAP_SLOT, "Failed to write an account map item to a non-map storage slot"), - (ERR_ACCOUNT_SETTING_VALUE_ITEM_ON_NON_VALUE_SLOT, "Failed to write an account value item to a non-value storage slot"), - (ERR_ACCOUNT_STORAGE_COMMITMENT_MISMATCH, "Computed account storage commitment does not match recorded account storage commitment"), - (ERR_ACCOUNT_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS, "Provided storage slot index is out of bounds"), - (ERR_ACCOUNT_TOO_MANY_PROCEDURES, "Number of account procedures exceeds the maximum limit of 256"), - (ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS, "Number of account storage slots exceeds the maximum limit of 255"), + (ERR_ACCOUNT_NONCE_INCREASE_MUST_BE_U32, "Account nonce cannot be increased by a greater than u32 value."), + (ERR_ACCOUNT_PROC_INDEX_OUT_OF_BOUNDS, "Provided procedure index is out of bounds."), + (ERR_ACCOUNT_PROC_NOT_PART_OF_ACCOUNT_CODE, "Account procedure is not part of the account code."), + (ERR_ACCOUNT_READING_MAP_VALUE_FROM_NON_MAP_SLOT, "Failed to read an account map item from a non-map storage slot."), + (ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH, "ID of the new account does not match the ID computed from the seed and anchor block commitment."), + (ERR_ACCOUNT_SETTING_MAP_ITEM_ON_NON_MAP_SLOT, "Failed to write an account map item to a non-map storage slot."), + (ERR_ACCOUNT_SETTING_VALUE_ITEM_ON_NON_VALUE_SLOT, "Failed to write an account value item to a non-value storage slot."), + (ERR_ACCOUNT_STORAGE_COMMITMENT_MISMATCH, "Computed account storage commitment does not match recorded account storage commitment."), + (ERR_ACCOUNT_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS, "Provided storage slot index is out of bounds."), + (ERR_ACCOUNT_TOO_MANY_PROCEDURES, "Number of account procedures exceeds the maximum limit of 256."), + (ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS, "Number of account storage slots exceeds the maximum limit of 255."), (ERR_ACCOUNT_STACK_OVERFLOW, "Depth of the nested FPI calls exceeded 64"), (ERR_ACCOUNT_STACK_UNDERFLOW, "Failed to end foreign context because the current account is the native account"), (ERR_ACCOUNT_ID_NON_PUBLIC_NETWORK_ACCOUNT, "The account ID must have storage mode public if the network flag is set."), @@ -286,7 +286,7 @@ pub const TX_KERNEL_ERRORS: [(u32, &str); 90] = [ (ERR_FAUCET_BURN_CANNOT_EXCEED_EXISTING_TOTAL_SUPPLY, "Asset amount to burn can not exceed the existing total supply"), (ERR_FAUCET_BURN_NON_FUNGIBLE_ASSET_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET, "The burn_non_fungible_asset procedure can only be called on a non-fungible faucet"), - (ERR_FAUCET_INVALID_STORAGE_OFFSET, "Storage offset is invalid for a faucet account (0 is prohibited as it is the reserved data slot for faucets)"), + (ERR_FAUCET_INVALID_STORAGE_OFFSET, "Storage offset is invalid for a faucet account (0 is prohibited as it is the reserved data slot for faucets)."), (ERR_FAUCET_IS_NF_ASSET_ISSUED_PROC_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET, "The faucet_is_non_fungible_asset_issued procedure can only be called on a non-fungible faucet"), (ERR_FAUCET_NEW_TOTAL_SUPPLY_WOULD_EXCEED_MAX_ASSET_AMOUNT, "Asset mint operation would cause the new total supply to exceed the maximum allowed asset amount"), (ERR_FAUCET_NON_FUNGIBLE_ASSET_ALREADY_ISSUED, "Failed to mint new non-fungible asset because it was already issued"), diff --git a/crates/miden-lib/src/note/well_known_note.rs b/crates/miden-lib/src/note/well_known_note.rs index 93e6ea1a97..1ad1748e4b 100644 --- a/crates/miden-lib/src/note/well_known_note.rs +++ b/crates/miden-lib/src/note/well_known_note.rs @@ -1,6 +1,8 @@ use miden_objects::{ - Digest, + Digest, Felt, + account::AccountId, assembly::{ProcedureName, QualifiedProcedureName}, + block::BlockNumber, note::{Note, NoteScript}, utils::{Deserializable, sync::LazyLock}, vm::Program, @@ -8,7 +10,7 @@ use miden_objects::{ use crate::account::{ components::basic_wallet_library, - interface::{AccountComponentInterface, AccountInterface}, + interface::{AccountComponentInterface, AccountInterface, NoteAccountCompatibility}, }; // WELL KNOWN NOTE SCRIPTS @@ -76,6 +78,21 @@ pub enum WellKnownNote { } impl WellKnownNote { + // CONSTANTS + // -------------------------------------------------------------------------------------------- + + /// Expected number of inputs of the P2ID note. + const P2ID_NUM_INPUTS: usize = 2; + + /// Expected number of inputs of the P2IDR note. + const P2IDR_NUM_INPUTS: usize = 3; + + /// Expected number of inputs of the SWAP note. + const SWAP_NUM_INPUTS: usize = 10; + + // CONSTRUCTOR + // -------------------------------------------------------------------------------------------- + /// Returns a [WellKnownNote] instance based on the note script of the provided [Note]. Returns /// `None` if the provided note is not a basic well-known note. pub fn from_note(note: &Note) -> Option { @@ -94,6 +111,18 @@ impl WellKnownNote { None } + // PUBLIC ACCESSORS + // -------------------------------------------------------------------------------------------- + + /// Returns the expected inputs number of the current note. + pub fn num_expected_inputs(&self) -> usize { + match self { + Self::P2ID => Self::P2ID_NUM_INPUTS, + Self::P2IDR => Self::P2IDR_NUM_INPUTS, + Self::SWAP => Self::SWAP_NUM_INPUTS, + } + } + /// Returns the note script of the current [WellKnownNote] instance. pub fn script(&self) -> NoteScript { match self { @@ -145,4 +174,101 @@ impl WellKnownNote { }, } } + + /// Checks the correctness of the provided note inputs against the target account. + /// + /// It performs: + /// - for all notes: a check that note inputs have correct number of values. + /// - for `P2ID` note: assertion that the account ID provided by the note inputs is equal to the + /// target account ID. + /// - for `P2IDR` note: assertion that the account ID provided by the note inputs is equal to + /// the target account ID (which means that the note is going to be consumed by the target + /// account) or that the target account ID is equal to the sender account ID (which means that + /// the note is going to be consumed by the sender account) + pub fn check_note_inputs( + &self, + note: &Note, + target_account_id: AccountId, + block_ref: BlockNumber, + ) -> NoteAccountCompatibility { + match self { + WellKnownNote::P2ID => { + let note_inputs = note.inputs().values(); + if note_inputs.len() != self.num_expected_inputs() { + return NoteAccountCompatibility::No; + } + + // Return `No` if the note input values used to construct the account ID are invalid + let Some(input_account_id) = try_read_account_id_from_inputs(note_inputs) else { + return NoteAccountCompatibility::No; + }; + + // check that the account ID in the note inputs equal to the target account ID + if input_account_id == target_account_id { + NoteAccountCompatibility::Yes + } else { + NoteAccountCompatibility::No + } + }, + WellKnownNote::P2IDR => { + let note_inputs = note.inputs().values(); + if note_inputs.len() != self.num_expected_inputs() { + return NoteAccountCompatibility::No; + } + + let recall_height: Result = note_inputs[2].try_into(); + // Return `No` if the note input value which represents the recall height is invalid + let Ok(recall_height) = recall_height else { + return NoteAccountCompatibility::No; + }; + + // Return `No` if the note input values used to construct the account ID are invalid + let Some(input_account_id) = try_read_account_id_from_inputs(note_inputs) else { + return NoteAccountCompatibility::No; + }; + + if block_ref.as_u32() >= recall_height { + let sender_account_id = note.metadata().sender(); + // if the sender can already reclaim the assets back, then: + // - target account ID could be equal to the inputs account ID if the note is + // going to be consumed by the target account + // - target account ID could be equal to the sender account ID if the note is + // going to be consumed by the sender account + if [input_account_id, sender_account_id].contains(&target_account_id) { + NoteAccountCompatibility::Yes + } else { + NoteAccountCompatibility::No + } + } else { + // in this case note could be consumed only by the target account + if input_account_id == target_account_id { + NoteAccountCompatibility::Yes + } else { + NoteAccountCompatibility::No + } + } + }, + WellKnownNote::SWAP => { + if note.inputs().values().len() != self.num_expected_inputs() { + return NoteAccountCompatibility::No; + } + + NoteAccountCompatibility::Maybe + }, + } + } +} + +// HELPER FUNCTIONS +// ================================================================================================ + +/// Reads the account ID from the first two note input values. +/// +/// Returns None if the note input values used to construct the account ID are invalid. +fn try_read_account_id_from_inputs(note_inputs: &[Felt]) -> Option { + let account_id_felts: [Felt; 2] = note_inputs[0..2].try_into().expect( + "Should be able to convert the first two note inputs to an array of two Felt elements", + ); + + AccountId::try_from([account_id_felts[1], account_id_felts[0]]).ok() } diff --git a/crates/miden-lib/src/transaction/events.rs b/crates/miden-lib/src/transaction/events.rs index f3eccfa0bd..165459ec3d 100644 --- a/crates/miden-lib/src/transaction/events.rs +++ b/crates/miden-lib/src/transaction/events.rs @@ -1,6 +1,6 @@ use core::fmt; -use super::{TransactionEventError, TransactionTraceParsingError}; +use super::TransactionEventError; // CONSTANTS // ================================================================================================ @@ -33,6 +33,21 @@ const NOTE_AFTER_ADD_ASSET: u32 = 0x2_000e; // 131086 const FALCON_SIG_TO_STACK: u32 = 0x2_000f; // 131087 +const PROLOGUE_START: u32 = 0x2_0010; // 131088 +const PROLOGUE_END: u32 = 0x2_0011; // 131089 + +const NOTES_PROCESSING_START: u32 = 0x2_0012; // 131090 +const NOTES_PROCESSING_END: u32 = 0x2_0013; // 131091 + +const NOTE_EXECUTION_START: u32 = 0x2_0014; // 131092 +const NOTE_EXECUTION_END: u32 = 0x2_0015; // 131093 + +const TX_SCRIPT_PROCESSING_START: u32 = 0x2_0016; // 131094 +const TX_SCRIPT_PROCESSING_END: u32 = 0x2_0017; // 131095 + +const EPILOGUE_START: u32 = 0x2_0018; // 131096 +const EPILOGUE_END: u32 = 0x2_0019; // 131097 + /// Events which may be emitted by a transaction kernel. /// /// The events are emitted via the `emit.` instruction. The event ID is a 32-bit @@ -67,6 +82,21 @@ pub enum TransactionEvent { NoteAfterAddAsset = NOTE_AFTER_ADD_ASSET, FalconSigToStack = FALCON_SIG_TO_STACK, + + PrologueStart = PROLOGUE_START, + PrologueEnd = PROLOGUE_END, + + NotesProcessingStart = NOTES_PROCESSING_START, + NotesProcessingEnd = NOTES_PROCESSING_END, + + NoteExecutionStart = NOTE_EXECUTION_START, + NoteExecutionEnd = NOTE_EXECUTION_END, + + TxScriptProcessingStart = TX_SCRIPT_PROCESSING_START, + TxScriptProcessingEnd = TX_SCRIPT_PROCESSING_END, + + EpilogueStart = EPILOGUE_START, + EpilogueEnd = EPILOGUE_END, } impl TransactionEvent { @@ -120,55 +150,22 @@ impl TryFrom for TransactionEvent { FALCON_SIG_TO_STACK => Ok(TransactionEvent::FalconSigToStack), - _ => Err(TransactionEventError::InvalidTransactionEvent(value)), - } - } -} - -// TRANSACTION TRACE -// ================================================================================================ + PROLOGUE_START => Ok(TransactionEvent::PrologueStart), + PROLOGUE_END => Ok(TransactionEvent::PrologueEnd), -#[repr(u32)] -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum TransactionTrace { - PrologueStart = 0x2_0000, // 131072 - PrologueEnd = 0x2_0001, // 131073 - NotesProcessingStart = 0x2_0002, // 131074 - NotesProcessingEnd = 0x2_0003, // 131075 - NoteExecutionStart = 0x2_0004, // 131076 - NoteExecutionEnd = 0x2_0005, // 131077 - TxScriptProcessingStart = 0x2_0006, // 131078 - TxScriptProcessingEnd = 0x2_0007, // 131079 - EpilogueStart = 0x2_0008, // 131080 - EpilogueEnd = 0x2_0009, // 131081 -} + NOTES_PROCESSING_START => Ok(TransactionEvent::NotesProcessingStart), + NOTES_PROCESSING_END => Ok(TransactionEvent::NotesProcessingEnd), -impl fmt::Display for TransactionTrace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self:?}") - } -} + NOTE_EXECUTION_START => Ok(TransactionEvent::NoteExecutionStart), + NOTE_EXECUTION_END => Ok(TransactionEvent::NoteExecutionEnd), -impl TryFrom for TransactionTrace { - type Error = TransactionTraceParsingError; + TX_SCRIPT_PROCESSING_START => Ok(TransactionEvent::TxScriptProcessingStart), + TX_SCRIPT_PROCESSING_END => Ok(TransactionEvent::TxScriptProcessingEnd), - fn try_from(value: u32) -> Result { - if value >> 16 != TransactionEvent::ID_PREFIX { - return Err(TransactionTraceParsingError::UnknownTransactionTrace(value)); - } + EPILOGUE_START => Ok(TransactionEvent::EpilogueStart), + EPILOGUE_END => Ok(TransactionEvent::EpilogueEnd), - match value { - 0x2_0000 => Ok(TransactionTrace::PrologueStart), - 0x2_0001 => Ok(TransactionTrace::PrologueEnd), - 0x2_0002 => Ok(TransactionTrace::NotesProcessingStart), - 0x2_0003 => Ok(TransactionTrace::NotesProcessingEnd), - 0x2_0004 => Ok(TransactionTrace::NoteExecutionStart), - 0x2_0005 => Ok(TransactionTrace::NoteExecutionEnd), - 0x2_0006 => Ok(TransactionTrace::TxScriptProcessingStart), - 0x2_0007 => Ok(TransactionTrace::TxScriptProcessingEnd), - 0x2_0008 => Ok(TransactionTrace::EpilogueStart), - 0x2_0009 => Ok(TransactionTrace::EpilogueEnd), - _ => Err(TransactionTraceParsingError::UnknownTransactionTrace(value)), + _ => Err(TransactionEventError::InvalidTransactionEvent(value)), } } } diff --git a/crates/miden-lib/src/transaction/mod.rs b/crates/miden-lib/src/transaction/mod.rs index f6eefaaa47..5a410da2f8 100644 --- a/crates/miden-lib/src/transaction/mod.rs +++ b/crates/miden-lib/src/transaction/mod.rs @@ -20,7 +20,7 @@ use super::MidenLib; pub mod memory; mod events; -pub use events::{TransactionEvent, TransactionTrace}; +pub use events::TransactionEvent; mod inputs; diff --git a/crates/miden-tx/src/executor/mast_store.rs b/crates/miden-tx/src/executor/mast_store.rs deleted file mode 100644 index b9b3c79a9d..0000000000 --- a/crates/miden-tx/src/executor/mast_store.rs +++ /dev/null @@ -1,109 +0,0 @@ -use alloc::{collections::BTreeMap, sync::Arc}; - -use miden_lib::{MidenLib, StdLibrary, transaction::TransactionKernel, utils::sync::RwLock}; -use miden_objects::{ - Digest, - account::AccountCode, - assembly::mast::MastForest, - transaction::{InputNote, InputNotes, TransactionArgs}, -}; -use vm_processor::MastForestStore; - -// TRANSACTION MAST STORE -// ================================================================================================ - -/// A store for the code available during transaction execution. -/// -/// Transaction MAST store contains a map between procedure MAST roots and [MastForest]s containing -/// MASTs for these procedures. The VM will request [MastForest]s from the store when it encounters -/// a procedure which it doesn't have the code for. Thus, to execute a program which makes -/// references to external procedures, the store must be loaded with [MastForest]s containing these -/// procedures. -pub struct TransactionMastStore { - mast_forests: RwLock>>, -} - -#[allow(clippy::new_without_default)] -impl TransactionMastStore { - /// Returns a new [TransactionMastStore] instantiated with the default libraries. - /// - /// The default libraries include: - /// - Miden standard library (miden-stdlib). - /// - Miden rollup library (miden-lib). - /// - Transaction kernel. - pub fn new() -> Self { - let mast_forests = RwLock::new(BTreeMap::new()); - let store = Self { mast_forests }; - - // load transaction kernel MAST forest - let kernels_forest = TransactionKernel::kernel().mast_forest().clone(); - store.insert(kernels_forest); - - // load miden-stdlib MAST forest - let miden_stdlib_forest = StdLibrary::default().mast_forest().clone(); - store.insert(miden_stdlib_forest); - - // load miden lib MAST forest - let miden_lib_forest = MidenLib::default().mast_forest().clone(); - store.insert(miden_lib_forest); - - store - } - - /// Loads the provided account code into this store. - pub fn load_account_code(&self, code: &AccountCode) { - self.insert(code.mast().clone()); - } - - /// Loads code required for executing a transaction with the specified inputs and args into - /// this store. - /// - /// The loaded code includes: - /// - Account code for the account specified from the provided [AccountCode]. - /// - Note scripts for all input notes in the provided [InputNotes]. - /// - Transaction script (if any) from the specified [TransactionArgs]. - /// - Foreign account code (if any) from the specified [TransactionArgs]. - pub fn load_transaction_code( - &self, - account_code: &AccountCode, - input_notes: &InputNotes, - tx_args: &TransactionArgs, - ) { - // load account code - self.load_account_code(account_code); - - // load note script MAST into the MAST store - for note in input_notes { - self.insert(note.note().script().mast().clone()); - } - - // load foreign account's MAST forests - for foreign_account in tx_args.foreign_accounts() { - self.load_account_code(foreign_account.account_code()); - } - - // load tx script MAST into the MAST store - if let Some(tx_script) = tx_args.tx_script() { - self.insert(tx_script.mast().clone()); - } - } - - /// Registers all procedures of the provided [MastForest] with this store. - pub fn insert(&self, mast_forest: Arc) { - let mut mast_forests = self.mast_forests.write(); - - // only register procedures that are local to this forest - for proc_digest in mast_forest.local_procedure_digests() { - mast_forests.insert(proc_digest, mast_forest.clone()); - } - } -} - -// MAST FOREST STORE IMPLEMENTATION -// ================================================================================================ - -impl MastForestStore for TransactionMastStore { - fn get(&self, procedure_root: &Digest) -> Option> { - self.mast_forests.read().get(procedure_root).cloned() - } -} diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index 8ded1775b3..c89b421ec4 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -5,14 +5,14 @@ use miden_objects::{ Felt, MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES, ZERO, account::AccountId, block::{BlockHeader, BlockNumber}, + note::NoteId, transaction::{ ExecutedTransaction, ForeignAccountInputs, InputNote, InputNotes, TransactionArgs, TransactionInputs, TransactionScript, }, vm::StackOutputs, }; -pub use vm_processor::MastForestStore; -use vm_processor::{AdviceInputs, ExecutionOptions, Process, RecAdviceProvider}; +use vm_processor::{AdviceInputs, ExecutionOptions, MemAdviceProvider, Process, RecAdviceProvider}; use winter_maybe_async::{maybe_async, maybe_await}; use super::{TransactionExecutorError, TransactionHost}; @@ -21,6 +21,9 @@ use crate::auth::TransactionAuthenticator; mod data_store; pub use data_store::DataStore; +mod notes_checker; +pub use notes_checker::{NoteConsumptionChecker, NoteInputsCheck}; + // TRANSACTION EXECUTOR // ================================================================================================ @@ -108,21 +111,7 @@ impl TransactionExecutor { notes: InputNotes, tx_args: TransactionArgs, ) -> Result { - // Validate that notes were not created after the reference, and build the set of required - // block numbers - let mut ref_blocks: BTreeSet = BTreeSet::new(); - for note in ¬es { - if let Some(location) = note.location() { - if location.block_num() > block_ref { - return Err(TransactionExecutorError::NoteBlockPastReferenceBlock( - note.id(), - block_ref, - )); - } - ref_blocks.insert(location.block_num()); - } - } - + let mut ref_blocks = validate_input_notes(¬es, block_ref)?; ref_blocks.insert(block_ref); let (account, seed, ref_block, mmr) = @@ -222,6 +211,92 @@ impl TransactionExecutor { Ok(*stack_outputs) } + + // CHECK CONSUMABILITY + // ============================================================================================ + + /// Executes the transaction with specified notes, returning the [NoteAccountExecution::Success] + /// if all notes has been consumed successfully and [NoteAccountExecution::Failure] if some note + /// returned an error. + /// + /// # Errors: + /// Returns an error if: + /// - If required data can not be fetched from the [DataStore]. + /// - If the transaction host can not be created from the provided values. + /// - If the execution of the provided program fails on the stage other than note execution. + #[maybe_async] + pub(crate) fn try_execute_notes( + &self, + account_id: AccountId, + block_ref: BlockNumber, + notes: InputNotes, + tx_args: TransactionArgs, + ) -> Result { + let mut ref_blocks = validate_input_notes(¬es, block_ref)?; + ref_blocks.insert(block_ref); + + let (account, seed, ref_block, mmr) = + maybe_await!(self.data_store.get_transaction_inputs(account_id, ref_blocks)) + .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + + validate_account_inputs(&tx_args, &ref_block)?; + + let tx_inputs = TransactionInputs::new(account, seed, ref_block, mmr, notes) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; + + let (stack_inputs, advice_inputs) = + TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, None) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; + + let advice_provider: MemAdviceProvider = advice_inputs.into(); + + let mut host = TransactionHost::new( + tx_inputs.account().into(), + advice_provider, + self.data_store.clone(), + self.authenticator.clone(), + tx_args.foreign_account_code_commitments(), + ) + .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; + + // execute the transaction kernel + let result = vm_processor::execute( + &TransactionKernel::main(), + stack_inputs, + &mut host, + self.exec_options, + ) + .map_err(TransactionExecutorError::TransactionProgramExecutionFailed); + + match result { + Ok(_) => Ok(NoteAccountExecution::Success), + Err(tx_execution_error) => { + let notes = host.tx_progress().note_execution(); + + // empty notes vector means that we didn't process the notes, so an error + // occurred somewhere else + if notes.is_empty() { + return Err(tx_execution_error); + } + + let ((last_note, last_note_interval), success_notes) = notes + .split_last() + .expect("notes vector should not be empty because we just checked"); + + // if the interval end of the last note is specified, then an error occurred after + // notes processing + if last_note_interval.end().is_some() { + return Err(tx_execution_error); + } + + Ok(NoteAccountExecution::Failure { + failed_note_id: *last_note, + successful_notes: success_notes.iter().map(|(note, _)| *note).collect(), + error: Some(tx_execution_error), + }) + }, + } + } } // HELPER FUNCTIONS @@ -301,3 +376,46 @@ fn validate_account_inputs( } Ok(()) } + +/// Validates that input notes were not created after the reference block. +/// +/// Returns the set of block numbers required to execute the provided notes. +fn validate_input_notes( + notes: &InputNotes, + block_ref: BlockNumber, +) -> Result, TransactionExecutorError> { + // Validate that notes were not created after the reference, and build the set of required + // block numbers + let mut ref_blocks: BTreeSet = BTreeSet::new(); + for note in notes.iter() { + if let Some(location) = note.location() { + if location.block_num() > block_ref { + return Err(TransactionExecutorError::NoteBlockPastReferenceBlock( + note.id(), + block_ref, + )); + } + ref_blocks.insert(location.block_num()); + } + } + + Ok(ref_blocks) +} + +// HELPER ENUM +// ================================================================================================ + +/// Describes whether a transaction with a specified set of notes could be executed against target +/// account. +/// +/// [NoteAccountExecution::Failure] holds data for error handling: `failing_note_id` is an ID of a +/// failing note and `successful_notes` is a vector of note IDs which were successfully executed. +#[derive(Debug)] +pub enum NoteAccountExecution { + Success, + Failure { + failed_note_id: NoteId, + successful_notes: Vec, + error: Option, + }, +} diff --git a/crates/miden-tx/src/executor/notes_checker.rs b/crates/miden-tx/src/executor/notes_checker.rs new file mode 100644 index 0000000000..9e214739be --- /dev/null +++ b/crates/miden-tx/src/executor/notes_checker.rs @@ -0,0 +1,103 @@ +use miden_lib::{ + account::interface::NoteAccountCompatibility, note::well_known_note::WellKnownNote, +}; +use miden_objects::{ + account::AccountId, + block::BlockNumber, + note::NoteId, + transaction::{InputNote, InputNotes, TransactionArgs}, +}; +use winter_maybe_async::{maybe_async, maybe_await}; + +use super::{NoteAccountExecution, TransactionExecutor, TransactionExecutorError}; + +/// This struct performs input notes check against provided target account. +/// +/// The check is performed using the [NoteConsumptionChecker::check_notes_consumability] procedure. +/// Essentially runs the transaction to make sure that provided input notes could be consumed by the +/// account. +pub struct NoteConsumptionChecker<'a>(&'a TransactionExecutor); + +impl<'a> NoteConsumptionChecker<'a> { + /// Creates a new [`NoteConsumptionChecker`] instance with the given transaction executor. + pub fn new(tx_executor: &'a TransactionExecutor) -> Self { + NoteConsumptionChecker(tx_executor) + } + + /// Checks whether the provided input notes could be consumed by the provided account. + /// + /// This check consists of two main steps: + /// - Statically check the notes: if all notes are either `P2ID` or `P2IDR` notes with correct + /// inputs, return `NoteAccountExecution::Success`. + /// - Execute the transaction: + /// - Returns `NoteAccountExecution::Success` if the execution was successful. + /// - Returns `NoteAccountExecution::Failure` if some note returned an error. The fields + /// associated with `Failure` variant contains the ID of the failed note, a vector of IDs of + /// the notes, which were successfully executed, and the [TransactionExecutorError] if the + /// check failed durning the execution stage. + #[maybe_async] + pub fn check_notes_consumability( + &self, + target_account_id: AccountId, + block_ref: BlockNumber, + input_notes: InputNotes, + tx_args: TransactionArgs, + ) -> Result { + // Check input notes + // ---------------------------------------------------------------------------------------- + + let mut successful_notes = vec![]; + for note in input_notes.iter() { + if let Some(well_known_note) = WellKnownNote::from_note(note.note()) { + if let WellKnownNote::SWAP = well_known_note { + // if we encountered a SWAP note, then we have to execute the transaction + // anyway, but we should continue iterating to make sure that there are no + // P2ID(R) notes which return a `No` + continue; + } + + match well_known_note.check_note_inputs(note.note(), target_account_id, block_ref) { + NoteAccountCompatibility::No => { + // if the check failed, return a `Failure` with the vector of successfully + // checked `P2ID` and `P2IDR` notes + return Ok(NoteAccountExecution::Failure { + failed_note_id: note.id(), + successful_notes, + error: None, + }); + }, + // this branch is unreachable, since we are handling the SWAP note separately, + // but as an extra precaution continue iterating over the notes and run the + // transaction to make sure the note which returned "Maybe" could be consumed + NoteAccountCompatibility::Maybe => continue, + NoteAccountCompatibility::Yes => { + // put the successfully checked `P2ID` or `P2IDR` note to the vector + successful_notes.push(note.id()); + }, + } + } else { + // if we encountered not a well known note, then we have to execute the transaction + // anyway, but we should continue iterating to make sure that there are no + // P2ID(R) notes which return a `No` + continue; + } + } + + // if all checked notes turned out to be either `P2ID` or `P2IDR` notes and all of them + // passed, then we could safely return the `Success` + if successful_notes.len() == input_notes.num_notes() { + return Ok(NoteAccountExecution::Success); + } + + // Execute transaction + // ---------------------------------------------------------------------------------------- + maybe_await!(self.0.try_execute_notes(target_account_id, block_ref, input_notes, tx_args)) + } +} + +/// Helper enum for getting a result of the well known note inputs check. +#[derive(Debug, PartialEq)] +pub enum NoteInputsCheck { + Maybe, + No { failed_note_id: NoteId }, +} diff --git a/crates/miden-tx/src/host/mod.rs b/crates/miden-tx/src/host/mod.rs index 55ff6776f2..56c4e8fe51 100644 --- a/crates/miden-tx/src/host/mod.rs +++ b/crates/miden-tx/src/host/mod.rs @@ -9,7 +9,7 @@ use alloc::{ use miden_lib::{ errors::tx_kernel_errors::TX_KERNEL_ERRORS, transaction::{ - TransactionEvent, TransactionEventError, TransactionKernelError, TransactionTrace, + TransactionEvent, TransactionEventError, TransactionKernelError, memory::{CURRENT_INPUT_NOTE_PTR, NATIVE_NUM_ACCT_STORAGE_SLOTS_PTR}, }, }; @@ -535,34 +535,56 @@ impl Host for TransactionHost { TransactionEvent::NoteAfterAddAsset => Ok(()), TransactionEvent::FalconSigToStack => self.on_signature_requested(process), - } - .map_err(|err| ExecutionError::EventError(Box::new(err)))?; - Ok(()) - } + TransactionEvent::PrologueStart => { + self.tx_progress.start_prologue(process.clk()); + Ok(()) + }, + TransactionEvent::PrologueEnd => { + self.tx_progress.end_prologue(process.clk()); + Ok(()) + }, - fn on_trace(&mut self, process: ProcessState, trace_id: u32) -> Result<(), ExecutionError> { - let event = TransactionTrace::try_from(trace_id) - .map_err(|err| ExecutionError::EventError(Box::new(err)))?; + TransactionEvent::NotesProcessingStart => { + self.tx_progress.start_notes_processing(process.clk()); + Ok(()) + }, + TransactionEvent::NotesProcessingEnd => { + self.tx_progress.end_notes_processing(process.clk()); + Ok(()) + }, - use TransactionTrace::*; - match event { - PrologueStart => self.tx_progress.start_prologue(process.clk()), - PrologueEnd => self.tx_progress.end_prologue(process.clk()), - NotesProcessingStart => self.tx_progress.start_notes_processing(process.clk()), - NotesProcessingEnd => self.tx_progress.end_notes_processing(process.clk()), - NoteExecutionStart => { + TransactionEvent::NoteExecutionStart => { let note_id = Self::get_current_note_id(process)?.expect( "Note execution interval measurement is incorrect: check the placement of the start and the end of the interval", ); self.tx_progress.start_note_execution(process.clk(), note_id); + Ok(()) }, - NoteExecutionEnd => self.tx_progress.end_note_execution(process.clk()), - TxScriptProcessingStart => self.tx_progress.start_tx_script_processing(process.clk()), - TxScriptProcessingEnd => self.tx_progress.end_tx_script_processing(process.clk()), - EpilogueStart => self.tx_progress.start_epilogue(process.clk()), - EpilogueEnd => self.tx_progress.end_epilogue(process.clk()), + TransactionEvent::NoteExecutionEnd => { + self.tx_progress.end_note_execution(process.clk()); + Ok(()) + }, + + TransactionEvent::TxScriptProcessingStart => { + self.tx_progress.start_tx_script_processing(process.clk()); + Ok(()) + } + TransactionEvent::TxScriptProcessingEnd => { + self.tx_progress.end_tx_script_processing(process.clk()); + Ok(()) + } + + TransactionEvent::EpilogueStart => { + self.tx_progress.start_epilogue(process.clk()); + Ok(()) + } + TransactionEvent::EpilogueEnd => { + self.tx_progress.end_epilogue(process.clk()); + Ok(()) + } } + .map_err(|err| ExecutionError::EventError(Box::new(err)))?; Ok(()) } diff --git a/crates/miden-tx/src/host/tx_progress.rs b/crates/miden-tx/src/host/tx_progress.rs index 3ef9c170e9..1c7fe2d62a 100644 --- a/crates/miden-tx/src/host/tx_progress.rs +++ b/crates/miden-tx/src/host/tx_progress.rs @@ -132,6 +132,14 @@ impl CycleInterval { self.end = Some(e); } + pub fn start(&self) -> Option { + self.start + } + + pub fn end(&self) -> Option { + self.end + } + /// Calculate the length of the interval pub fn len(&self) -> usize { if let Some(start) = self.start { diff --git a/crates/miden-tx/src/lib.rs b/crates/miden-tx/src/lib.rs index a612f8ea9a..ec6e49ded8 100644 --- a/crates/miden-tx/src/lib.rs +++ b/crates/miden-tx/src/lib.rs @@ -9,7 +9,7 @@ extern crate std; pub use miden_objects::transaction::TransactionInputs; mod executor; -pub use executor::{DataStore, MastForestStore, TransactionExecutor}; +pub use executor::{DataStore, NoteConsumptionChecker, NoteInputsCheck, TransactionExecutor}; pub mod host; pub use host::{TransactionHost, TransactionProgress}; diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index dd98fb7671..fe5ecd2a47 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -246,7 +246,7 @@ impl TransactionContextBuilder { .unwrap() } - /// Adds one input note with a note script that creates another ouput note. + /// Adds one input note with a note script that creates another output note. fn input_note_with_one_output_note( &mut self, sender: AccountId, @@ -300,7 +300,7 @@ impl TransactionContextBuilder { .unwrap() } - /// Adds one input note with a note script that creates 2 ouput notes. + /// Adds one input note with a note script that creates 2 output notes. fn input_note_with_two_output_notes( &mut self, sender: AccountId, diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index 3d727110ca..9cd86f9831 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -9,12 +9,18 @@ use ::assembly::{ LibraryPath, ast::{Module, ModuleKind}, }; -use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; +use assert_matches::assert_matches; +use miden_lib::{ + note::{create_p2id_note, create_p2idr_note}, + transaction::TransactionKernel, + utils::word_to_masm_push_string, +}; use miden_objects::{ Felt, FieldElement, MIN_PROOF_SECURITY_LEVEL, Word, - account::{Account, AccountBuilder, AccountComponent, AccountStorage, StorageSlot}, + account::{Account, AccountBuilder, AccountComponent, AccountId, AccountStorage, StorageSlot}, assembly::DefaultSourceManager, asset::{Asset, AssetVault, FungibleAsset, NonFungibleAsset}, + block::BlockNumber, note::{ Note, NoteAssets, NoteExecutionHint, NoteExecutionMode, NoteHeader, NoteId, NoteInputs, NoteMetadata, NoteRecipient, NoteScript, NoteTag, NoteType, @@ -24,10 +30,10 @@ use miden_objects::{ account_id::{ ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, ACCOUNT_ID_SENDER, }, constants::{FUNGIBLE_ASSET_AMOUNT, NON_FUNGIBLE_ASSET_DATA}, - note::DEFAULT_NOTE_CODE, + note::{DEFAULT_NOTE_CODE, NoteBuilder}, storage::{STORAGE_INDEX_0, STORAGE_INDEX_2}, }, transaction::{OutputNote, ProvenTransaction, TransactionScript}, @@ -36,7 +42,8 @@ use miden_prover::ProvingOptions; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use vm_processor::{ - Digest, MemAdviceProvider, ONE, + Digest, ExecutionError, MemAdviceProvider, ONE, + crypto::RpoRandomCoin, utils::{Deserializable, Serializable}, }; @@ -44,7 +51,11 @@ use super::{ LocalTransactionProver, TransactionExecutor, TransactionHost, TransactionProver, TransactionVerifier, }; -use crate::{TransactionMastStore, testing::TransactionContextBuilder}; +use crate::{ + TransactionExecutorError, TransactionMastStore, + executor::{NoteAccountExecution, NoteConsumptionChecker}, + testing::TransactionContextBuilder, +}; mod kernel_tests; @@ -956,3 +967,118 @@ fn test_execute_program() { assert_eq!(stack_outputs[..3], [Felt::new(7), Felt::new(2), ONE]); } + +#[test] +fn test_check_note_consumability() { + // Success (well known notes) + // -------------------------------------------------------------------------------------------- + let p2id_note = create_p2id_note( + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into().unwrap(), + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), + vec![FungibleAsset::mock(10)], + NoteType::Public, + Default::default(), + &mut RpoRandomCoin::new([ONE, Felt::new(2), Felt::new(3), Felt::new(4)]), + ) + .unwrap(); + + let p2idr_note = create_p2idr_note( + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into().unwrap(), + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), + vec![FungibleAsset::mock(10)], + NoteType::Public, + Default::default(), + BlockNumber::default(), + &mut RpoRandomCoin::new([ONE, Felt::new(2), Felt::new(3), Felt::new(4)]), + ) + .unwrap(); + + let tx_context = TransactionContextBuilder::with_standard_account(ONE) + .input_notes(vec![p2id_note, p2idr_note]) + .build(); + + let input_notes = tx_context.input_notes().clone(); + let target_account_id = tx_context.account().id(); + let block_ref = tx_context.tx_inputs().block_header().block_num(); + let tx_args = tx_context.tx_args().clone(); + + let executor: TransactionExecutor = + TransactionExecutor::new(Arc::new(tx_context), None).with_tracing(); + let notes_checker = NoteConsumptionChecker::new(&executor); + + let execution_check_result = notes_checker + .check_notes_consumability(target_account_id, block_ref, input_notes, tx_args) + .unwrap(); + assert_matches!(execution_check_result, NoteAccountExecution::Success); + + // Success (custom notes) + // -------------------------------------------------------------------------------------------- + let tx_context = TransactionContextBuilder::with_standard_account(ONE) + .with_mock_notes_preserved() + .build(); + + let input_notes = tx_context.input_notes().clone(); + let account_id = tx_context.account().id(); + let block_ref = tx_context.tx_inputs().block_header().block_num(); + let tx_args = tx_context.tx_args().clone(); + + let executor: TransactionExecutor = + TransactionExecutor::new(Arc::new(tx_context), None).with_tracing(); + let notes_checker = NoteConsumptionChecker::new(&executor); + + let execution_check_result = notes_checker + .check_notes_consumability(account_id, block_ref, input_notes, tx_args) + .unwrap(); + assert_matches!(execution_check_result, NoteAccountExecution::Success); + + // Failure + // -------------------------------------------------------------------------------------------- + let sender = AccountId::try_from(ACCOUNT_ID_SENDER).unwrap(); + + let failing_note_1 = NoteBuilder::new( + sender, + ChaCha20Rng::from_seed(ChaCha20Rng::from_seed([0_u8; 32]).random()), + ) + .code("begin push.1 drop push.0 div end") + .build(&TransactionKernel::testing_assembler()) + .unwrap(); + + let failing_note_2 = NoteBuilder::new( + sender, + ChaCha20Rng::from_seed(ChaCha20Rng::from_seed([0_u8; 32]).random()), + ) + .code("begin push.2 drop push.0 div end") + .build(&TransactionKernel::testing_assembler()) + .unwrap(); + + let tx_context = TransactionContextBuilder::with_standard_account(ONE) + .with_mock_notes_preserved() + .input_notes(vec![failing_note_1, failing_note_2.clone()]) + .build(); + + let input_notes = tx_context.input_notes().clone(); + let input_note_ids = + input_notes.iter().map(|input_note| input_note.id()).collect::>(); + let account_id = tx_context.account().id(); + let block_ref = tx_context.tx_inputs().block_header().block_num(); + let tx_args = tx_context.tx_args().clone(); + + let executor: TransactionExecutor = + TransactionExecutor::new(Arc::new(tx_context), None).with_tracing(); + let notes_checker = NoteConsumptionChecker::new(&executor); + + // let notes_checker = NoteConsumptionChecker::new(account_id, input_notes.clone().into_vec()); + let execution_check_result = notes_checker + .check_notes_consumability(account_id, block_ref, input_notes, tx_args) + .unwrap(); + + assert_matches!(execution_check_result, NoteAccountExecution::Failure { + failed_note_id, + successful_notes, + error: Some(e)} => { + assert_eq!(failed_note_id, failing_note_2.id()); + assert_eq!(successful_notes, input_note_ids[..2].to_vec()); + assert_matches!(e, TransactionExecutorError::TransactionProgramExecutionFailed(ExecutionError::DivideByZero(_))); + } + ); +}