diff --git a/CHANGELOG.md b/CHANGELOG.md index 7da924941e..13555510ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,18 +7,28 @@ * [BREAKING][type][rust] `rpc::domain::transaction::TransactionRecord` gained a non-public field, so it can no longer be constructed with a struct literal outside the crate ([#2300](https://github.com/0xMiden/rust-sdk/pull/2300)). * [BREAKING][rust] `StateSyncUpdate` is now immutable once built: its `block_num`, `partial_blockchain_updates`, `note_updates`, `transaction_updates` and `account_updates` fields are private and it no longer implements `Default`. Build one with `StateSyncUpdate::from_parts`, read it through the same-named accessors, and take ownership of the contents with `into_parts` ([#2297](https://github.com/0xMiden/rust-sdk/pull/2297)). * [BREAKING][param][rust] `PartialBlockchainUpdates::insert` no longer takes the block's MMR authentication nodes; stage them separately with the new `extend_authentication_nodes` ([#2297](https://github.com/0xMiden/rust-sdk/pull/2297)). +* [BREAKING][rust] Transaction fees moved out of the kernel epilogue and into the authentication procedure. On a chain whose `verification_base_fee` is non-zero, signature-based auth components (`AuthSingleSig`, `AuthMultisig`) require the transaction to commit fee conversion info, and the paying account must hold a balance of the fee asset. use the new `TransactionRequestBuilder::fee_conversion_info` to commit it. Chains that charge no fee are unaffected. +* [BREAKING][rename][rust] Protocol renames surfaced through the client's re-exports: `miden_client::assembly::Library` is removed (packages are the only representation now, use `miden_client::vm::Package`). +* [BREAKING][param][rust] Network accounts now require a fee policy: `AuthNetworkAccount::with_allowed_notes` → `AuthNetworkAccount::new(notes, FeePolicyManager)` and `NetworkAccount::builder` takes a `FeePolicyManager`. Every allowlisted note script must have an explicit fee-schedule entry, including a zero one, because a script root missing from the schedule aborts fee estimation rather than defaulting to free. `AuthNetworkAccount` also no longer converts into a single `AccountComponent`: it yields the auth component plus its fee policy components, so it must be passed to `with_components`. +* [BREAKING][rust] Removed the `AuthSingleSigAcl` and `AuthSingleSigAclConfig` re-exports along with the `auth/acl-auth`. Use `AuthSingleSig`, which requires a signature for every call, or `NoAuth` where no authentication is wanted. +* [BREAKING][param][rust] `send_notes` transaction script now reads its payload from the advice provider and requires the payload commitment as its transaction script argument. The client binds that argument automatically, so a `TransactionRequestBuilder::script_arg` set alongside a `SendNotes` template is ignored; it still applies to caller-supplied custom scripts. +* [BREAKING][behavior][rust] Creating a note that carries a `NetworkAccountTarget` attachment now performs a foreign procedure invocation into the target account to price the note, even on a chain that charges no fees. Such transactions must supply the target network account as a foreign account, anchored at a reference block that already commits it. * [BREAKING][rust] Transaction inputs are now sealed before submission. The client fetches the validator set's shared encryption key on first submission and verifies its validator attestations against the validator set committed in the chain tip before using it. A client must be synced far enough to have a genesis header and a chain-tip header locally before it can submit. `NodeRpcClient::submit_proven_transaction` and `NodeRpcClient::submit_proven_batch` now take `SealedTransactionInputs` instead of `TransactionInputs`. * [BREAKING][rename][rust] `NoteScreener::can_consume` → `NoteScreener::get_consumability` and `NoteScreener::can_consume_batch` → `NoteScreener::get_batch_consumability`. The new names reflect that both return a `NoteConsumptionStatus` per account rather than a boolean ([#2338](https://github.com/0xMiden/rust-sdk/pull/2338)). * [BREAKING][behavior][rust] Transaction inputs are now encrypted on submission, so the RPC operator relaying them cannot read them. `Client::submit_proven_transaction` seals the inputs against the validator set's shared transaction encryption key: on first use it fetches the key from the node, verifies a validator attestation for it against the validator set committed in a trusted block header (binding the genesis commitment, so an attestation cannot be replayed from another network), and caches the verified key in the store's settings table, evicting it when the node rejects a submission sealed against a retired key so the next submission re-fetches. Requires a node that unseals submitted inputs; such nodes reject plaintext submissions ([#2341](https://github.com/0xMiden/rust-sdk/pull/2341)). * [BREAKING][param][rust] `NodeRpcClient` models encrypted submissions: `submit_proven_transaction` now takes `SealedTransactionInputs` instead of `TransactionInputs`, `submit_proven_batch` now takes `Vec` (one per transaction, each sealed against its own transaction ID), and implementations must provide the new `get_transaction_encryption_key` method ([#2341](https://github.com/0xMiden/rust-sdk/pull/2341)). * [BREAKING][removal][cli] Removed the `account --show --with-code` flag. Use `account --inspect --verbose` to view procedure disassembly. ([#2312](https://github.com/0xMiden/rust-sdk/issues/2312)). * [BREAKING][type][rust] Added the `NoteFilter::ScriptRoots` variant, so exhaustive matches on `NoteFilter` in `Store` implementations must handle it ([#2335](https://github.com/0xMiden/rust-sdk/pull/2335)). +* [BREAKING][behavior][rpc] The `SyncNotes` response now carries a reduced note metadata message: instead of the note's attachments commitment it carries one entry per attachment, with single-word attachments sent verbatim and larger ones sent as commitments. The client reconstructs the protocol-level `NoteMetadata` from those entries, so it requires a node that speaks this format. * [BREAKING][behavior][store] The SQLite base schema now declares an index on `input_notes(script_root)`. This changes the schema fingerprint, so opening a database created before this change fails with `SchemaHashMismatch` and existing stores must be recreated ([#2335](https://github.com/0xMiden/rust-sdk/pull/2335)). ### Enhancements * [FEATURE][rust] A client that only watches a public account now recovers notes the account consumed authenticated, even when it never tracked them by tag. During sync it reads the note references the node attaches to the account's transactions, fetches each note body by id, and surfaces it through `InputNoteReader`. Requires node `0.15.1` ([#2300](https://github.com/0xMiden/rust-sdk/pull/2300)). * [FEATURE][cli] Added a `--payback-note-type` option to `swap` so the payback note can be created as public or private (defaults to private). Public payback works without any off-band advice now that SWAP derives the payback recipient deterministically ([#2190](https://github.com/0xMiden/rust-sdk/pull/2190)). +* [FEATURE][cli] `init` now also writes the non-fungible faucet, guarded multisig auth and network account auth component packages ([#2356](https://github.com/0xMiden/rust-sdk/pull/2356)). +* [FEATURE][rust] Added the `NonFungibleFaucet` component re-export to `miden_client::account::component` ([#2356](https://github.com/0xMiden/rust-sdk/pull/2356)). +* [FEATURE][rust] A request built with `TransactionRequestBuilder::fee_conversion_info` is now rejected before execution, with `TransactionRequestError::FeeConversionInfoUnsupported` ([#2356](https://github.com/0xMiden/rust-sdk/pull/2356)). * [FEATURE][rust] `Client::get_consumable_notes(Some(account_id))` now screens only that account instead of screening every tracked account and discarding the rest, so its cost no longer grows with the number of tracked accounts. Added `NoteScreener::get_batch_consumability_for_account` to screen notes against a single account ([#2338](https://github.com/0xMiden/rust-sdk/pull/2338)). * [FEATURE][rust] Added the `miden_client::rpc::encryption` module backing encrypted submissions: `TransactionEncryptionKey`, `AttestedTransactionEncryptionKey` (whose `verify` is the only path to a usable key), `ValidatorAttestation`, `NextTransactionEncryptionKey`, `SealedTransactionInputs` and `seal_transaction_inputs`, along with re-exports of the validator DSA key types reachable from this API ([#2341](https://github.com/0xMiden/rust-sdk/pull/2341)). * [FEATURE][rust,store] Added `NoteFilter::ScriptRoots` to query input notes by their note script root directly at the store level, without loading and screening unrelated notes. The filter doesn't apply to output notes: querying output notes with it returns an empty list ([#2335](https://github.com/0xMiden/rust-sdk/pull/2335)). diff --git a/Cargo.lock b/Cargo.lock index d0b4278982..e906815eef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ - "crypto-common", + "crypto-common 0.2.2", "inout", ] @@ -36,12 +36,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "alloy-primitives" version = "1.6.0" @@ -59,6 +53,16 @@ dependencies = [ "sha3 0.11.0", ] +[[package]] +name = "alloy-rlp" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24671b1f62edcf0f9b62994c7bf72cd621a04a4b99f5020ece1a647b40e2f103" +dependencies = [ + "arrayvec", + "bytes", +] + [[package]] name = "alloy-sol-macro" version = "1.6.0" @@ -182,6 +186,195 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.118", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.6", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.6", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.6", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -241,6 +434,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "autocfg" version = "1.5.1" @@ -313,6 +517,18 @@ version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake3" version = "1.8.5" @@ -387,6 +603,12 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + [[package]] name = "bytemuck" version = "1.25.0" @@ -476,7 +698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ "block-buffer", - "crypto-common", + "crypto-common 0.2.2", "inout", ] @@ -584,6 +806,27 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -714,6 +957,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "crypto-common" version = "0.2.2" @@ -743,7 +996,7 @@ dependencies = [ "cfg-if", "cpufeatures 0.3.0", "curve25519-dalek-derive", - "digest", + "digest 0.11.3", "fiat-crypto", "rustc_version 0.4.1", "subtle", @@ -867,6 +1120,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "2.1.1" @@ -896,6 +1160,24 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "crypto-common 0.1.7", +] + [[package]] name = "digest" version = "0.11.3" @@ -904,7 +1186,7 @@ checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer", "const-oid", - "crypto-common", + "crypto-common 0.2.2", "ctutils", ] @@ -957,7 +1239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" dependencies = [ "der", - "digest", + "digest 0.11.3", "elliptic-curve", "rfc6979", "signature", @@ -990,6 +1272,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "either" version = "1.16.0" @@ -1004,8 +1298,8 @@ checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" dependencies = [ "base16ct", "crypto-bigint", - "crypto-common", - "digest", + "crypto-common 0.2.2", + "digest 0.11.3", "ff", "group", "hkdf", @@ -1017,6 +1311,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "env_filter" version = "2.0.0" @@ -1064,7 +1378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1085,6 +1399,28 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.14.0" @@ -1127,6 +1463,9 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ + "byteorder", + "rand 0.8.6", + "rustc-hex", "static_assertions", ] @@ -1191,6 +1530,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.32" @@ -1300,6 +1645,16 @@ dependencies = [ "windows-result", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -1408,8 +1763,6 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.2.0", ] @@ -1455,7 +1808,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "digest", + "digest 0.11.3", ] [[package]] @@ -1599,6 +1952,26 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "indenter" version = "0.3.4" @@ -1651,6 +2024,24 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +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 = "itertools" version = "0.14.0" @@ -1660,6 +2051,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1736,6 +2136,21 @@ dependencies = [ "cpufeatures 0.3.0", ] +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + [[package]] name = "lazy_static" version = "1.5.0" @@ -1908,10 +2323,11 @@ checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "miden-ace-codegen" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1831e4b40ba86d848581824b7089da20fb039dd8161f44e02b1ae2e3da6f30" +checksum = "a66d3f9f8abd86405b76e5fb33425ca663a6c7db5bc3b93d1386f6aa817633f6" dependencies = [ + "miden-constraint-compiler", "miden-core", "miden-crypto", "thiserror", @@ -1919,37 +2335,38 @@ dependencies = [ [[package]] name = "miden-agglayer" -version = "0.16.0-alpha.4" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4fbcb0a920295f20284c9ccfc51984e2df5bbab54cf95e538ed804b0dcada5" +checksum = "5ed2916f90e07a781b0664b9e08e9a8b4e1cdd4a5d40699a54e3661c8fada8a9" dependencies = [ "alloy-sol-types", "fs-err", "miden-assembly", - "miden-assembly-syntax", "miden-core", + "miden-core-lib", "miden-crypto", + "miden-mast-package", + "miden-package-registry", "miden-protocol", + "miden-protocol-build-utils", "miden-standards", "miden-utils-sync", - "primitive-types", - "regex", "serde", "serde_json", "thiserror", - "walkdir", ] [[package]] name = "miden-air" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cb4a9efe57aa970a7506b07729abd32702bdc6482a2a0364ecb045866c1d5b" +checksum = "06523a8e7130f70e5974c40861e808085a34eec27df1d397fb767850425a44e1" dependencies = [ "miden-ace-codegen", "miden-core", "miden-crypto", "miden-utils-indexing", + "p3-field", "proptest", "thiserror", "tracing", @@ -1957,9 +2374,9 @@ dependencies = [ [[package]] name = "miden-assembly" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31a8dbf11a81ae5f563ef5140a33bff2ec413ff0d34ca48404a8d11a2a43280" +checksum = "7c580e0f6b4a1fe06aa1ebe5dfa8924ed58ab5a0d0afeb845fe0cbafd481917f" dependencies = [ "env_logger", "log", @@ -1975,9 +2392,9 @@ dependencies = [ [[package]] name = "miden-assembly-syntax" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97be191cb4063a22312d88c5f6debf020d1f7b7d4eb2b1563172c4fda1f0b5de" +checksum = "c2acfd54fda86d88c08e2d4b23538c4f6011327e21a9576de88be90dc95fa77b" dependencies = [ "env_logger", "log", @@ -1998,9 +2415,9 @@ dependencies = [ [[package]] name = "miden-assembly-syntax-cst" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb812985ff68aa2d17ea8a87b48e769c5f9f69974ee723323c4739ef00a54f0" +checksum = "c983ea80cf3c747f39f61a9cffbf048f9107b7a5175b873d37527398019c6760" dependencies = [ "miden-debug-types", "miden-rowan", @@ -2010,9 +2427,9 @@ dependencies = [ [[package]] name = "miden-block-prover" -version = "0.16.0-alpha.4" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e503f64c41090fa581ac9dbd21b2fc18b393c05051235b56fde7ce8a6b68a5e" +checksum = "ee3d1c7e5bb954409d647a47472add0c851f80c478fe757654405ce090765fcb" dependencies = [ "miden-protocol", "thiserror", @@ -2020,7 +2437,7 @@ dependencies = [ [[package]] name = "miden-client" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -2060,7 +2477,7 @@ dependencies = [ [[package]] name = "miden-client-bench" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "assert_cmd", @@ -2076,7 +2493,7 @@ dependencies = [ [[package]] name = "miden-client-cli" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "assert_cmd", @@ -2104,7 +2521,7 @@ dependencies = [ [[package]] name = "miden-client-integration-tests" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "assert_matches", @@ -2127,7 +2544,7 @@ dependencies = [ [[package]] name = "miden-client-sqlite-store" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -2145,7 +2562,7 @@ dependencies = [ [[package]] name = "miden-client-unit-tests" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "miden-client", "miden-client-sqlite-store", @@ -2159,11 +2576,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "miden-constraint-compiler" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc2de03e3ca664006f6a523810c1a5a3b4254bbda8bf78e5aa009e2502c4f5d" +dependencies = [ + "miden-core", + "miden-crypto", +] + [[package]] name = "miden-core" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e26dcf78743d4abbca1bbc6799712e4ea674bad8e86dc4fd8732bf237450b1" +checksum = "f8394188e9b1fb828ad304d9984247b78660e53595f34880d8a403216a0e804e" dependencies = [ "derive_more", "log", @@ -2180,28 +2607,40 @@ dependencies = [ [[package]] name = "miden-core-lib" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcb1063ac5272a02037a5fb36355b267024aa09de81bb46f54bb68ced0eebb1" +checksum = "ef7ef6c4f708261e948f0b59c85c055c4a1169f1066c04ca56a87d3c7e0ef119" dependencies = [ "env_logger", "fs-err", "miden-assembly", "miden-assembly-syntax", "miden-core", + "miden-core-lib-codegen", "miden-crypto", "miden-mast-package", "miden-package-registry", + "miden-precompiles", "miden-processor", "miden-utils-sync", "thiserror", ] +[[package]] +name = "miden-core-lib-codegen" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823c735b6d34b34ae6bdc390cefafc6d1e5c81fe08cc14efe6c78834c59a59cc" +dependencies = [ + "miden-core", + "miden-precompiles", +] + [[package]] name = "miden-crypto" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afd70d37ade91ce0f37a0ad7b9f1709391657243857d5d209ec62a100e358d4d" +checksum = "5ac8bc266f7dc1f7069eb4f0786500241ad9b499d34cb5b8aa5b1a42fcb55e2b" dependencies = [ "blake3", "cc", @@ -2241,9 +2680,9 @@ dependencies = [ [[package]] name = "miden-crypto-derive" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9197f2837af387b5a9b60ef3c30670cf34a453c3a8e81f9cf68df84ca3122253" +checksum = "832fa19dfec7601a3e7ca007e55e16b38e333e553f233249e00417432409674d" dependencies = [ "quote", "syn 2.0.118", @@ -2251,9 +2690,9 @@ dependencies = [ [[package]] name = "miden-debug" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e4971fefa10e310c76ca0dc5037dd7fe0c1a097ce17a20b17265cff3ecd591" +checksum = "6ed993a17b7c5e13177f032bd5c01b1615d600a34f441a80783a9d0428f9523f" dependencies = [ "clap", "compact_str", @@ -2276,9 +2715,9 @@ dependencies = [ [[package]] name = "miden-debug-dap" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a694b0b59aeb4fb82adfec83e03763d9e370dce7d9287f908b9064b5d31ef34" +checksum = "d974ad4982cd62cb8357977a19c6ecc0a1c1daaccb068d45262cc3783985afa5" dependencies = [ "serde", "serde_json", @@ -2287,9 +2726,9 @@ dependencies = [ [[package]] name = "miden-debug-engine" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338b0d4003123733d51a7a4fe19d39437bef3ce84fb81a62471851b9bc36e3ff" +checksum = "6216e37ce0cdbb2f9c5800216ac94c5c3dbac398436a405a4d0fe9eb23b1ae76" dependencies = [ "clap", "glob", @@ -2317,9 +2756,9 @@ dependencies = [ [[package]] name = "miden-debug-types" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b9ba4ccb10ca8f719dc3c96a418aa2ade8251f108fba6034facb3e3eabae70" +checksum = "4556cf4e43be205707d04d9532dd302cd313162ee986160a37923b4a613a71c1" dependencies = [ "memchr", "miden-crypto", @@ -2337,12 +2776,12 @@ dependencies = [ [[package]] name = "miden-field" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45929f2e6b18f6535cfa25a55f5dac8be556410a4fc5c7e003a147b678af9e18" +checksum = "d86dc6aae6776bfdd2c3d148d2c7c29c56510887056dc48aa41ffc87c2e6eae4" dependencies = [ "miden-serde-utils", - "num-bigint", + "num-bigint 0.5.1", "p3-challenger", "p3-field", "p3-goldilocks", @@ -2365,9 +2804,9 @@ dependencies = [ [[package]] name = "miden-lifted-air" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320d7e0f1ac4a668682146cce69585ddc8dfe1fdf6ba5dac1986233e3e48d4df" +checksum = "1ddb6a87c95e6bb384ec290d29daf0d7d3fc5104d0ed9b9ff0c4a311fab65b73" dependencies = [ "p3-air", "p3-challenger", @@ -2379,9 +2818,9 @@ dependencies = [ [[package]] name = "miden-lifted-stark" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8075f037bb02eb763223bc2f762a55c793f3795677f88fc06e58641091fd69e0" +checksum = "e17c540c72c6a0adfa7e473f98bbf30b31ebd726026a76266eb77a5d00961931" dependencies = [ "miden-lifted-air", "miden-stark-transcript", @@ -2402,9 +2841,9 @@ dependencies = [ [[package]] name = "miden-mast-package" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee79180c3d317ab6239d7c2c488760fe3590b9f639e549d9d13f3e0f314a381" +checksum = "ffa6fd0d84e932cbd8c51fd2e71c4f48dc4edea1dbef9259ff440e4212341e7d" dependencies = [ "hashbrown 0.17.1", "log", @@ -2456,8 +2895,8 @@ dependencies = [ [[package]] name = "miden-node-proto-build" -version = "0.16.0-alpha.2" -source = "git+https://github.com/0xMiden/node.git?rev=b4ece8c9036745840e1cdd904a10b573283c37e2#b4ece8c9036745840e1cdd904a10b573283c37e2" +version = "0.16.0-rc.1" +source = "git+https://github.com/0xMiden/node.git?branch=next#92dd097a2835143d6e70de11cbfebc42e5f0b6bd" dependencies = [ "build-rs", "codegen", @@ -2481,9 +2920,9 @@ dependencies = [ [[package]] name = "miden-package-registry" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bf8ca360321a414771807cd3b95c732e99e30bf7187a9a80a0e63db36bbcc2" +checksum = "bfe36161cad2d5945b81c21c55a71bcb5d36445183556908eb7196a2465e1852" dependencies = [ "miden-assembly-syntax", "miden-core", @@ -2495,17 +2934,51 @@ dependencies = [ "thiserror", ] +[[package]] +name = "miden-precompiles" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee334f0a36c1a24d041323898b087da3b9bf2aa3b520d0d44ebc2ed07f5f617" +dependencies = [ + "miden-core", + "miden-crypto", +] + +[[package]] +name = "miden-precompiles-prover" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf74c0b721b4a04852561c4bad282644e5173089732132749dccc0cbca37088" +dependencies = [ + "miden-ace-codegen", + "miden-air", + "miden-core", + "miden-crypto", + "miden-lifted-air", + "miden-lifted-stark", + "miden-precompiles", + "miden-serde-utils", + "ruint", + "serde", + "serde-wincode", + "thiserror", + "tracing", + "wincode", +] + [[package]] name = "miden-processor" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6853b729e245f8c310bfba8e47cdbd303b1d11763499d3b7efd90bc821239aa9" +checksum = "d6b1429a0c3ac67db377fa5656937888ad89c6f7d8e6cb51afa549066d432d60" dependencies = [ - "itertools", + "hashbrown 0.17.1", + "itertools 0.15.0", "miden-air", "miden-core", "miden-debug-types", "miden-mast-package", + "miden-precompiles", "miden-utils-diagnostics", "miden-utils-indexing", "paste", @@ -2516,9 +2989,9 @@ dependencies = [ [[package]] name = "miden-project" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d12f4281e563c01305d989461574ccab41b749ac5d6e987ede1e9941ed18f5e" +checksum = "1aff0af79739a77d0128a307811cf6d1d134d14637fd2295d44eb7c4af28378d" dependencies = [ "miden-assembly-syntax", "miden-core", @@ -2533,9 +3006,9 @@ dependencies = [ [[package]] name = "miden-protocol" -version = "0.16.0-alpha.4" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f185d7a1e0c6c05ae760281956de3f6057e6d7889daeade4c71c158d6a252748" +checksum = "277cfbf96f95a422d9a8c4fa54bc37ba1ecffd77e3c628a84bcc259936201fdc" dependencies = [ "bech32", "fs-err", @@ -2549,6 +3022,7 @@ dependencies = [ "miden-mast-package", "miden-package-registry", "miden-processor", + "miden-protocol-build-utils", "miden-utils-sync", "miden-verifier", "rand 0.10.1", @@ -2559,18 +3033,34 @@ dependencies = [ "serde", "thiserror", "toml 1.1.2+spec-1.1.0", +] + +[[package]] +name = "miden-protocol-build-utils" +version = "0.16.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07569c89b4bd503b83db7afd5f9c8ec2e33406b5cf157f08ca50957c658d6d1f" +dependencies = [ + "fs-err", + "miden-assembly", + "miden-core", + "miden-mast-package", + "miden-package-registry", + "miden-project", + "regex", "walkdir", ] [[package]] name = "miden-prover" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31894254d15caa4a711108de10f96941e4ddb67dee68a1316dccedb17986eb3" +checksum = "86609ed83aa69f23cd8dfe7391dfe5d16cd9a160f2922c3eb230e44c7c39aed7" dependencies = [ "miden-air", "miden-core", "miden-crypto", + "miden-precompiles-prover", "miden-processor", "serde", "serde-wincode", @@ -2589,39 +3079,37 @@ dependencies = [ [[package]] name = "miden-serde-utils" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf6872ac0f2de384ac65968e9bdc24656b31c487ea3bb1665871095c10f11ee" +checksum = "a8bc2e1ffd6d9c0a445259f3e32f02b79af2776d34d7dc5dbd6e39e19bbebdce" dependencies = [ "p3-field", "p3-goldilocks", + "wincode", ] [[package]] name = "miden-standards" -version = "0.16.0-alpha.4" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6556a340bf1bec696fd376a5a567d1d4056df5f2d80cecc4f67b56d07defd050" +checksum = "ea6706455ef46e5ec988728e2b161e6b30badfcb2e5927f6f9032b2e37269107" dependencies = [ "bon", - "fs-err", "miden-assembly", "miden-core-lib", - "miden-mast-package", "miden-package-registry", - "miden-project", "miden-protocol", + "miden-protocol-build-utils", + "primitive-types 0.14.0", "rand 0.10.1", - "regex", "thiserror", - "walkdir", ] [[package]] name = "miden-stark-transcript" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2f5cc37a6b24ef2ab4c8d4dfb874a8f55add5147bfad47fde901f03165a51" +checksum = "8fc72d9321645757904aebc53e2ee78de46f992a961a04cd15a996137fedd0ce" dependencies = [ "p3-challenger", "p3-field", @@ -2631,9 +3119,9 @@ dependencies = [ [[package]] name = "miden-stateful-hasher" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93a95d46e93b94d82e0fcc6cec67ea362a548c1b6209bfdd1211433537314b83" +checksum = "99c1612fbad6502deb79a34bd852a53b30cbcae92fbf20a2f2c220a708e1aec7" dependencies = [ "p3-field", "p3-symmetric", @@ -2641,12 +3129,12 @@ dependencies = [ [[package]] name = "miden-testing" -version = "0.16.0-alpha.2" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610ba28ab9d73da0fcde6aa2389b2029e096df0c7248fde558d7d44be67ec8f7" +checksum = "3f56c7af2c5776c27307a2de05e8175cde00c1f6fc35be6f4ce7395f7d6ae9cb" dependencies = [ "anyhow", - "itertools", + "itertools 0.15.0", "miden-block-prover", "miden-core-lib", "miden-crypto", @@ -2662,10 +3150,12 @@ dependencies = [ [[package]] name = "miden-tx" -version = "0.16.0-alpha.4" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548c667b479e16a8f6415181cd1f84bbae68999182c1b1f5a5b9aa4488ab500a" +checksum = "27a155a881004695c5ecc7c432967babf58ade522e55c200123aaf99d337808c" dependencies = [ + "bon", + "miden-agglayer", "miden-processor", "miden-protocol", "miden-prover", @@ -2675,9 +3165,9 @@ dependencies = [ [[package]] name = "miden-tx-batch" -version = "0.16.0-alpha.4" +version = "0.16.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e6652dd5f40a5c1cc62122385c7125a22a6490c9ac47793998a0cf8a5c6347" +checksum = "555d90956b0f9f7dcacacbbe4970f1ca9e5077ed6f9d4be69f14207ff9a63723" dependencies = [ "miden-processor", "miden-protocol", @@ -2688,9 +3178,9 @@ dependencies = [ [[package]] name = "miden-utils-core-derive" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb2baba2f71907ab82be0d064410030196f8e06f19687d7bb33970e02dd9cec" +checksum = "a21bd1f2a35b3e8e48b391c51bd5d4d3d080066d9f0cd8a1567be477fd6acbed" dependencies = [ "proc-macro2", "quote", @@ -2699,9 +3189,9 @@ dependencies = [ [[package]] name = "miden-utils-diagnostics" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "485627595e49b2d83d163511ddc7200194a07ee80bbeab67713ebcfeab57e2e4" +checksum = "9927aebed020f53666d1daf01b834e134ce80ced02cef6f6b82c3a2f855fb85c" dependencies = [ "miden-debug-types", "miden-miette", @@ -2710,9 +3200,9 @@ dependencies = [ [[package]] name = "miden-utils-indexing" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6be5944699579d8babf57d0d6dd625cb59b7a10bdf85e5fc96ae568991df9f" +checksum = "1e1ce02f96261808a50f86088c83bc9eef809205bbc51f76f10432bb9a5e1337" dependencies = [ "miden-serde-utils", "proptest", @@ -2722,9 +3212,9 @@ dependencies = [ [[package]] name = "miden-utils-sync" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d4980ed8c1f02727ef294ec78ec2e73c367bc53ca784f4de62c1c3e5b6cbfe3" +checksum = "579fdffa79eb4e9d90f53ee6cc29d7122b50b095c388a0f4ca1e1f6e04df7faf" dependencies = [ "lock_api", "loom", @@ -2734,24 +3224,26 @@ dependencies = [ [[package]] name = "miden-verifier" -version = "0.25.8" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afef2b344a7c0a5a90c2b6335f4ab50e74cbaa255009ec718eb6c9598b7d9486" +checksum = "8a6cf11175c58139dd15330caf77c8462f742bfc73d7e0216c8ece45e53f90f2" dependencies = [ "miden-air", "miden-core", "miden-crypto", + "miden-precompiles", + "miden-precompiles-prover", + "miden-serde-utils", "serde", "serde-wincode", "thiserror", - "tracing", ] [[package]] name = "midenc-hir-type" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67fe32b429d499d0ae713e044b593d866b1ab51540de6ca8881413aba42e858" +checksum = "e03aa1e30a8eec3e08eba9a1fd17c7c4462f0d49dfbd64cb65193b68ee14cdcc" dependencies = [ "miden-formatting", "miden-serde-utils", @@ -2838,7 +3330,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-complex", "num-integer", "num-iter", @@ -2856,6 +3348,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e7820bc0a80a0238e650327316f929ba18d5be054b647490a3a6a339f3e7c0" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -2891,7 +3393,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -2961,9 +3463,9 @@ checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "p3-air" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e18b22bf85451382098e54da526733c7f390f83d4141b3b8b93e98e805df55" +checksum = "ddb1be05c0d6f691afe0c9f468018a9a37cfa904dee78a8081ec96eb3cdd88e8" dependencies = [ "p3-field", "p3-matrix", @@ -2972,9 +3474,9 @@ dependencies = [ [[package]] name = "p3-blake3" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be4f62b2e8cc5c9b2bc0bfb0b1a98dcaaa2f5c25b167f04c8ac6123537a604b" +checksum = "6f202f5fbcceb6f56f783d98efb5de27e5a171470e3364de97b0923b39c87ab5" dependencies = [ "blake3", "p3-symmetric", @@ -2983,9 +3485,9 @@ dependencies = [ [[package]] name = "p3-challenger" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "272b2cfdcd3cf1affeab292aa7888ed7e4c156e0d5ffc19612c86553941db178" +checksum = "84d5d5e1ecf2c80b09b48ce870e8abd08b643454101c5dc9d0fd71bfbd78224d" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -2997,11 +3499,11 @@ dependencies = [ [[package]] name = "p3-dft" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dc420990b39aa4cdb78ac248d5defe97f760c1056aeceb160dcf3e62baf4eb7" +checksum = "4321a952da2721ecd85ca593ea189798dfb4e439a2cc1378ce1442091880f173" dependencies = [ - "itertools", + "itertools 0.15.0", "p3-field", "p3-matrix", "p3-maybe-rayon", @@ -3012,12 +3514,12 @@ dependencies = [ [[package]] name = "p3-field" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab37408c6c964e7e18c2305a15e31bc784aa20eb82eb513b4850aaa13ee445d3" +checksum = "53db75d38e04fc255826f388eca9d05976733dc9754aa3db411bc9ea1a37c1a0" dependencies = [ - "itertools", - "num-bigint", + "itertools 0.15.0", + "num-bigint 0.5.1", "p3-maybe-rayon", "p3-util", "paste", @@ -3028,11 +3530,11 @@ dependencies = [ [[package]] name = "p3-goldilocks" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf8c89d8e833f93c488bd207786cd2d525a9f93de7f00363bca5652c88110a4" +checksum = "d03b3f31080df31be723b876709246f8f1e532e1c5b82efb5281d705c8304c63" dependencies = [ - "num-bigint", + "num-bigint 0.5.1", "p3-challenger", "p3-dft", "p3-field", @@ -3044,13 +3546,14 @@ dependencies = [ "paste", "rand 0.10.1", "serde", + "spin 0.12.1", ] [[package]] name = "p3-keccak" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868cb9c763e5786f89d531e15b9899f9dd3ba96768645294b99fd9df861b530" +checksum = "ae50c8c37eb847c660298fb275e53c025c49b2623a8cfabf67f5322258b2b4db" dependencies = [ "p3-symmetric", "p3-util", @@ -3059,11 +3562,11 @@ dependencies = [ [[package]] name = "p3-matrix" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c5e32dd61fa6341f8ce7abe2a97e9c3f8a93d9ea17bf4f675a2f6c987b658e" +checksum = "473eb920c446a6f4536e0d3528fbdca2a23c0e24e1d0d7767452e6d385dd335c" dependencies = [ - "itertools", + "itertools 0.15.0", "p3-field", "p3-maybe-rayon", "p3-util", @@ -3074,18 +3577,18 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49c17330c94d04221bafe310d2c13afedd9d26bb57a63ec088b68b6cfe64b357" +checksum = "e6fddfd435f96394769414cf5590b77058aa506659bf20d6592e9d1989e04440" dependencies = [ "rayon", ] [[package]] name = "p3-mds" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ea6f54d4436d44f14841f78238b79199b83ea983a4a2fa3c4d16202f28f119" +checksum = "551ba0ab2cccd89f85a99450224898aff224e323bbf61f777ba6344f0896ef10" dependencies = [ "p3-dft", "p3-field", @@ -3096,12 +3599,12 @@ dependencies = [ [[package]] name = "p3-monty-31" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d3acd0d5f0ba2e8a1c903e80c92e778368b68c2e551a6c30fc3982a4be023e" +checksum = "871f635f7340cd0868b17e43e0c98fefdafdaed90469d0725caf6d8372a2a47c" dependencies = [ - "itertools", - "num-bigint", + "itertools 0.15.0", + "num-bigint 0.5.1", "p3-dft", "p3-field", "p3-matrix", @@ -3120,9 +3623,9 @@ dependencies = [ [[package]] name = "p3-poseidon1" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cccfe593f85f87681f885c32f1447ea7afe12b3c9b11b4149c4534edacacb51" +checksum = "8d0d304e9a1f29c0d66534aa84e69528e2118351fdce08dcf5898af4e0fecc32" dependencies = [ "p3-field", "p3-mds", @@ -3132,9 +3635,9 @@ dependencies = [ [[package]] name = "p3-poseidon2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d28bb6596f38c493d7a590e3b7d30eae86cbcfc325fb44f652ec3540933bcaa0" +checksum = "43eb8a73a26d14becaed1c67c3e8a047e4311d7909b402383c82ca9643ba17c6" dependencies = [ "p3-field", "p3-mds", @@ -3145,11 +3648,11 @@ dependencies = [ [[package]] name = "p3-symmetric" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284db1f284c4007eeb65cef4656426c93192af9bd9703b7f3afbf7faab274500" +checksum = "2015ea80cad969b6aabf27a04884286fe1354393b166d968ee0d80a95126b2a4" dependencies = [ - "itertools", + "itertools 0.15.0", "p3-field", "p3-util", "serde", @@ -3157,13 +3660,40 @@ dependencies = [ [[package]] name = "p3-util" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f241f0faa735a03b1af8c923b4728a9fac5e4a26e573a087656c354a784dfcae" +checksum = "6c5466fc40e6df89d3b291a2eff16b33e68e8571207790370137ec18090aadab" dependencies = [ "rayon", "serde", - "transpose", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] @@ -3230,6 +3760,16 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" +dependencies = [ + "memchr", + "ucd-trie", +] + [[package]] name = "petgraph" version = "0.8.3" @@ -3364,7 +3904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" dependencies = [ "crypto-bigint", - "crypto-common", + "crypto-common 0.2.2", "ff", "rand_core 0.10.1", "subtle", @@ -3383,6 +3923,17 @@ dependencies = [ "wnaf", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint 0.9.5", +] + [[package]] name = "primitive-types" version = "0.14.0" @@ -3390,7 +3941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "721a1da530b5a2633218dc9f75713394c983c352be88d2d7c9ee85e2c4c21794" dependencies = [ "fixed-hash", - "uint", + "uint 0.10.0", ] [[package]] @@ -3500,7 +4051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ "heck", - "itertools", + "itertools 0.14.0", "log", "multimap", "petgraph", @@ -3521,7 +4072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.118", @@ -3639,12 +4190,20 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ + "libc", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -3669,6 +4228,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -3694,6 +4263,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] [[package]] name = "rand_core" @@ -3827,6 +4399,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + [[package]] name = "rstest" version = "0.25.0" @@ -3863,9 +4445,22 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0298da754d1395046b0afdc2f20ee76d29a8ae310cd30ffa84ed42acba9cb12a" dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "ark-ff 0.5.0", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types 0.12.2", "proptest", "rand 0.8.6", "rand 0.9.4", + "rlp", "ruint-macro", "serde_core", "valuable", @@ -3914,6 +4509,12 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + [[package]] name = "rustc_version" version = "0.2.3" @@ -3923,6 +4524,15 @@ dependencies = [ "semver 0.9.0", ] +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.1" @@ -3942,7 +4552,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4077,7 +4687,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.3", ] [[package]] @@ -4096,6 +4715,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.228" @@ -4235,7 +4863,7 @@ checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "digest", + "digest 0.11.3", ] [[package]] @@ -4244,7 +4872,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" dependencies = [ - "digest", + "digest 0.11.3", "keccak", ] @@ -4254,7 +4882,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc9bad02c26382724b2d2692c6f179285e4b54eeecd7968f52a50059c3c11759" dependencies = [ - "digest", + "digest 0.11.3", "keccak", "sponge-cursor", ] @@ -4280,7 +4908,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" dependencies = [ - "digest", + "digest 0.11.3", "rand_core 0.10.1", ] @@ -4355,12 +4983,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strength_reduce" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" - [[package]] name = "strip-ansi-escapes" version = "0.2.1" @@ -4425,6 +5047,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn-solidity" version = "1.6.0" @@ -4443,6 +5076,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.13.5" @@ -4465,7 +5104,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4495,7 +5134,7 @@ checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-node-genesis" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "miden-agglayer", @@ -4943,16 +5582,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "transpose" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" -dependencies = [ - "num-integer", - "strength_reduce", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -4987,6 +5616,24 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "uint" version = "0.10.0" @@ -5062,7 +5709,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" dependencies = [ - "crypto-common", + "crypto-common 0.2.2", "ctutils", ] @@ -5269,7 +5916,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5280,9 +5927,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wincode" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d967db7705dc29120bb6e8ce5b5a2e27734ed5976d1c904e95bd238d1c3c5a" +checksum = "b5d39d1a984eb7ae37afa348f058216d62a6d5f71640f4113a8114386c2a812a" dependencies = [ "pastey", "proc-macro2", @@ -5466,6 +6113,15 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x25519-dalek" version = "3.0.0" @@ -5507,6 +6163,20 @@ name = "zeroize" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] [[package]] name = "zmij" diff --git a/Cargo.toml b/Cargo.toml index 1a5e4d8fb8..d73f5f1c34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ edition = "2024" license = "MIT" repository = "https://github.com/0xMiden/rust-sdk" rust-version = "1.96" -version = "0.16.0-alpha.1" +version = "0.16.0-rc.1" [profile.dev] codegen-units = 16 @@ -36,24 +36,24 @@ opt-level = 1 [workspace.dependencies] # Workspace crates -miden-client = { default-features = false, path = "crates/rust-client", version = "0.16.0-alpha.1" } -miden-client-sqlite-store = { default-features = false, path = "crates/sqlite-store", version = "0.16.0-alpha.1" } +miden-client = { default-features = false, path = "crates/rust-client", version = "0.16.0-rc.1" } +miden-client-sqlite-store = { default-features = false, path = "crates/sqlite-store", version = "0.16.0-rc.1" } # Miden protocol dependencies -miden-agglayer = { default-features = false, version = "0.16.0-alpha.4" } -miden-protocol = { default-features = false, version = "0.16.0-alpha.4" } -miden-standards = { default-features = false, version = "0.16.0-alpha.4" } -miden-testing = { default-features = false, version = "0.16.0-alpha.2" } -miden-tx = { default-features = false, version = "0.16.0-alpha.4" } -miden-tx-batch = { default-features = false, version = "0.16.0-alpha.4" } +miden-agglayer = { default-features = false, version = "0.16.0-rc.3" } +miden-protocol = { default-features = false, version = "0.16.0-rc.3" } +miden-standards = { default-features = false, version = "0.16.0-rc.3" } +miden-testing = { default-features = false, version = "0.16.0-rc.3" } +miden-tx = { default-features = false, version = "0.16.0-rc.3" } +miden-tx-batch = { default-features = false, version = "0.16.0-rc.3" } # Miden node dependencies -miden-node-proto-build = { default-features = false, git = "https://github.com/0xMiden/node.git", rev = "b4ece8c9036745840e1cdd904a10b573283c37e2" } +miden-node-proto-build = { branch = "next", default-features = false, git = "https://github.com/0xMiden/node.git" } # TODO: switch to rc.3 once available miden-note-transport-proto-build = { default-features = false, version = "0.5.0-alpha.1" } # Miden debug dependency -miden-debug = { default-features = false, features = ["dap", "std"], version = "0.9.2" } -miden-processor = { default-features = false, version = "0.25.8" } +miden-debug = { default-features = false, features = ["dap", "std"], version = "0.10" } +miden-processor = { default-features = false, version = "0.29" } # External dependencies anyhow = { default-features = false, version = "1.0" } diff --git a/bin/integration-tests/src/asm/PASS_THROUGH.masm b/bin/integration-tests/src/asm/PASS_THROUGH.masm index 65d5e18840..6225f04ff9 100644 --- a/bin/integration-tests/src/asm/PASS_THROUGH.masm +++ b/bin/integration-tests/src/asm/PASS_THROUGH.masm @@ -40,7 +40,7 @@ pub proc main # move the incoming note's assets into the account vault so they can be # moved into the output note from the account context - exec.basic_wallet::add_assets_to_account + exec.basic_wallet::move_note_assets_to_account # => [] # pad the stack for the create_note call diff --git a/bin/integration-tests/src/asm/custom_p2id.masm b/bin/integration-tests/src/asm/custom_p2id.masm index 8e7c7be7d5..5caab8d23d 100644 --- a/bin/integration-tests/src/asm/custom_p2id.masm +++ b/bin/integration-tests/src/asm/custom_p2id.masm @@ -67,6 +67,6 @@ pub proc main exec.account_id::eq assert.err="P2ID's target account address and transaction address do not match" # => [] - exec.basic_wallet::add_assets_to_account + exec.basic_wallet::move_note_assets_to_account # => [] end diff --git a/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs b/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs index 6768d5b797..3e550ef5a1 100644 --- a/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs +++ b/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs @@ -29,13 +29,12 @@ use miden_agglayer::{ ClaimNoteStorage, ConfigAggBridgeNote, ConversionMetadata, - EthAddress, - EthEmbeddedAccountId, UpdateGerNote, create_agglayer_faucet, }; use miden_client::Felt; use miden_client::account::AccountType; +use miden_client::agglayer::{EthAddress, EthEmbeddedAccountId}; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::crypto::FeltRng; @@ -227,7 +226,7 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< // Submit CLAIM note: done by the user (or could also be a claim manager entity) let miden_claim_amount = leaf_data .amount - .scale_to_token_amount(scale as u32) + .scale_to_asset_amount(scale as u32) .expect("amount should scale successfully"); println!("[bridge_in_out] Round {round}: miden claim amount: {:?}", miden_claim_amount); diff --git a/bin/integration-tests/src/tests/agglayer/agglayer_test_utils.rs b/bin/integration-tests/src/tests/agglayer/agglayer_test_utils.rs index 7a920cf8df..031d723a88 100644 --- a/bin/integration-tests/src/tests/agglayer/agglayer_test_utils.rs +++ b/bin/integration-tests/src/tests/agglayer/agglayer_test_utils.rs @@ -5,9 +5,6 @@ use alloc::vec::Vec; use anyhow::{Context, Result, ensure}; use miden_agglayer::{ - EthAddress, - EthAmount, - EthEmbeddedAccountId, ExitRoot, GlobalIndex, Keccak256Output, @@ -16,6 +13,7 @@ use miden_agglayer::{ ProofData, SmtNode, }; +use miden_client::agglayer::{EthAddress, EthAmount, EthEmbeddedAccountId}; use miden_client::utils::hex_to_bytes; use miden_protocol::account::AccountId; use serde::Deserialize; diff --git a/bin/integration-tests/src/tests/agglayer/mod.rs b/bin/integration-tests/src/tests/agglayer/mod.rs index 686f11a279..d7258305ff 100644 --- a/bin/integration-tests/src/tests/agglayer/mod.rs +++ b/bin/integration-tests/src/tests/agglayer/mod.rs @@ -1,7 +1,8 @@ +use std::collections::BTreeSet; use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; -use miden_agglayer::create_bridge_account; +use miden_agglayer::{BridgeRoles, create_bridge_account}; use miden_client::Deserializable; use miden_client::account::{AccountFile, AccountId, AccountType}; use miden_client::auth::RPO_FALCON_SCHEME_ID; @@ -23,6 +24,13 @@ mod agglayer_test_utils; pub mod ger; pub mod note_reader; +/// The `AggLayer` network ID assigned to the Miden chain. +/// +/// Bridge-in asserts that a claim leaf's `destination_network` equals the value the bridge account +/// was built with, so this must match the `MIDEN_NETWORK_ID` used to generate the Solidity test +/// vectors under `foundry-vectors/`. +const MIDEN_NETWORK_ID: u32 = 77; + // AGGLAYER CONFIG // ================================================================================================ @@ -218,12 +226,14 @@ pub async fn setup_core_accounts( // The bridge is an `AuthNetworkAccount`. Create it (unconfigured) and distribute it to all // three clients so each can build transactions that reference it. let bridge_seed = bridge_admin.client.rng().draw_word(); - let bridge_account = create_bridge_account( - bridge_seed, - bridge_admin_account.id(), - ger_manager_account.id(), - ger_manager_account.id(), - ); + let roles = BridgeRoles::new( + BTreeSet::from([bridge_admin_account.id()]), + BTreeSet::from([ger_manager_account.id()]), + BTreeSet::from([ger_manager_account.id()]), + ) + .context("failed to build bridge roles")?; + let bridge_account = + create_bridge_account(bridge_seed, bridge_admin_account.id(), roles, MIDEN_NETWORK_ID); println!("[setup] bridge admin: {}", bridge_admin_account.id()); println!("[setup] GER manager: {}", ger_manager_account.id()); println!("[setup] bridge: {}", bridge_account.id()); @@ -241,5 +251,13 @@ pub async fn setup_core_accounts( wait_for_tx(&mut bridge_admin.client, tx_id).await?; println!("[setup] Bridge account deployed on-chain"); + // Only the submitting client advanced past the deploy. Creating a note aimed at the bridge + // makes an FPI call into it to price the note, and the kernel resolves that foreign account + // against the transaction's reference block, so a client still anchored before the deploy + // block cannot see the account at all. + for pair in [&mut *ger_manager, &mut *user] { + pair.client.sync_state().await?; + } + Ok((bridge_admin_account.id(), ger_manager_account.id(), bridge_account.id())) } diff --git a/bin/integration-tests/src/tests/client.rs b/bin/integration-tests/src/tests/client.rs index e397ac08cd..601f5d753e 100644 --- a/bin/integration-tests/src/tests/client.rs +++ b/bin/integration-tests/src/tests/client.rs @@ -1752,7 +1752,7 @@ pub async fn test_get_account_storage_map_key_filtering(client_config: ClientCon let account = AccountBuilder::new(Default::default()) .with_component(component) - .with_auth_component(auth_component) + .with_component(auth_component) .account_type(AccountType::Public) .build_with_schema_commitment() .context("failed to build account")?; diff --git a/bin/integration-tests/src/tests/fpi.rs b/bin/integration-tests/src/tests/fpi.rs index 81d9ef0e8b..345a6f2eaa 100644 --- a/bin/integration-tests/src/tests/fpi.rs +++ b/bin/integration-tests/src/tests/fpi.rs @@ -649,7 +649,7 @@ fn foreign_account_with_code( let account = AccountBuilder::new(Default::default()) .with_component(get_item_component.clone()) - .with_auth_component(auth_component) + .with_component(auth_component) .account_type(account_type) .build_with_schema_commitment() .context("failed to build foreign account")?; diff --git a/bin/integration-tests/src/tests/network_transaction.rs b/bin/integration-tests/src/tests/network_transaction.rs index 4cb77ce207..c939711db3 100644 --- a/bin/integration-tests/src/tests/network_transaction.rs +++ b/bin/integration-tests/src/tests/network_transaction.rs @@ -8,7 +8,10 @@ use miden_client::account::component::{ AccountComponent, AccountComponentMetadata, AuthNetworkAccount, + BasicConstantFeePolicy, BurnPolicy, + FeePolicy, + FeePolicyManager, FungibleFaucet, MintPolicy, NetworkAccount, @@ -28,10 +31,13 @@ use miden_client::account::{ use miden_client::assembly::{CodeBuilder, SourceManagerSync}; use miden_client::asset::{AssetAmount, FungibleAsset, TokenSymbol}; use miden_client::auth::RPO_FALCON_SCHEME_ID; +use miden_client::block::BlockNumber; use miden_client::crypto::FeltRng; use miden_client::note::{ + FeeSponsorshipNote, MintNote, MintNoteStorage, + NetworkAccountConfigNote, NetworkAccountTarget, Note, NoteAssets, @@ -60,7 +66,7 @@ use miden_client::testing::common::{ wait_for_blocks, wait_for_tx, }; -use miden_client::transaction::{ExpirationTransactionScript, TransactionRequestBuilder}; +use miden_client::transaction::TransactionRequestBuilder; use miden_client::{Felt, Word, ZERO}; use rand::{Rng, RngExt}; @@ -170,7 +176,7 @@ const NON_STANDARD_CLAIM_NOTE_SCRIPT: &str = r#" # => [] # move all of the note's assets into the consuming account's vault - exec.basic_wallet::add_assets_to_account + exec.basic_wallet::move_note_assets_to_account # => [] end "#; @@ -184,13 +190,41 @@ pub(crate) async fn deploy_network_counter_contract( allowed_note_script_roots: &[NoteScriptRoot], ) -> Result { let roots = allowed_note_script_roots.iter().copied().collect::>(); - let auth = AuthNetworkAccount::with_allowed_notes(roots) + let (genesis, _) = client + .get_block_header_by_num(BlockNumber::GENESIS) + .await? + .context("genesis block header is not in the store")?; + let fee_policy_manager = + zero_fee_policy_manager(genesis.fee_parameters().fee_faucet_id(), roots.iter().copied()); + let auth = AuthNetworkAccount::new(roots, fee_policy_manager) .map_err(|err| anyhow::anyhow!(err)) - .context("failed to build network account auth component")? - .with_allowed_tx_scripts(BTreeSet::from([ExpirationTransactionScript::script_root()])); + .context("failed to build network account auth component")?; deploy_counter_with_auth(client, auth).await } +/// Builds a fee policy manager pricing every note the account can consume at zero. +/// +/// `fee_faucet_id` must be the faucet the chain charges fees in, as named by the genesis header's +/// fee parameters. +fn zero_fee_policy_manager( + fee_faucet_id: AccountId, + allowed_note_script_roots: impl IntoIterator, +) -> FeePolicyManager { + let fee_policy: FeePolicy = BasicConstantFeePolicy::new() + .with_fees( + allowed_note_script_roots + .into_iter() + .chain([NetworkAccountConfigNote::script_root(), FeeSponsorshipNote::script_root()]) + .map(|root| (root, AssetAmount::ZERO)), + ) + .into(); + + FeePolicyManager::builder() + .fee_faucet_id(fee_faucet_id) + .active_fee_policy(fee_policy) + .build() +} + /// Deploys a counter contract as an ordinary public account that consumes notes via user /// transactions (the node rejects user transactions against network accounts). pub(crate) async fn deploy_counter_contract(client: &mut TestClient) -> Result { @@ -204,7 +238,7 @@ pub(crate) async fn deploy_counter_contract(client: &mut TestClient) -> Result Result, + auth: impl IntoIterator>, ) -> Result { let counter_slot = StorageSlot::with_empty_value(COUNTER_SLOT_NAME.clone()); let counter_code = CodeBuilder::default() @@ -232,7 +266,7 @@ async fn deploy_counter_with_auth( let acc = AccountBuilder::new(init_seed) .account_type(AccountType::Public) .with_component(counter_component) - .with_auth_component(auth) + .with_components(auth) .build_with_schema_commitment() .context("failed to build counter contract account")?; @@ -274,7 +308,15 @@ async fn deploy_network_fungible_faucet( .active_mint_policy(MintPolicy::owner_only()) .active_burn_policy(BurnPolicy::allow_all()) .build(); - let faucet = NetworkAccount::builder(init_seed, allowed_roots)? + let (genesis, _) = client + .get_block_header_by_num(BlockNumber::GENESIS) + .await? + .context("genesis block header is not in the store")?; + let fee_policy_manager = zero_fee_policy_manager( + genesis.fee_parameters().fee_faucet_id(), + allowed_roots.iter().copied(), + ); + let faucet = NetworkAccount::builder(init_seed, allowed_roots, fee_policy_manager)? .with_component(faucet_component) .with_components(AccessControl::Ownable2Step { owner: owner_id }) .with_components(policy_manager) diff --git a/bin/integration-tests/src/tests/pass_through.rs b/bin/integration-tests/src/tests/pass_through.rs index 05de62596b..1b6f892de1 100644 --- a/bin/integration-tests/src/tests/pass_through.rs +++ b/bin/integration-tests/src/tests/pass_through.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeSet; - use anyhow::Result; use miden_client::account::component::BasicWallet; use miden_client::account::{ @@ -11,14 +9,7 @@ use miden_client::account::{ }; use miden_client::assembly::CodeBuilder; use miden_client::asset::{Asset, FungibleAsset}; -use miden_client::auth::{ - Approver, - AuthSchemeId, - AuthSecretKey, - AuthSingleSigAcl, - AuthSingleSigAclConfig, - TransactionAuthenticator, -}; +use miden_client::auth::{AuthSchemeId, NoAuth, TransactionAuthenticator}; use miden_client::crypto::FeltRng; use miden_client::note::{ Note, @@ -82,7 +73,7 @@ pub async fn test_pass_through(client_config: ClientConfig) -> Result<()> { ) .await?; - let pass_through_account = create_pass_through_account(&mut client, &authenticator_1).await?; + let pass_through_account = create_pass_through_account(&mut client).await?; // Create client with faucets BTC faucet let (btc_faucet_account, ..) = insert_new_fungible_faucet( @@ -201,33 +192,20 @@ pub async fn test_pass_through(client_config: ClientConfig) -> Result<()> { async fn create_pass_through_account( client: &mut Client, - keystore: &FilesystemKeyStore, ) -> Result { let mut init_seed = [0u8; 32]; client.rng().fill_bytes(&mut init_seed); - let key_pair = AuthSecretKey::new_falcon512_poseidon2(); - let pub_key = key_pair.public_key().to_commitment(); - - // The pass-through consumption must not change the account commitment, so the wallet - // procedures invoked by the PASS_THROUGH note script are exempt from signature checks. - let exempt_procedures = BTreeSet::from([ - BasicWallet::receive_asset_root(), - BasicWallet::move_asset_to_note_root(), - BasicWallet::create_note_root(), - ]); - let acl_config = AuthSingleSigAclConfig::new(exempt_procedures).unwrap(); - - let auth_component = - AuthSingleSigAcl::new(Approver::new(pub_key, AuthSchemeId::Falcon512Poseidon2), acl_config); + // The pass-through consumption must not change the account commitment: the note moves the + // asset straight back out, and `NoAuth` only bumps the nonce when the account state differs + // at the end of the transaction. let account = AccountBuilder::new(init_seed) .account_type(AccountType::Private) - .with_auth_component(auth_component) + .with_component(NoAuth) .with_component(BasicWallet) .build_with_schema_commitment() .unwrap(); - keystore.add_key(&key_pair, account.id()).await?; client.add_account(&account, false).await?; Ok(account) } diff --git a/bin/integration-tests/src/tests/swap_transaction.rs b/bin/integration-tests/src/tests/swap_transaction.rs index 6d75c759fb..81540c3435 100644 --- a/bin/integration-tests/src/tests/swap_transaction.rs +++ b/bin/integration-tests/src/tests/swap_transaction.rs @@ -104,7 +104,7 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> execute_tx_and_sync(&mut client1, account_a.id(), tx_request).await?; - let swap_note_tag = SwapNote::build_tag( + let swap_note_tag = SwapNote::create_tag( NoteType::Public, &Asset::Fungible(offered_asset), &Asset::Fungible(requested_asset), @@ -259,7 +259,7 @@ pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { .await? .with_context(|| format!("Output note {} not found", expected_output_notes[0].id()))?; - let tag = SwapNote::build_tag( + let tag = SwapNote::create_tag( NoteType::Private, &Asset::Fungible(offered_asset), &Asset::Fungible(requested_asset), diff --git a/bin/miden-bench/src/deploy.rs b/bin/miden-bench/src/deploy.rs index 4d56a98140..83146f9290 100644 --- a/bin/miden-bench/src/deploy.rs +++ b/bin/miden-bench/src/deploy.rs @@ -96,14 +96,14 @@ fn create_account_with_empty_maps( // Basic wallet for normal operations let wallet_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], BasicWallet::component_metadata(), ) .expect("basic wallet component should satisfy account component requirements"); let account = AccountBuilder::new(seed) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( sk.public_key().to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) diff --git a/bin/miden-bench/src/generators/large_account.rs b/bin/miden-bench/src/generators/large_account.rs index deb6355dae..70a65713e2 100644 --- a/bin/miden-bench/src/generators/large_account.rs +++ b/bin/miden-bench/src/generators/large_account.rs @@ -172,14 +172,14 @@ mod tests { // Wallet component: provides standard wallet operations (no storage slots) let wallet_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], BasicWallet::component_metadata(), ) .expect("basic wallet component should satisfy account component requirements"); let account = AccountBuilder::new(config.seed) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( sk.public_key().to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) diff --git a/bin/miden-cli/Cargo.toml b/bin/miden-cli/Cargo.toml index 7e30f71195..69b68ab6ac 100644 --- a/bin/miden-cli/Cargo.toml +++ b/bin/miden-cli/Cargo.toml @@ -48,8 +48,8 @@ miden-client = { features = ["std"], workspace = true } anyhow = { workspace = true } assert_cmd = { workspace = true } miden-client = { features = ["testing"], workspace = true } -miden-mast-package = { version = "0.25.8" } -midenc-hir-type = { version = "0.9" } +miden-mast-package = { version = "0.29" } +midenc-hir-type = { version = "0.10" } predicates = { workspace = true } regex = { workspace = true } serial_test = { features = ["file_locks"], version = "3.0" } diff --git a/bin/miden-cli/build.rs b/bin/miden-cli/build.rs index 9525f6bf9b..bd8b3e73a7 100644 --- a/bin/miden-cli/build.rs +++ b/bin/miden-cli/build.rs @@ -3,48 +3,50 @@ use std::{env, fs}; use miden_client::account::component::{ AccountComponentMetadata, + AuthGuardedMultisig, AuthMultisig, + AuthNetworkAccount, AuthSingleSig, - AuthSingleSigAcl, BasicWallet, FungibleFaucet, MIDEN_PACKAGE_EXTENSION, NoAuth, + NonFungibleFaucet, }; -use miden_client::assembly::Library; use miden_client::utils::Serializable; -use miden_client::vm::{ - Package, - PackageExport, - ProcedureExport, - QualifiedProcedureName, - Section, - SectionId, - TargetType, -}; +use miden_client::vm::{Package, Section, SectionId, TargetType}; const PACKAGE_DIR: &str = "packages"; fn main() { // Basic wallet (no storage schema) let basic_wallet_metadata = BasicWallet::component_metadata(); - build_package("basic-wallet", BasicWallet::code().as_library(), &basic_wallet_metadata, None); + build_package("basic-wallet", BasicWallet::code().as_package(), &basic_wallet_metadata, None); // Basic fungible faucet let basic_faucet_metadata = FungibleFaucet::component_metadata(); build_package( "basic-fungible-faucet", - FungibleFaucet::code().as_library(), + FungibleFaucet::code().as_package(), &basic_faucet_metadata, None, ); + // Basic non-fungible faucet + let non_fungible_faucet_metadata = NonFungibleFaucet::component_metadata(); + build_package( + "basic-non-fungible-faucet", + NonFungibleFaucet::code().as_package(), + &non_fungible_faucet_metadata, + None, + ); + // Basic auth (singlesig - supports both RPO Falcon and ECDSA) let singlesig_metadata = AuthSingleSig::component_metadata(); build_package( "basic-auth", - AuthSingleSig::code().as_library(), + AuthSingleSig::code().as_package(), &singlesig_metadata, Some("auth"), ); @@ -52,7 +54,7 @@ fn main() { // ECDSA auth (same component, different package name for discoverability) build_package( "ecdsa-auth", - AuthSingleSig::code().as_library(), + AuthSingleSig::code().as_package(), &singlesig_metadata, Some("auth"), ); @@ -60,65 +62,53 @@ fn main() { // No authentication component. Nonce is incremented on first transaction and when the account // state is changed. Provides no cryptographic authentication. let no_auth_metadata = NoAuth::component_metadata(); - build_package("no-auth", NoAuth::code().as_library(), &no_auth_metadata, Some("auth")); + build_package("no-auth", NoAuth::code().as_package(), &no_auth_metadata, Some("auth")); // Multisig auth let multisig_metadata = AuthMultisig::component_metadata(); build_package( "multisig-auth", - AuthMultisig::code().as_library(), + AuthMultisig::code().as_package(), &multisig_metadata, Some("auth"), ); - // ACL auth - let acl_metadata = AuthSingleSigAcl::component_metadata(); - build_package("acl-auth", AuthSingleSigAcl::code().as_library(), &acl_metadata, Some("auth")); + // Guarded multisig auth + let guarded_multisig_metadata = AuthGuardedMultisig::component_metadata(); + build_package( + "guarded-multisig-auth", + AuthGuardedMultisig::code().as_package(), + &guarded_multisig_metadata, + Some("auth"), + ); + + // Network account auth + let network_account_metadata = AuthNetworkAccount::component_metadata(); + build_package( + "network-account-auth", + AuthNetworkAccount::code().as_package(), + &network_account_metadata, + Some("auth"), + ); } /// Builds a package and stores it under `{OUT_DIR}/{PACKAGE_DIR}` or /// `{OUT_DIR}/{PACKAGE_DIR}/{subdirectory}` if a subdirectory is provided. pub fn build_package( package_name: &str, - library: &Library, + component_package: &Package, metadata: &AccountComponentMetadata, subdirectory: Option<&str>, ) { - // NOTE: Taken from the miden-compiler's build_package function: - // https://github.com/0xMiden/compiler/blob/61ee77f57c07c197323728642f8feca972b24217/midenc-compile/src/stages/assemble.rs#L71-L88 - // Gather all of the procedure metadata for exports of this package - let mut exports: Vec = Vec::new(); - for module_info in library.module_infos() { - for (_, proc_info) in module_info.procedures() { - let name = QualifiedProcedureName::new(module_info.path(), proc_info.name.clone()); - let export = ProcedureExport { - path: name.into_inner(), - node: None, - source_node: None, - digest: proc_info.digest, - signature: proc_info.signature.as_deref().cloned(), - attributes: proc_info.attributes.clone(), - }; - exports.push(PackageExport::Procedure(export)); - } - } - - let mast = library.mast_forest().clone(); - - let account_component_metadata_section = - Section::new(SectionId::ACCOUNT_COMPONENT_METADATA, metadata.to_bytes()); - - let mut package = Package::create( - metadata.name().to_string().into(), - metadata.version().clone(), - TargetType::AccountComponent, - mast, - exports, - [], - ) - .expect("package creation failed"); + // The component's code is already a package carrying its MAST forest and exports, so it only + // needs the component's identity and its metadata section on top. + let mut package = component_package.clone(); + package.name = metadata.name().to_string().into(); + package.version = metadata.version().clone(); + package.kind = TargetType::AccountComponent; package.description = Some(metadata.description().to_string()); - package.sections = vec![account_component_metadata_section]; + package.sections = + vec![Section::new(SectionId::ACCOUNT_COMPONENT_METADATA, metadata.to_bytes())]; let out_dir = env::var("OUT_DIR").expect("OUT_DIR environment variable not set"); diff --git a/bin/miden-cli/src/commands/call.rs b/bin/miden-cli/src/commands/call.rs index 5b7cf6cbbf..7fc478ce32 100644 --- a/bin/miden-cli/src/commands/call.rs +++ b/bin/miden-cli/src/commands/call.rs @@ -106,7 +106,7 @@ impl CallCmd { // it at compile time to resolve `call.` to a known procedure — otherwise it // emits a "phantom target" warning. Dynamic linking provides that resolution without // embedding the library bytes in the script. - let linked_builder = client.code_builder().with_dynamically_linked_library(&package)?; + let linked_builder = client.code_builder().with_dynamically_linked_package(&package)?; // 1) Read-only execution to get return values. If `result_felts` is unknown we skip // the drop sequence and let `print_output_stack` auto-detect results from the stack. diff --git a/bin/miden-cli/src/commands/init.rs b/bin/miden-cli/src/commands/init.rs index 8a808a6931..832afa9f32 100644 --- a/bin/miden-cli/src/commands/init.rs +++ b/bin/miden-cli/src/commands/init.rs @@ -35,6 +35,13 @@ const FAUCET_PACKAGE: (&str, &[u8]) = ( include_bytes!(concat!(env!("OUT_DIR"), "/packages/", "basic-fungible-faucet.masp")), ); +/// Contains the account component template file generated on build.rs, corresponding to the +/// non-fungible faucet component. +const NON_FUNGIBLE_FAUCET_PACKAGE: (&str, &[u8]) = ( + "basic-non-fungible-faucet.masp", + include_bytes!(concat!(env!("OUT_DIR"), "/packages/", "basic-non-fungible-faucet.masp")), +); + // AUTH COMPONENT PACKAGES // ================================================================================================ @@ -50,11 +57,6 @@ const ECDSA_AUTH_PACKAGE: (&str, &[u8]) = ( include_bytes!(concat!(env!("OUT_DIR"), "/packages/auth/", "ecdsa-auth.masp")), ); -const ACL_AUTH_PACKAGE: (&str, &[u8]) = ( - "auth/acl-auth.masp", - include_bytes!(concat!(env!("OUT_DIR"), "/packages/auth/", "acl-auth.masp")), -); - const NO_AUTH_PACKAGE: (&str, &[u8]) = ( "auth/no-auth.masp", include_bytes!(concat!(env!("OUT_DIR"), "/packages/auth/", "no-auth.masp")), @@ -65,14 +67,26 @@ const MULTISIG_AUTH_PACKAGE: (&str, &[u8]) = ( include_bytes!(concat!(env!("OUT_DIR"), "/packages/auth/", "multisig-auth.masp")), ); -const DEFAULT_INCLUDED_PACKAGES: [(&str, &[u8]); 7] = [ +const GUARDED_MULTISIG_AUTH_PACKAGE: (&str, &[u8]) = ( + "auth/guarded-multisig-auth.masp", + include_bytes!(concat!(env!("OUT_DIR"), "/packages/auth/", "guarded-multisig-auth.masp")), +); + +const NETWORK_ACCOUNT_AUTH_PACKAGE: (&str, &[u8]) = ( + "auth/network-account-auth.masp", + include_bytes!(concat!(env!("OUT_DIR"), "/packages/auth/", "network-account-auth.masp")), +); + +const DEFAULT_INCLUDED_PACKAGES: [(&str, &[u8]); 9] = [ BASIC_WALLET_PACKAGE, FAUCET_PACKAGE, + NON_FUNGIBLE_FAUCET_PACKAGE, BASIC_AUTH_PACKAGE, ECDSA_AUTH_PACKAGE, NO_AUTH_PACKAGE, MULTISIG_AUTH_PACKAGE, - ACL_AUTH_PACKAGE, + GUARDED_MULTISIG_AUTH_PACKAGE, + NETWORK_ACCOUNT_AUTH_PACKAGE, ]; // INIT COMMAND diff --git a/bin/miden-cli/src/commands/new_account.rs b/bin/miden-cli/src/commands/new_account.rs index 94498e61d0..236fd2ce73 100644 --- a/bin/miden-cli/src/commands/new_account.rs +++ b/bin/miden-cli/src/commands/new_account.rs @@ -537,12 +537,12 @@ async fn create_client_account( // Add the auth component (either from packages or default Falcon) let key_pair = if let Some(auth_component) = auth_component { debug!("Adding auth component from package"); - builder = builder.with_auth_component(auth_component); + builder = builder.with_component(auth_component); None } else { debug!("Adding default Falcon auth component"); let kp = AuthSecretKey::new_falcon512_poseidon2_with_rng(client.rng()); - builder = builder.with_auth_component(AuthSingleSig::new(Approver::new( + builder = builder.with_component(AuthSingleSig::new(Approver::new( kp.public_key().to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))); diff --git a/bin/miden-cli/tests/cli.rs b/bin/miden-cli/tests/cli.rs index ee51defc18..eb67cd5239 100644 --- a/bin/miden-cli/tests/cli.rs +++ b/bin/miden-cli/tests/cli.rs @@ -197,6 +197,24 @@ fn miden_directory_structure_creation() { let basic_faucet_package = packages_dir.join("basic-fungible-faucet.masp"); assert!(basic_faucet_package.exists(), "basic-fungible-faucet package should be created"); + let non_fungible_faucet_package = packages_dir.join("basic-non-fungible-faucet.masp"); + assert!( + non_fungible_faucet_package.exists(), + "basic-non-fungible-faucet package should be created" + ); + + let guarded_multisig_auth_package = packages_dir.join("auth/guarded-multisig-auth.masp"); + assert!( + guarded_multisig_auth_package.exists(), + "guarded-multisig-auth package should be created" + ); + + let network_account_auth_package = packages_dir.join("auth/network-account-auth.masp"); + assert!( + network_account_auth_package.exists(), + "network-account-auth package should be created" + ); + // Verify config file contains correct paths relative to config file location let config_content = std::fs::read_to_string(&config_file).unwrap(); assert!( @@ -1702,9 +1720,7 @@ fn call_nonexistent_procedure() { /// Helper: builds the `call-test` package (arithmetic + storage procedures) at runtime and /// writes the serialized `.masp` to `out_path`. -fn call_test_exports( - library: &miden_client::assembly::Library, -) -> Vec { +fn call_test_exports(package: &miden_client::vm::Package) -> Vec { use miden_client::vm::{PackageExport, ProcedureExport, QualifiedProcedureName}; use midenc_hir_type::{CallConv, FunctionType, Type}; @@ -1725,9 +1741,10 @@ fn call_test_exports( ]; let mut exports = Vec::new(); - for module_info in library.module_infos() { - for (_, proc_info) in module_info.procedures() { - let name = QualifiedProcedureName::new(module_info.path(), proc_info.name.clone()); + for module_descriptor in package.module_descriptors() { + for (_, proc_info) in module_descriptor.procedures() { + let name = + QualifiedProcedureName::new(module_descriptor.path(), proc_info.name.clone()); let override_sig = signature_overrides .iter() .find(|(n, _)| *n == proc_info.name.as_str()) @@ -1755,7 +1772,7 @@ fn build_call_test_masp(out_path: &Path) { ValueSlotSchema, WordSchema, }; - use miden_client::assembly::{CodeBuilder, Library}; + use miden_client::assembly::CodeBuilder; use miden_client::vm::{Package, Section, SectionId, TargetType}; let call_test_code = r#" @@ -1790,7 +1807,7 @@ fn build_call_test_masp(out_path: &Path) { end "#; - let library: Library = CodeBuilder::default() + let component_package: Package = CodeBuilder::default() .compile_component_code("miden::testing::call_test", call_test_code) .expect("failed to compile call-test component") .into(); @@ -1813,8 +1830,8 @@ fn build_call_test_masp(out_path: &Path) { let metadata = AccountComponentMetadata::new("call-test").with_storage_schema(storage_schema); - let exports = call_test_exports(&library); - let modules = library.module_infos().map(|module_info| { + let exports = call_test_exports(&component_package); + let modules = component_package.module_descriptors().map(|module_info| { miden_mast_package::PackageModule::new( std::sync::Arc::from(module_info.path().to_path_buf().into_boxed_path()), module_info @@ -1829,7 +1846,7 @@ fn build_call_test_masp(out_path: &Path) { metadata.name().to_string().into(), metadata.version().clone(), TargetType::AccountComponent, - library.mast_forest().clone(), + component_package.mast_forest().clone(), exports, modules, [], @@ -2113,43 +2130,7 @@ fn create_account_with_multisig_auth() { create_account_cmd.current_dir(&temp_dir).assert().success(); } -/// Tests creating an account with the acl-auth component. -#[test] -fn create_account_with_acl_auth() { - let temp_dir = init_cli().1; - - // Create init storage data file for acl-auth with a test public key - let init_storage_data_toml = r#" - "miden::standards::auth::singlesig_acl::pub_key" = "0x0000000000000000000000000000000000000000000000000000000000000001" - "miden::standards::auth::singlesig_acl::scheme" = "Falcon512Poseidon2" - "miden::standards::auth::singlesig_acl::config.num_trigger_procs" = "1" - "miden::standards::auth::singlesig_acl::config.allow_unauthorized_output_notes" = "0" - "miden::standards::auth::singlesig_acl::config.allow_unauthorized_input_notes" = "0" - - "miden::standards::auth::singlesig_acl::trigger_procedure_roots" = [ - { key = ["0", "0", "0", "0"], value = "0xd2d1b6229d7cfb9f2ada31c5cb61453cf464f91828e124437c708eec55b9cd07" } - ] - "#; - let file_path = temp_dir.join("acl_init_data.toml"); - fs::write(&file_path, init_storage_data_toml).unwrap(); - - let mut create_account_cmd = cargo_bin_cmd!("miden-client"); - create_account_cmd.args([ - "new-account", - "-t", - "private", - "-p", - "basic-wallet", - "-p", - "auth/acl-auth", - "-i", - "acl_init_data.toml", - ]); - - create_account_cmd.current_dir(&temp_dir).assert().success(); -} - -// Tests creating an account with the acl-auth component. +/// Tests creating an account with the ecdsa-auth component. #[test] fn create_account_with_ecdsa_auth() { let temp_dir = init_cli().1; diff --git a/crates/rust-client/src/account/mod.rs b/crates/rust-client/src/account/mod.rs index ce7552d85b..12983bee7d 100644 --- a/crates/rust-client/src/account/mod.rs +++ b/crates/rust-client/src/account/mod.rs @@ -188,18 +188,26 @@ pub mod component { FungibleFaucetBuilder, FungibleFaucetError, LogoURI, + NonFungibleFaucet, TokenMetadata, TokenMetadataError, TokenName, create_network_fungible_faucet, create_singlesig_user_fungible_faucet, }; + pub use miden_standards::account::fees::{ + BasicConstantFeePolicy, + FeePolicy, + FeePolicyError, + FeePolicyManager, + FeePolicyManagerBuilder, + }; pub use miden_standards::account::policies::{ - AllowlistOwnerControlled, + AllowlistManager, AllowlistStorage, BasicAllowlist, BasicBlocklist, - BlocklistOwnerControlled, + BlocklistManager, BlocklistStorage, BurnAllowAll, BurnOwnerOnly, @@ -643,7 +651,7 @@ pub fn build_wallet_id( let account = AccountBuilder::new(init_seed) .account_type(account_visibility) - .with_auth_component(auth_component) + .with_component(auth_component) .with_component(BasicWallet) .build_with_schema_commitment()?; @@ -671,7 +679,7 @@ mod schema_commitment_tests { let key = AuthSecretKey::new_falcon512_poseidon2(); let account = AccountBuilder::new([2u8; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( key.public_key().to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) diff --git a/crates/rust-client/src/lib.rs b/crates/rust-client/src/lib.rs index 3dac21c41d..4926eb2b3f 100644 --- a/crates/rust-client/src/lib.rs +++ b/crates/rust-client/src/lib.rs @@ -150,6 +150,13 @@ pub mod notes { /// Provides `AggLayer` bridge components, note constructors, and helper types. pub mod agglayer { pub use miden_agglayer::*; + pub use miden_standards::interop::eth::{ + AddressConversionError, + EthAddress, + EthAmount, + EthAmountError, + EthEmbeddedAccountId, + }; } /// Provides types and utilities for working with Miden Assembly. @@ -161,14 +168,7 @@ pub mod assembly { pub use miden_protocol::assembly::diagnostics::Report; pub use miden_protocol::assembly::diagnostics::reporting::PrintDiagnostic; pub use miden_protocol::assembly::mast::MastNodeExt; - pub use miden_protocol::assembly::{ - Assembler, - DefaultSourceManager, - Library, - Module, - ModuleKind, - Path, - }; + pub use miden_protocol::assembly::{Assembler, DefaultSourceManager, Module, ModuleKind, Path}; pub use miden_standards::code_builder::CodeBuilder; } @@ -218,8 +218,6 @@ pub mod auth { AuthMultisig, AuthMultisigConfig, AuthSingleSig, - AuthSingleSigAcl, - AuthSingleSigAclConfig, NoAuth, }; pub use miden_tx::auth::{BasicAuthenticator, SigningInputs, TransactionAuthenticator}; diff --git a/crates/rust-client/src/note/mod.rs b/crates/rust-client/src/note/mod.rs index 7f9c1ada58..dac79af457 100644 --- a/crates/rust-client/src/note/mod.rs +++ b/crates/rust-client/src/note/mod.rs @@ -107,8 +107,10 @@ pub use miden_protocol::transaction::ToInputNoteCommitments; /// Raw access to `miden-standards` note modules for items not curated by `miden-client`. pub use miden_standards::note as standards; pub use miden_standards::note::{ + FeeSponsorshipNote, MintNote, MintNoteStorage, + NetworkAccountConfigNote, NetworkAccountTarget, NoteConsumptionStatus, NoteExecutionHint, @@ -121,6 +123,7 @@ pub use miden_standards::note::{ PswapNote, StandardNote, SwapNote, + TxFeeNote, }; pub use miden_tx::{FailedNote, NoteConsumptionInfo}; pub use note_reader::InputNoteReader; diff --git a/crates/rust-client/src/rpc/domain/note.rs b/crates/rust-client/src/rpc/domain/note.rs index c516e5d27e..bbb7d03746 100644 --- a/crates/rust-client/src/rpc/domain/note.rs +++ b/crates/rust-client/src/rpc/domain/note.rs @@ -4,9 +4,11 @@ use alloc::vec::Vec; use miden_protocol::account::AccountId; use miden_protocol::block::{BlockHeader, BlockNumber}; +use miden_protocol::crypto::SequentialCommit; use miden_protocol::crypto::merkle::MerklePath; use miden_protocol::note::{ Note, + NoteAttachment, NoteAttachmentHeader, NoteAttachmentScheme, NoteAttachments, @@ -21,7 +23,7 @@ use miden_protocol::note::{ NoteType, PartialNoteMetadata, }; -use miden_protocol::{MastForest, MastNodeId, Word}; +use miden_protocol::{Felt, MastForest, MastNodeId, Word}; use miden_tx::utils::serde::Deserializable; use super::{MissingFieldHelper, RpcConversionError}; @@ -129,6 +131,90 @@ impl TryFrom for NoteMetadata { } } +/// Aggregates individual attachment commitments into the note's attachments commitment. +/// +/// The element layout mirrors [`NoteAttachments`]' own sequential commitment, so hashing this +/// yields the same value as the full attachments would, without needing their contents. +// TODO: single-word attachment payloads now arrive inline in the sync response, so some note data +// may be derived without a `GetNotesById` request +// https://github.com/0xMiden/rust-sdk/issues/2360 +struct AttachmentCommitments(Vec); + +impl SequentialCommit for AttachmentCommitments { + type Commitment = Word; + + fn to_elements(&self) -> Vec { + let mut elements = Vec::with_capacity(self.0.len() * miden_protocol::WORD_SIZE); + for commitment in &self.0 { + elements.extend_from_slice(commitment.as_elements()); + } + elements + } +} + +impl TryFrom for NoteMetadata { + type Error = RpcConversionError; + + fn try_from(value: proto::note::NoteSyncMetadata) -> Result { + let sender = value + .sender + .ok_or_else(|| proto::note::NoteSyncMetadata::missing_field(stringify!(sender)))? + .try_into()?; + let note_type = note_type_from_proto(value.note_type)?; + let tag = NoteTag::new(value.tag); + let partial_metadata = PartialNoteMetadata::new(sender, note_type).with_tag(tag); + + if value.attachments.len() > NoteAttachments::MAX_COUNT { + return Err(RpcConversionError::InvalidField(format!( + "attachments length {} exceeds NoteAttachments::MAX_COUNT", + value.attachments.len(), + ))); + } + + let mut attachment_headers = [NoteAttachmentHeader::absent(); NoteAttachments::MAX_COUNT]; + let mut commitments = Vec::with_capacity(value.attachments.len()); + + for (slot, attachment) in value.attachments.into_iter().enumerate() { + let raw_scheme = u16::try_from(attachment.scheme).map_err(|_| { + RpcConversionError::InvalidField(format!( + "attachments[{slot}].scheme={} does not fit in u16", + attachment.scheme, + )) + })?; + let scheme = NoteAttachmentScheme::new(raw_scheme).map_err(|err| { + RpcConversionError::InvalidField(format!("attachments[{slot}].scheme: {err}")) + })?; + attachment_headers[slot] = NoteAttachmentHeader::new(scheme); + + let payload = attachment.payload.ok_or_else(|| { + proto::note::NoteSyncAttachment::missing_field(stringify!(payload)) + })?; + // Single-word attachments are sent verbatim, so their commitment is derived locally; + // larger ones are sent as commitments to keep the sync response bounded. + // TODO: the verbatim word is discarded here, but it could be kept to derive note data + // without a `GetNotesById` request + // https://github.com/0xMiden/rust-sdk/issues/2360 + let commitment = match payload { + proto::note::note_sync_attachment::Payload::Value(value) => { + NoteAttachment::with_word(scheme, Word::try_from(value)?).to_commitment() + }, + proto::note::note_sync_attachment::Payload::Commitment(commitment) => { + Word::try_from(commitment)? + }, + }; + commitments.push(commitment); + } + + let attachments_commitment = AttachmentCommitments(commitments).to_commitment(); + + Ok(NoteMetadata::from_parts( + partial_metadata, + attachment_headers, + attachments_commitment, + )) + } +} + impl TryFrom<&proto::note::NoteMetadata> for PartialNoteMetadata { type Error = RpcConversionError; @@ -565,3 +651,133 @@ impl TryFrom for NoteScript { Ok(NoteScript::from_parts(alloc::sync::Arc::new(mast_forest), entrypoint)) } } + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + use miden_protocol::account::{AccountIdVersion, AccountType, AssetCallbackFlag}; + + use super::*; + + fn sender() -> AccountId { + AccountId::dummy( + [1; 15], + AccountIdVersion::Version1, + AccountType::Public, + AssetCallbackFlag::Disabled, + ) + } + + /// Encodes attachments the way the node does in a sync response: single-word attachments carry + /// their value, larger ones only their commitment. + fn sync_attachments(attachments: &NoteAttachments) -> Vec { + attachments + .iter() + .map(|attachment| { + let payload = if attachment.num_words() == 1 { + proto::note::note_sync_attachment::Payload::Value( + attachment.content().as_words()[0].into(), + ) + } else { + proto::note::note_sync_attachment::Payload::Commitment( + attachment.to_commitment().into(), + ) + }; + + proto::note::NoteSyncAttachment { + scheme: u32::from(attachment.attachment_scheme().as_u16()), + payload: Some(payload), + } + }) + .collect() + } + + fn sync_metadata( + attachments: Vec, + ) -> proto::note::NoteSyncMetadata { + proto::note::NoteSyncMetadata { + sender: Some(sender().into()), + note_type: note_type_to_proto(NoteType::Private), + tag: 7, + attachments, + } + } + + #[test] + fn sync_metadata_reconstructs_metadata_with_mixed_attachments() { + let attachments = NoteAttachments::new(vec![ + NoteAttachment::with_word( + NoteAttachmentScheme::new(42).unwrap(), + Word::from([1u32, 2, 3, 4]), + ), + NoteAttachment::with_words( + NoteAttachmentScheme::new(100).unwrap(), + vec![Word::from([5u32, 6, 7, 8]), Word::from([9u32, 10, 11, 12])], + ) + .unwrap(), + ]) + .unwrap(); + + let expected = NoteMetadata::new( + PartialNoteMetadata::new(sender(), NoteType::Private).with_tag(NoteTag::new(7)), + &attachments, + ); + + let reconstructed: NoteMetadata = + sync_metadata(sync_attachments(&attachments)).try_into().unwrap(); + + assert_eq!(reconstructed, expected); + } + + #[test] + fn sync_metadata_reconstructs_metadata_without_attachments() { + let attachments = NoteAttachments::empty(); + let expected = NoteMetadata::new( + PartialNoteMetadata::new(sender(), NoteType::Private).with_tag(NoteTag::new(7)), + &attachments, + ); + + let reconstructed: NoteMetadata = sync_metadata(Vec::new()).try_into().unwrap(); + + assert_eq!(reconstructed, expected); + } + + #[test] + fn sync_metadata_rejects_too_many_attachments() { + let attachment = proto::note::NoteSyncAttachment { + scheme: 42, + payload: Some(proto::note::note_sync_attachment::Payload::Value(Word::empty().into())), + }; + let attachments = vec![attachment; NoteAttachments::MAX_COUNT + 1]; + + let err = NoteMetadata::try_from(sync_metadata(attachments)).unwrap_err(); + + assert!(matches!(err, RpcConversionError::InvalidField(_)), "got {err:?}"); + } + + #[test] + fn sync_metadata_rejects_reserved_absent_scheme() { + let attachments = vec![proto::note::NoteSyncAttachment { + scheme: 0, + payload: Some(proto::note::note_sync_attachment::Payload::Value(Word::empty().into())), + }]; + + let err = NoteMetadata::try_from(sync_metadata(attachments)).unwrap_err(); + + assert!(matches!(err, RpcConversionError::InvalidField(_)), "got {err:?}"); + } + + #[test] + fn sync_metadata_rejects_missing_attachment_payload() { + let attachments = vec![proto::note::NoteSyncAttachment { scheme: 42, payload: None }]; + + let err = NoteMetadata::try_from(sync_metadata(attachments)).unwrap_err(); + + assert!( + matches!(err, RpcConversionError::MissingFieldInProtobufRepresentation { .. }), + "got {err:?}" + ); + } +} diff --git a/crates/rust-client/src/sync/state_sync.rs b/crates/rust-client/src/sync/state_sync.rs index 167b531f45..a7a6b06f78 100644 --- a/crates/rust-client/src/sync/state_sync.rs +++ b/crates/rust-client/src/sync/state_sync.rs @@ -1419,7 +1419,7 @@ mod tests { use miden_protocol::{EMPTY_WORD, Felt, Word, ZERO}; use miden_standards::code_builder::CodeBuilder; use miden_standards::note::{NetworkAccountTarget, NoteExecutionHint}; - use miden_testing::{MockChainBuilder, TxContextInput}; + use miden_testing::{MockChainBuilder, MockTransactionInput}; use super::*; use crate::store::{OutputNoteRecord, OutputNoteState}; @@ -1701,8 +1701,7 @@ mod tests { let sync_target_header = chain.latest_block_header(); let tx = Box::pin( chain - .build_tx_context(TxContextInput::AccountId(account.id()), &[], &[]) - .unwrap() + .build_transaction(MockTransactionInput::AccountId(account.id())) .build() .unwrap() .execute(), @@ -2053,12 +2052,8 @@ mod tests { for note in [¬e1, ¬e2, ¬e3] { let tx = Box::pin( chain - .build_tx_context( - TxContextInput::Account(current_account.clone()), - &[], - core::slice::from_ref(note), - ) - .unwrap() + .build_transaction(MockTransactionInput::Account(current_account.clone())) + .unauthenticated_input_note(note.clone()) .build() .unwrap() .execute(), @@ -2251,12 +2246,9 @@ mod tests { .unwrap(); let tx = Box::pin( chain - .build_tx_context( - miden_testing::TxContextInput::Account(faucet_account.clone()), - &[], - &[], - ) - .unwrap() + .build_transaction(miden_testing::MockTransactionInput::Account( + faucet_account.clone(), + )) .extend_advice_inputs(recipient_advice.clone()) .tx_script(tx_script) .with_source_manager(source_manager) @@ -2506,12 +2498,8 @@ mod tests { let tx = Box::pin( chain - .build_tx_context( - TxContextInput::Account(sender_account.clone()), - &[], - core::slice::from_ref(¬e), - ) - .unwrap() + .build_transaction(MockTransactionInput::Account(sender_account.clone())) + .unauthenticated_input_note(note.clone()) .build() .unwrap() .execute(), diff --git a/crates/rust-client/src/test_utils/common.rs b/crates/rust-client/src/test_utils/common.rs index 877fca29f9..f166736588 100644 --- a/crates/rust-client/src/test_utils/common.rs +++ b/crates/rust-client/src/test_utils/common.rs @@ -93,7 +93,7 @@ pub async fn insert_new_wallet_with_seed( let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(auth_component) + .with_component(auth_component) .with_component(BasicWallet) .build_with_schema_commitment() .unwrap(); @@ -148,7 +148,7 @@ pub async fn insert_new_fungible_faucet( .build(); let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(auth_component) + .with_component(auth_component) .with_component(faucet) .with_components(policy_manager) .build_with_schema_commitment() @@ -634,7 +634,7 @@ pub async fn insert_account_with_custom_component( let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) diff --git a/crates/rust-client/src/transaction/mod.rs b/crates/rust-client/src/transaction/mod.rs index 1015454dc3..0f7ff69a87 100644 --- a/crates/rust-client/src/transaction/mod.rs +++ b/crates/rust-client/src/transaction/mod.rs @@ -84,6 +84,7 @@ use miden_protocol::transaction::AccountInputs; use miden_protocol::vm::MIN_STACK_DEPTH; use miden_protocol::{Felt, Word}; use miden_standards::account::faucets::FungibleFaucet; +use miden_standards::account::interface::AccountInterfaceExt; use miden_tx::{DataStore, NoteConsumptionChecker, TransactionExecutor}; use tracing::info; @@ -1180,6 +1181,8 @@ pub(super) fn validate_account_request( transaction_request: &TransactionRequest, account: &Account, ) -> Result<(), ClientError> { + validate_fee_conversion_info_support(transaction_request, account)?; + if account.code_interface().contains([FungibleFaucet::mint_and_send_root()]) { // TODO(SantiagoPittella): Add faucet validations. Ok(()) @@ -1188,6 +1191,34 @@ pub(super) fn validate_account_request( } } +/// Verifies that the account can consume fee conversion info passed through the auth args. +/// +/// Only the signature-based auth components read the auth args as conversion info (through +/// `miden::standards::fee`). On any other auth component the declared asset and rate would be +/// silently ignored and the fee paid in the chain's native asset, so the request is rejected here +/// instead. +fn validate_fee_conversion_info_support( + transaction_request: &TransactionRequest, + account: &Account, +) -> Result<(), ClientError> { + if !transaction_request.declares_fee_conversion_info() { + return Ok(()); + } + + let interface = AccountInterface::from_account(account); + let auth_component = interface.auth_component(); + if matches!( + auth_component, + AccountComponentInterface::AuthSingleSig | AccountComponentInterface::AuthMultisig + ) { + return Ok(()); + } + + Err(ClientError::TransactionRequestError( + TransactionRequestError::FeeConversionInfoUnsupported(auth_component.name()), + )) +} + /// Verifies that every output note emitted directly by the transaction declares `account_id` as /// its sender. /// @@ -1375,7 +1406,8 @@ mod tests { use alloc::vec; use miden_protocol::Word; - use miden_protocol::account::AccountId; + use miden_protocol::account::auth::AuthSecretKey; + use miden_protocol::account::{AccountBuilder, AccountComponent, AccountId, AccountType}; use miden_protocol::asset::FungibleAsset; use miden_protocol::crypto::rand::RandomCoin; use miden_protocol::note::{Note, NoteType}; @@ -1384,10 +1416,21 @@ mod tests { ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, ACCOUNT_ID_SENDER, }; + use miden_standards::account::AccountBuilderSchemaCommitmentExt; + use miden_standards::account::auth::{Approver, AuthSingleSig, FeeConversionInfo, NoAuth}; + use miden_standards::account::wallets::BasicWallet; use miden_standards::note::P2idNote; - use super::{TransactionRequestBuilder, validate_output_note_senders}; + use super::{ + Account, + AccountComponentInterface, + TransactionRequest, + TransactionRequestBuilder, + validate_fee_conversion_info_support, + validate_output_note_senders, + }; use crate::ClientError; + use crate::auth::AuthSchemeId; use crate::transaction::TransactionRequestError; fn own_note_with_sender(sender: AccountId) -> Note { @@ -1458,4 +1501,59 @@ mod tests { validate_output_note_senders(&request, account_id).unwrap(); } + + /// Builds an account carrying `auth_component` and a basic wallet. + fn account_with_auth(auth_component: impl Into) -> Account { + AccountBuilder::new([7u8; 32]) + .account_type(AccountType::Public) + .with_component(auth_component) + .with_component(BasicWallet) + .build_with_schema_commitment() + .expect("account creation failed") + } + + fn fee_conversion_request() -> TransactionRequest { + let faucet_id = AccountId::try_from(ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET).unwrap(); + + TransactionRequestBuilder::new() + .fee_conversion_info(FeeConversionInfo::one_to_one(faucet_id), Word::default()) + .build() + .unwrap() + } + + #[test] + fn fee_conversion_info_is_accepted_by_a_signature_authenticated_account() { + let key = AuthSecretKey::new_falcon512_poseidon2(); + let auth = AuthSingleSig::new(Approver::new( + key.public_key().to_commitment(), + AuthSchemeId::Falcon512Poseidon2, + )); + + validate_fee_conversion_info_support(&fee_conversion_request(), &account_with_auth(auth)) + .unwrap(); + } + + #[test] + fn fee_conversion_info_is_rejected_by_an_account_that_cannot_read_it() { + let account = account_with_auth(NoAuth); + + let err = validate_fee_conversion_info_support(&fee_conversion_request(), &account) + .expect_err("NoAuth does not read the auth args"); + match err { + ClientError::TransactionRequestError( + TransactionRequestError::FeeConversionInfoUnsupported(auth_component), + ) => assert_eq!(auth_component, AccountComponentInterface::AuthNoAuth.name()), + other => panic!("expected FeeConversionInfoUnsupported, got {other:?}"), + } + } + + #[test] + fn a_request_without_fee_conversion_info_skips_the_auth_component_check() { + // `NoAuth` cannot read conversion info, but a request that declares none is unaffected. + validate_fee_conversion_info_support( + &TransactionRequestBuilder::new().build().unwrap(), + &account_with_auth(NoAuth), + ) + .unwrap(); + } } diff --git a/crates/rust-client/src/transaction/request/builder.rs b/crates/rust-client/src/transaction/request/builder.rs index 935d6582be..7cc289de64 100644 --- a/crates/rust-client/src/transaction/request/builder.rs +++ b/crates/rust-client/src/transaction/request/builder.rs @@ -14,7 +14,6 @@ use miden_protocol::note::{ Note, NoteAssets, NoteAttachment, - NoteAttachments, NoteDetails, NoteDetailsCommitment, NoteId, @@ -29,6 +28,7 @@ use miden_protocol::note::{ use miden_protocol::transaction::TransactionScript; use miden_protocol::vm::AdviceMap; use miden_protocol::{Felt, Word}; +use miden_standards::account::auth::{FeeConversionInfo, commit_fee_conversion_info}; use miden_standards::note::{P2idNote, P2ideNote, PswapNote, PswapNoteStorage, SwapNote}; use super::{ @@ -90,6 +90,10 @@ pub struct TransactionRequestBuilder { /// Optional [`Word`] that will be pushed to the stack for the authentication procedure /// during transaction execution. auth_arg: Option, + /// Whether the auth arg carries fee conversion info set through + /// [`TransactionRequestBuilder::fee_conversion_info`], which only accounts with a + /// fee-conversion-aware auth component can consume. + declares_fee_conversion_info: bool, /// Note scripts that the node's NTX builder will need in its script registry. /// /// See [`TransactionRequestBuilder::expected_ntx_scripts`] for details. @@ -116,6 +120,7 @@ impl TransactionRequestBuilder { ignore_invalid_input_notes: false, script_arg: None, auth_arg: None, + declares_fee_conversion_info: false, expected_ntx_scripts: vec![], } } @@ -270,6 +275,21 @@ impl TransactionRequestBuilder { self } + /// Declares the asset the transaction fee is paid in, and the rate converting the chain's + /// native fee into it. + /// + /// The info is committed to through the transaction's auth args, so it only has an effect on + /// accounts whose auth component reads them: [`AuthSingleSig`](crate::auth::AuthSingleSig) and + /// [`AuthMultisig`](crate::auth::AuthMultisig). Executing + /// such a request against an account with any other auth component is rejected before execution + /// with [`TransactionRequestError::FeeConversionInfoUnsupported`]. + #[must_use] + pub fn fee_conversion_info(mut self, conversion_info: FeeConversionInfo, salt: Word) -> Self { + let (auth_arg, preimage) = commit_fee_conversion_info(conversion_info, salt); + self.declares_fee_conversion_info = true; + self.auth_arg(auth_arg).extend_advice_map([(auth_arg, preimage)]) + } + /// Specifies note scripts that the node's network transaction (NTX) builder will need in /// its script registry. /// @@ -383,15 +403,17 @@ impl TransactionRequestBuilder { ) -> Result { // The created note is the one that we need as the output of the tx, the other one is the // one that we expect to receive and consume eventually. - let (created_note, payback_note_details) = SwapNote::create( - swap_data.account_id(), - swap_data.offered_asset(), - swap_data.requested_asset(), - note_type, - NoteAttachments::empty(), - payback_note_type, - rng, - )?; + let swap_note = SwapNote::builder() + .sender(swap_data.account_id()) + .offered_asset(swap_data.offered_asset()) + .requested_asset(swap_data.requested_asset()) + .note_type(note_type) + .payback_note_type(payback_note_type) + .generate_serial_number(rng) + .build()?; + + let payback_note_details = swap_note.payback_note_details(); + let created_note = Note::from(swap_note); let payback_tag = NoteTag::with_account_target(swap_data.account_id()); @@ -612,6 +634,7 @@ impl TransactionRequestBuilder { ignore_invalid_input_notes: self.ignore_invalid_input_notes, script_arg: self.script_arg, auth_arg: self.auth_arg, + declares_fee_conversion_info: self.declares_fee_conversion_info, expected_ntx_scripts: self.expected_ntx_scripts, }) } diff --git a/crates/rust-client/src/transaction/request/mod.rs b/crates/rust-client/src/transaction/request/mod.rs index bc6b45f30c..6ef31db58c 100644 --- a/crates/rust-client/src/transaction/request/mod.rs +++ b/crates/rust-client/src/transaction/request/mod.rs @@ -123,6 +123,10 @@ pub struct TransactionRequest { /// Optional [`Word`] that will be pushed to the stack for the authentication procedure /// during transaction execution. auth_arg: Option, + /// Whether the auth arg carries fee conversion info set through + /// [`TransactionRequestBuilder::fee_conversion_info`], which only accounts with a + /// fee-conversion-aware auth component can consume. + declares_fee_conversion_info: bool, /// Note scripts that the node's NTX builder will need in its script registry. /// /// See [`TransactionRequestBuilder::expected_ntx_scripts`] for details. @@ -232,6 +236,12 @@ impl TransactionRequest { &self.auth_arg } + /// Returns whether the auth arg carries fee conversion info set through + /// [`TransactionRequestBuilder::fee_conversion_info`]. + pub fn declares_fee_conversion_info(&self) -> bool { + self.declares_fee_conversion_info + } + /// Returns the expected NTX scripts that the node's NTX builder will need in its registry. pub fn expected_ntx_scripts(&self) -> &[NoteScript] { &self.expected_ntx_scripts @@ -299,7 +309,7 @@ impl TransactionRequest { /// Miden host. pub(crate) fn into_transaction_args( self, - tx_script: Option, + tx_script: Option<(TransactionScript, Option)>, ) -> TransactionArgs { let note_args = self.get_note_args(); let TransactionRequest { @@ -314,9 +324,9 @@ impl TransactionRequest { // A script argument without a script has nothing to bind to, so it is only applied when a // transaction script is present. With no argument the default empty word is used, which is // equivalent to setting no argument at all. - if let Some(tx_script) = tx_script { - tx_args = - tx_args.with_tx_script_and_args(tx_script, self.script_arg.unwrap_or_default()); + if let Some((tx_script, script_args)) = tx_script { + let script_args = script_args.or(self.script_arg).unwrap_or_default(); + tx_args = tx_args.with_tx_script_and_args(tx_script, script_args); } if let Some(auth_argument) = self.auth_arg { @@ -332,8 +342,13 @@ impl TransactionRequest { /// Builds the transaction script based on the account capabilities and the transaction request. /// - /// Returns `None` when the request carries no script template, producing a transaction with no - /// transaction script (a zero script root). + /// Returns the script together with the `TX_SCRIPT_ARGS` word it must be executed with, if the + /// script determines it. The `SendNotes` script reads the notes it creates from the advice + /// provider and only receives their payload commitment on the stack, so its argument + /// is fixed by the notes the script was built for, and passing anything else + /// makes the script fail to resolve its payload. A caller-supplied + /// [`TransactionScriptTemplate::CustomScript`] carries no such constraint and yields `None`, so + /// the request's own [`TransactionRequestBuilder::script_arg`] applies to it. /// /// Scripts supplied by the caller via [`TransactionScriptTemplate::CustomScript`] are expected /// to have already been compiled against the client's source manager (e.g. via @@ -341,9 +356,11 @@ impl TransactionRequest { pub(crate) fn build_transaction_script( &self, code_interface: &AccountCodeInterface, - ) -> Result, TransactionRequestError> { + ) -> Result)>, TransactionRequestError> { match &self.script_template { - Some(TransactionScriptTemplate::CustomScript(script)) => Ok(Some(script.clone())), + Some(TransactionScriptTemplate::CustomScript(script)) => { + Ok(Some((script.clone(), None))) + }, Some(TransactionScriptTemplate::SendNotes(notes)) => { let script = match self.expiration_delta.and_then(NonZeroU16::new) { Some(delta) => SendNotesTransactionScript::with_expiration_delta( @@ -353,7 +370,7 @@ impl TransactionRequest { )?, None => SendNotesTransactionScript::new(code_interface, notes)?, }; - Ok(Some(script.into())) + Ok(Some((script.tx_script().clone(), Some(script.tx_script_args())))) }, None => Ok(None), } @@ -388,6 +405,7 @@ impl Serializable for TransactionRequest { target.write_u8(u8::from(self.ignore_invalid_input_notes)); self.script_arg.write_into(target); self.auth_arg.write_into(target); + target.write_u8(u8::from(self.declares_fee_conversion_info)); self.expected_ntx_scripts.write_into(target); } } @@ -428,6 +446,7 @@ impl Deserializable for TransactionRequest { let ignore_invalid_input_notes = source.read_u8()? == 1; let script_arg = Option::::read_from(source)?; let auth_arg = Option::::read_from(source)?; + let declares_fee_conversion_info = source.read_u8()? == 1; let expected_ntx_scripts = Vec::::read_from(source)?; Ok(TransactionRequest { @@ -443,6 +462,7 @@ impl Deserializable for TransactionRequest { ignore_invalid_input_notes, script_arg, auth_arg, + declares_fee_conversion_info, expected_ntx_scripts, }) } @@ -516,6 +536,10 @@ pub enum TransactionRequestError { "output note declares sender {actual} but the transaction is executed by account {expected}" )] OutputNoteSenderMismatch { expected: AccountId, actual: AccountId }, + #[error( + "the request declares fee conversion info but the account's auth component {0} does not read it" + )] + FeeConversionInfoUnsupported(String), #[error("invalid transaction script")] InvalidTransactionScript(#[from] TransactionScriptError), #[error("merkle proof error")] @@ -644,7 +668,7 @@ mod tests { let account = AccountBuilder::new(Default::default()) .with_component(MockAccountComponent::with_empty_slots()) - .with_auth_component(auth_component()) + .with_component(auth_component()) .account_type(AccountType::Private) .build_existing() .unwrap(); diff --git a/crates/rust-client/src/transaction/store_update.rs b/crates/rust-client/src/transaction/store_update.rs index c50ec93ec4..d1b28f9fc4 100644 --- a/crates/rust-client/src/transaction/store_update.rs +++ b/crates/rust-client/src/transaction/store_update.rs @@ -126,7 +126,7 @@ mod tests { ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, ACCOUNT_ID_SENDER, }; - use miden_testing::{MockChainBuilder, TxContextInput}; + use miden_testing::{MockChainBuilder, MockTransactionInput}; use super::*; use crate::note::NoteUpdateTracker; @@ -151,12 +151,8 @@ mod tests { let executed_tx = Box::pin( chain - .build_tx_context( - TxContextInput::Account(account.clone()), - &[], - core::slice::from_ref(¬e), - ) - .unwrap() + .build_transaction(MockTransactionInput::Account(account.clone())) + .unauthenticated_input_note(note.clone()) .build() .unwrap() .execute(), diff --git a/crates/sqlite-store/src/account/helpers.rs b/crates/sqlite-store/src/account/helpers.rs index 7dd89d106b..242253744d 100644 --- a/crates/sqlite-store/src/account/helpers.rs +++ b/crates/sqlite-store/src/account/helpers.rs @@ -13,7 +13,7 @@ use miden_client::account::{ StorageSlotName, StorageSlotType, }; -use miden_client::asset::Asset; +use miden_client::asset::{Asset, AssetId}; use miden_client::store::{AccountStatus, AccountStorageFilter, ClientAccountType, StoreError}; use miden_client::{Deserializable, Serializable, Word}; use rusqlite::types::Value; @@ -214,9 +214,9 @@ pub(crate) fn query_vault_assets( .into_store_error()? .map(|result| { let (asset_id_bytes, asset_bytes): (Vec, Vec) = result.into_store_error()?; - let key_word = Word::read_from_bytes(&asset_id_bytes)?; + let asset_id = AssetId::read_from_bytes(&asset_id_bytes)?; let value_word = Word::read_from_bytes(&asset_bytes)?; - Ok(Asset::from_id_and_value_words(key_word, value_word)?) + Ok(Asset::from_id_and_value_words(asset_id.to_word(), value_word)?) }) .collect::, StoreError>>() } diff --git a/crates/sqlite-store/src/account/tests.rs b/crates/sqlite-store/src/account/tests.rs index f6d8a4e0e6..0641a8ec32 100644 --- a/crates/sqlite-store/src/account/tests.rs +++ b/crates/sqlite-store/src/account/tests.rs @@ -114,7 +114,7 @@ async fn apply_account_patch_additions() -> anyhow::Result<()> { StorageSlotName::new("miden::testing::sqlite_store::mapB").expect("valid slot name"); let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![ StorageSlot::with_empty_value(value_slot_name.clone()), StorageSlot::with_empty_map(map_slot_name.clone()), @@ -126,7 +126,7 @@ async fn apply_account_patch_additions() -> anyhow::Result<()> { // Create and insert an account let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -236,7 +236,7 @@ async fn apply_account_patch_preserves_fungible_callback_flag() -> anyhow::Resul // Create and insert an account with an empty vault. let account = AccountBuilder::new([7; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -321,7 +321,7 @@ async fn apply_account_patch_removals() -> anyhow::Result<()> { .insert(StorageMapKey::new([ONE, ZERO, ZERO, ZERO].into()), [ONE, ONE, ONE, ONE].into())?; let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![ StorageSlot::with_value(value_slot_name.clone(), [ZERO, ZERO, ZERO, ONE].into()), StorageSlot::with_map(map_slot_name.clone(), dummy_map), @@ -340,7 +340,7 @@ async fn apply_account_patch_removals() -> anyhow::Result<()> { ]; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -437,14 +437,14 @@ async fn get_account_storage_item_success() -> anyhow::Result<()> { let test_value: [miden_client::Felt; 4] = [ONE, ONE, ONE, ONE]; let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_value(value_slot_name.clone(), test_value.into())], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -472,14 +472,14 @@ async fn get_account_storage_item_not_found() -> anyhow::Result<()> { StorageSlotName::new("miden::testing::sqlite_store::value").expect("valid slot name"); let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_empty_value(value_slot_name)], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -515,14 +515,14 @@ async fn get_account_map_item_success() -> anyhow::Result<()> { storage_map.insert(test_key, test_value)?; let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_map(map_slot_name.clone(), storage_map)], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -551,14 +551,14 @@ async fn get_account_map_item_value_slot_error() -> anyhow::Result<()> { StorageSlotName::new("miden::testing::sqlite_store::value").expect("valid slot name"); let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_empty_value(value_slot_name.clone())], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -584,14 +584,14 @@ async fn get_account_code() -> anyhow::Result<()> { let store = create_test_store().await; let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -639,14 +639,14 @@ async fn account_reader_nonce_and_status() -> anyhow::Result<()> { let store = Arc::new(create_test_store().await); let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -717,14 +717,14 @@ async fn account_reader_storage_access() -> anyhow::Result<()> { let test_value: [miden_client::Felt; 4] = [ONE, ONE, ONE, ONE]; let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_value(value_slot_name.clone(), test_value.into())], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -756,14 +756,14 @@ async fn account_reader_addresses_access() -> anyhow::Result<()> { let store = Arc::new(create_test_store().await); let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -888,13 +888,13 @@ async fn prune_account_history_multiple_accounts() -> anyhow::Result<()> { // Account B: different seed to different account. We need a different builder seed. let component_b = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_empty_map(map_slot_name_b.clone())], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account_b = AccountBuilder::new([1; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -1095,14 +1095,14 @@ async fn setup_account_with_map( } let component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_map(map_slot_name.clone(), map)], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -1303,14 +1303,14 @@ async fn undo_account_state_deletes_account_entirely() -> anyhow::Result<()> { )?; } let component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_map(map_slot_name.clone(), map)], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -1502,7 +1502,7 @@ async fn undo_after_update_account_state_does_not_resurrect_removed_entries() -> initial_map.insert(key_c, [Felt::from(300u32), ZERO, ZERO, ZERO].into())?; let component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_map(map_slot_name.clone(), initial_map)], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; @@ -1510,7 +1510,7 @@ async fn undo_after_update_account_state_does_not_resurrect_removed_entries() -> // Build an existing account at nonce 1: no initial assets let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -1996,14 +1996,14 @@ async fn undo_after_update_removes_genuinely_new_entries() -> anyhow::Result<()> initial_map.insert(key_b, [Felt::from(200u32), ZERO, ZERO, ZERO].into())?; let component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![StorageSlot::with_map(map_slot_name.clone(), initial_map)], AccountComponentMetadata::new("miden::testing::dummy_component"), )?; let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -2168,7 +2168,7 @@ async fn insert_account_with_storage_for_snapshot_test() StorageSlotName::new("miden::testing::sqlite_store::map").expect("valid slot name"); let dummy_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![ StorageSlot::with_empty_value(value_slot_name.clone()), StorageSlot::with_empty_map(map_slot_name.clone()), @@ -2178,7 +2178,7 @@ async fn insert_account_with_storage_for_snapshot_test() let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) @@ -2294,12 +2294,12 @@ async fn watched_status_survives_state_replacement() -> anyhow::Result<()> { let account = AccountBuilder::new([0; 32]) .account_type(AccountType::Private) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, ))) .with_component(AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], AccountComponentMetadata::new("miden::testing::watched_replace"), )?) diff --git a/crates/testing/miden-client-tests/src/tests.rs b/crates/testing/miden-client-tests/src/tests.rs index ce35507a89..26d389f1a3 100644 --- a/crates/testing/miden-client-tests/src/tests.rs +++ b/crates/testing/miden-client-tests/src/tests.rs @@ -126,12 +126,13 @@ use miden_standards::note::{ use miden_standards::testing::mock_account::MockAccountExt; use miden_standards::testing::note::NoteBuilder; use miden_standards::tx_script::SendNotesTransactionScriptError; -use miden_testing::{MockChain, MockChainBuilder, TxContextInput}; +use miden_testing::{MockChain, MockChainBuilder, MockTransactionInput}; use rand::rngs::StdRng; use rand::{Rng, RngExt, SeedableRng}; use rstest::rstest; mod batch; +mod fees; pub mod store; mod transaction; mod transport; @@ -325,10 +326,10 @@ async fn insert_same_account_twice_fails() { let account = Account::mock( ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); assert!(client.add_account(&account, false).await.is_ok()); @@ -342,10 +343,10 @@ async fn account_code() { let account = Account::mock( ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); let account_code = account.code(); @@ -367,10 +368,10 @@ async fn get_account_by_id() { let account = Account::mock( ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); client.add_account(&account, false).await.unwrap(); @@ -1107,7 +1108,7 @@ async fn note_without_asset() { error, ClientError::TransactionRequestError( TransactionRequestError::SendNotesTransactionScriptError( - SendNotesTransactionScriptError::FaucetNoteWithoutAsset + SendNotesTransactionScriptError::FaucetNoteUnexpectedNumAssets ) ) )); @@ -1400,12 +1401,8 @@ async fn input_note_reader_finds_externally_consumed_notes() { // Consumer consumes the note directly on the chain (bypassing any client). let tx = Box::pin( chain - .build_tx_context( - miden_testing::TxContextInput::Account(consumer.clone()), - &[], - core::slice::from_ref(&p2id_note), - ) - .unwrap() + .build_transaction(miden_testing::MockTransactionInput::Account(consumer.clone())) + .unauthenticated_input_note(p2id_note.clone()) .build() .unwrap() .execute(), @@ -1511,12 +1508,8 @@ async fn import_by_id_already_consumed_note_is_findable_by_id() { // Consumer consumes the note directly on the chain (bypassing any client). let tx = Box::pin( chain - .build_tx_context( - miden_testing::TxContextInput::Account(consumer.clone()), - &[], - core::slice::from_ref(&p2id_note), - ) - .unwrap() + .build_transaction(miden_testing::MockTransactionInput::Account(consumer.clone())) + .unauthenticated_input_note(p2id_note.clone()) .build() .unwrap() .execute(), @@ -1597,9 +1590,9 @@ async fn setup_prunable_block_scenario( // Block 1: create the first unspent note (keeps block 1 permanently relevant). let tx = Box::pin( chain - .build_tx_context(TxContextInput::AccountId(mock_account.id()), &[], &[spawn_note_1]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(note_first)]) + .build_transaction(MockTransactionInput::AccountId(mock_account.id())) + .unauthenticated_input_note(spawn_note_1) + .expected_output_notes(vec![RawOutputNote::Full(note_first)]) .build() .unwrap() .execute(), @@ -1617,9 +1610,9 @@ async fn setup_prunable_block_scenario( // irrelevant. let tx = Box::pin( chain - .build_tx_context(TxContextInput::AccountId(mock_account.id()), &[], &[spawn_note_2]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(note_second.clone())]) + .build_transaction(MockTransactionInput::AccountId(mock_account.id())) + .unauthenticated_input_note(spawn_note_2) + .expected_output_notes(vec![RawOutputNote::Full(note_second.clone())]) .build() .unwrap() .execute(), @@ -1665,8 +1658,8 @@ async fn consume_note_and_prove(mock_rpc: &MockRpcApi, account_id: AccountId, no let tx_context = mock_rpc .mock_chain .write() - .build_tx_context(TxContextInput::AccountId(account_id), &[], &[note]) - .unwrap() + .build_transaction(MockTransactionInput::AccountId(account_id)) + .unauthenticated_input_note(note) .build() .unwrap(); Box::pin(tx_context.execute()).await.unwrap() @@ -3984,7 +3977,7 @@ async fn empty_storage_map() { let account = AccountBuilder::new(init_seed) .account_type(AccountType::Public) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) @@ -4101,7 +4094,7 @@ async fn storage_and_vault_proofs() { let account = AccountBuilder::new(init_seed) .account_type(AccountType::Public) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) @@ -4196,10 +4189,10 @@ async fn account_addresses_basic_wallet() { let account = Account::mock( ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); client.add_account(&account, false).await.unwrap(); @@ -4239,10 +4232,10 @@ async fn account_add_address_after_creation() { let account = Account::mock( ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); client.add_account(&account, false).await.unwrap(); @@ -4577,9 +4570,9 @@ async fn sync_stores_private_note_attachments() { // 3. Commit the private note at block 1, then advance a few blocks. let tx = Box::pin( mock_chain - .build_tx_context(TxContextInput::AccountId(sender.id()), &[], &[spawn_note]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) + .build_transaction(MockTransactionInput::AccountId(sender.id())) + .unauthenticated_input_note(spawn_note) + .expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) .build() .unwrap() .execute(), @@ -4724,8 +4717,7 @@ async fn sync_large_public_account() { // This changes the on-chain commitment so sync detects a mismatch. let tx = Box::pin( mock_chain - .build_tx_context(TxContextInput::AccountId(mock_account.id()), &[], &[]) - .unwrap() + .build_transaction(MockTransactionInput::AccountId(mock_account.id())) .build() .unwrap() .execute(), @@ -4932,9 +4924,9 @@ pub async fn create_prebuilt_mock_chain() -> MockChain { // Block 1: Create first note let tx = Box::pin( mock_chain - .build_tx_context(TxContextInput::AccountId(mock_account.id()), &[], &[spawn_note_1]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(note_first)]) + .build_transaction(MockTransactionInput::AccountId(mock_account.id())) + .unauthenticated_input_note(spawn_note_1) + .expected_output_notes(vec![RawOutputNote::Full(note_first)]) .build() .unwrap() .execute(), @@ -4954,9 +4946,9 @@ pub async fn create_prebuilt_mock_chain() -> MockChain { let tx = Box::pin( mock_chain - .build_tx_context(mock_account.id(), &[], &[spawn_note_2]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(note_second.clone())]) + .build_transaction(mock_account.id()) + .unauthenticated_input_note(spawn_note_2) + .expected_output_notes(vec![RawOutputNote::Full(note_second.clone())]) .build() .unwrap() .execute(), @@ -4969,8 +4961,8 @@ pub async fn create_prebuilt_mock_chain() -> MockChain { let transaction = Box::pin( mock_chain - .build_tx_context(mock_account.id(), &[], &[note_second]) - .unwrap() + .build_transaction(mock_account.id()) + .unauthenticated_input_note(note_second) .build() .unwrap() .execute(), @@ -4998,7 +4990,7 @@ async fn insert_new_wallet( let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) @@ -5026,7 +5018,7 @@ async fn insert_new_ecdsa_wallet( let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::EcdsaK256Keccak, ))) @@ -5072,7 +5064,7 @@ async fn insert_new_fungible_faucet( let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) @@ -5121,7 +5113,7 @@ async fn insert_new_ecdsa_fungible_faucet( let account = AccountBuilder::new(init_seed) .account_type(visibility) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::EcdsaK256Keccak, ))) @@ -5193,7 +5185,7 @@ async fn storage_and_vault_proofs_ecdsa() { let account = AccountBuilder::new(init_seed) .account_type(AccountType::Public) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::EcdsaK256Keccak, ))) @@ -5313,7 +5305,7 @@ async fn execute_transaction_fails_for_watched_account() { .build(); let faucet = AccountBuilder::new(init_seed) .account_type(AccountType::Public) - .with_auth_component(auth_component) + .with_component(auth_component) .with_component(token) .with_components(policy_manager) .build_with_schema_commitment() diff --git a/crates/testing/miden-client-tests/src/tests/batch.rs b/crates/testing/miden-client-tests/src/tests/batch.rs index fc765322ba..6f817f2309 100644 --- a/crates/testing/miden-client-tests/src/tests/batch.rs +++ b/crates/testing/miden-client-tests/src/tests/batch.rs @@ -28,7 +28,7 @@ use miden_client::transaction::{ use miden_client_sqlite_store::ClientBuilderSqliteExt; use miden_protocol::Felt; use miden_protocol::crypto::rand::RandomCoin; -use miden_testing::{Auth, MockChainBuilder, TxContextInput}; +use miden_testing::{Auth, MockChainBuilder, MockTransactionInput}; use crate::tests::{create_test_client, seed_mock_transaction_encryption_key}; @@ -56,8 +56,7 @@ async fn submit_proven_batch_returns_chain_tip() { let tx_context = rpc_api .mock_chain .read() - .build_tx_context(TxContextInput::AccountId(account_id), &[], &[]) - .unwrap() + .build_transaction(MockTransactionInput::AccountId(account_id)) .build() .unwrap(); let executed_tx = Box::pin(tx_context.execute()).await.unwrap(); @@ -185,8 +184,7 @@ async fn apply_transaction_batch_rolls_back_on_mid_batch_failure() { let tx_ctx_a = rpc_api .mock_chain .read() - .build_tx_context(TxContextInput::AccountId(a_id), &[], &[]) - .unwrap() + .build_transaction(MockTransactionInput::AccountId(a_id)) .build() .unwrap(); let executed_a = Box::pin(tx_ctx_a.execute()).await.unwrap(); @@ -194,8 +192,7 @@ async fn apply_transaction_batch_rolls_back_on_mid_batch_failure() { let tx_ctx_b = rpc_api .mock_chain .read() - .build_tx_context(TxContextInput::AccountId(b_id), &[], &[]) - .unwrap() + .build_transaction(MockTransactionInput::AccountId(b_id)) .build() .unwrap(); let executed_b = Box::pin(tx_ctx_b.execute()).await.unwrap(); diff --git a/crates/testing/miden-client-tests/src/tests/fees.rs b/crates/testing/miden-client-tests/src/tests/fees.rs new file mode 100644 index 0000000000..c61ba39908 --- /dev/null +++ b/crates/testing/miden-client-tests/src/tests/fees.rs @@ -0,0 +1,178 @@ +//! Tests for transaction fee payment. +//! +//! Fees are charged inside the authentication procedure, so a signature-authenticated account only +//! transacts on a fee-charging chain when the request commits fee conversion info. These tests run +//! against a `MockChain` with a non-zero `verification_base_fee`, which is the only switch that +//! turns fee collection on. + +use miden_client::account::component::{FeeConversionInfo, commit_fee_conversion_info}; +use miden_client::account::{Account, AccountId}; +use miden_client::asset::{Asset, FungibleAsset}; +use miden_client::auth::AuthSchemeId; +use miden_client::transaction::{TransactionExecutorError, TransactionRequestBuilder}; +use miden_protocol::Word; +use miden_protocol::testing::account_id::ACCOUNT_ID_FEE_FAUCET; +use miden_testing::{Auth, MockChain, MockChainBuilder}; + +/// Base fee used by the protocol's own fee-payment tests. Large enough that the computed fee is +/// non-zero, which is what forces the conversion info to be present. +const VERIFICATION_BASE_FEE: u32 = 500; + +/// Balance of the fee asset given to the paying account. `pay_fee` withdraws from the vault, so an +/// account that does not hold the fee asset cannot transact at all. +const FEE_ASSET_BALANCE: u64 = 1_000_000; + +/// Builds a fee-charging chain holding one singlesig wallet funded with `balance` of the fee asset. +fn fee_charging_chain(balance: u64) -> (MockChain, Account, AccountId) { + let fee_faucet_id: AccountId = ACCOUNT_ID_FEE_FAUCET.try_into().unwrap(); + let fee_asset: Asset = FungibleAsset::new(fee_faucet_id, balance).unwrap().into(); + + let mut builder = MockChainBuilder::new().verification_base_fee(VERIFICATION_BASE_FEE); + let account = builder + .add_existing_wallet_with_assets( + Auth::BasicAuth { + auth_scheme: AuthSchemeId::Falcon512Poseidon2, + }, + [fee_asset], + ) + .unwrap(); + let chain = builder.build().unwrap(); + + (chain, account, fee_faucet_id) +} + +/// `TransactionRequestBuilder::fee_conversion_info` produces an auth arg and advice map entry the +/// auth procedure accepts, and the resulting transaction emits the fee note. +#[tokio::test] +async fn fee_conversion_info_pays_the_transaction_fee() { + let (chain, account, fee_faucet_id) = fee_charging_chain(FEE_ASSET_BALANCE); + let salt = Word::from([1u32, 2, 3, 4]); + let conversion_info = FeeConversionInfo::one_to_one(fee_faucet_id); + + let request = TransactionRequestBuilder::new() + .fee_conversion_info(conversion_info, salt) + .build() + .unwrap(); + + // The builder commits the conversion info rather than storing it verbatim, so the auth arg is + // the commitment and the advice map holds its preimage. + let (expected_auth_arg, preimage) = commit_fee_conversion_info(conversion_info, salt); + assert_eq!( + *request.auth_arg(), + Some(expected_auth_arg), + "the request should carry the conversion info commitment as its auth arg" + ); + + let executed = Box::pin( + chain + .build_transaction(account.id()) + .auth_args(expected_auth_arg) + .add_advice_map_entry(expected_auth_arg, preimage) + .build() + .unwrap() + .execute(), + ) + .await + .unwrap(); + + // Paying a non-zero fee creates exactly one output note, the fee note, funded from the vault. + assert_eq!( + executed.output_notes().num_notes(), + 1, + "a fee-paying transaction should emit the fee note" + ); +} + +/// Without committed conversion info the auth procedure aborts, so a request that omits it cannot +/// be executed on a fee-charging chain. This is why `fee_conversion_info` is mandatory rather than +/// optional once a chain charges anything. +#[tokio::test] +async fn transaction_without_fee_conversion_info_is_rejected() { + let (chain, account, _) = fee_charging_chain(FEE_ASSET_BALANCE); + + let result = Box::pin(chain.build_transaction(account.id()).build().unwrap().execute()).await; + + let Err(err) = result else { + panic!("a fee-charging chain should reject an empty auth arg"); + }; + assert!( + format!("{err:?}").contains("conversion info"), + "expected a missing-conversion-info abort, got: {err:?}" + ); +} + +/// An account holding none of the fee asset can still pay, provided the transaction consumes a note +/// carrying it: note scripts run before the authentication procedure, so the credit lands in the +/// vault before `pay_fee` withdraws from it. +/// +/// This is what makes a fee-charging chain usable without pre-funding vaults at genesis: a fresh +/// account's first transaction can consume a mint note and settle its own fee from the proceeds. +#[tokio::test] +async fn fee_can_be_paid_from_a_note_consumed_in_the_same_transaction() { + let mut builder = MockChainBuilder::new().verification_base_fee(VERIFICATION_BASE_FEE); + // Deliberately no assets: the account starts unable to pay anything. + let account = builder + .add_existing_wallet(Auth::BasicAuth { + auth_scheme: AuthSchemeId::Falcon512Poseidon2, + }) + .unwrap(); + let funding_note = builder.add_p2id_note_with_fee(account.id(), FEE_ASSET_BALANCE).unwrap(); + let chain = builder.build().unwrap(); + + let salt = Word::from([9u32, 10, 11, 12]); + let (auth_arg, preimage) = + commit_fee_conversion_info(FeeConversionInfo::one_to_one(chain.fee_faucet_id()), salt); + + let executed = Box::pin( + chain + .build_transaction(account.id()) + .authenticated_input_notes([funding_note.id()]) + .auth_args(auth_arg) + .add_advice_map_entry(auth_arg, preimage) + .build() + .unwrap() + .execute(), + ) + .await + .unwrap(); + + // One output note, the fee note, paid out of the funds the consumed note just delivered. + assert_eq!( + executed.output_notes().num_notes(), + 1, + "the fee should be paid from the assets the consumed note delivered" + ); +} + +/// An account that does not hold the fee asset cannot pay, even with correctly committed +/// conversion info: `pay_fee` withdraws the fee from the account vault. +#[tokio::test] +async fn fee_payment_fails_without_fee_asset_balance() { + let (chain, account, fee_faucet_id) = fee_charging_chain(0); + let salt = Word::from([5u32, 6, 7, 8]); + let (auth_arg, preimage) = + commit_fee_conversion_info(FeeConversionInfo::one_to_one(fee_faucet_id), salt); + + let result = Box::pin( + chain + .build_transaction(account.id()) + .auth_args(auth_arg) + .add_advice_map_entry(auth_arg, preimage) + .build() + .unwrap() + .execute(), + ) + .await; + + // The withdrawal aborts inside the vault, so the failure surfaces as a kernel assertion rather + // than as a client-side balance check. + let TransactionExecutorError::TransactionProgramExecutionFailed(err) = result.unwrap_err() + else { + panic!("expected the fee withdrawal to fail while executing the transaction program"); + }; + assert!( + format!("{err}") + .contains("amount of the asset in the vault is less than the amount to remove"), + "expected the vault withdrawal to abort, got: {err:?}" + ); +} diff --git a/crates/testing/miden-client-tests/src/tests/store.rs b/crates/testing/miden-client-tests/src/tests/store.rs index c720f7970c..86f88c6483 100644 --- a/crates/testing/miden-client-tests/src/tests/store.rs +++ b/crates/testing/miden-client-tests/src/tests/store.rs @@ -37,10 +37,10 @@ use crate::tests::{create_test_client, insert_new_fungible_faucet, insert_new_wa fn create_account_data(account_id: u128) -> AccountFile { let account = Account::mock( account_id, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); AccountFile::new(account.clone(), vec![AuthSecretKey::new_falcon512_poseidon2()]) @@ -49,10 +49,10 @@ fn create_account_data(account_id: u128) -> AccountFile { fn create_ecdsa_account_data(account_id: u128) -> AccountFile { let account = Account::mock( account_id, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::EcdsaK256Keccak, - )), + ))], ); AccountFile::new(account.clone(), vec![AuthSecretKey::new_falcon512_poseidon2()]) @@ -87,10 +87,10 @@ pub async fn try_add_account() { let account = Account::mock( ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::Falcon512Poseidon2, - )), + ))], ); // The mock account has nonce 1, we need it to be 0 for the test. @@ -112,10 +112,10 @@ pub async fn try_add_ecdsa_account() { let account = Account::mock( ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, - AuthSingleSig::new(Approver::new( + [AuthSingleSig::new(Approver::new( PublicKeyCommitment::from(EMPTY_WORD), AuthSchemeId::EcdsaK256Keccak, - )), + ))], ); // The mock account has nonce 1, we need it to be 0 for the test. @@ -329,7 +329,7 @@ async fn build_three_slot_account( let account = AccountBuilder::new(init_seed) .account_type(AccountType::Public) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) diff --git a/crates/testing/miden-client-tests/src/tests/transaction.rs b/crates/testing/miden-client-tests/src/tests/transaction.rs index dd3f524ca9..b4b1c0b65e 100644 --- a/crates/testing/miden-client-tests/src/tests/transaction.rs +++ b/crates/testing/miden-client-tests/src/tests/transaction.rs @@ -119,7 +119,7 @@ async fn transaction_creates_two_notes() { let account = AccountBuilder::new(Default::default()) .with_component(BasicWallet) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( pub_key.to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) @@ -388,7 +388,7 @@ async fn lazy_foreign_account_loading() { let foreign_account = AccountBuilder::new(Default::default()) .account_type(AccountType::Public) .with_component(fpi_component) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( secret_key.public_key().to_commitment(), AuthSchemeId::Falcon512Poseidon2, ))) diff --git a/crates/testing/miden-client-tests/src/tests/transport.rs b/crates/testing/miden-client-tests/src/tests/transport.rs index d1a784be39..56b54d9e6a 100644 --- a/crates/testing/miden-client-tests/src/tests/transport.rs +++ b/crates/testing/miden-client-tests/src/tests/transport.rs @@ -39,7 +39,7 @@ use miden_protocol::transaction::RawOutputNote; use miden_protocol::utils::serde::Serializable; use miden_standards::note::P2idNote; use miden_standards::testing::note::NoteBuilder; -use miden_testing::{Auth, MockChainBuilder, TxContextInput}; +use miden_testing::{Auth, MockChainBuilder, MockTransactionInput}; use rand::RngExt; use crate::tests::{ @@ -122,9 +122,9 @@ async fn transport_recovers_attachments() { let mut mock_chain = mock_chain_builder.build().unwrap(); let tx = Box::pin( mock_chain - .build_tx_context(TxContextInput::AccountId(sender.id()), &[], &[spawn_note]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) + .build_transaction(MockTransactionInput::AccountId(sender.id())) + .unauthenticated_input_note(spawn_note) + .expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) .build() .unwrap() .execute(), @@ -514,9 +514,9 @@ async fn fetch_private_notes_finds_note_committed_at_sync_height() { // Block 1: commit the private note. let tx = Box::pin( mock_chain - .build_tx_context(TxContextInput::AccountId(mock_account.id()), &[], &[spawn_note]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) + .build_transaction(MockTransactionInput::AccountId(mock_account.id())) + .unauthenticated_input_note(spawn_note) + .expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) .build() .unwrap() .execute(), @@ -973,9 +973,9 @@ async fn committed_private_note_recipient( // Block 1: commit the private note. let tx = Box::pin( mock_chain - .build_tx_context(TxContextInput::AccountId(mock_account.id()), &[], &[spawn_note]) - .unwrap() - .extend_expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) + .build_transaction(MockTransactionInput::AccountId(mock_account.id())) + .unauthenticated_input_note(spawn_note) + .expected_output_notes(vec![RawOutputNote::Full(private_note.clone())]) .build() .unwrap() .execute(), diff --git a/crates/testing/test-node-genesis/src/agglayer.rs b/crates/testing/test-node-genesis/src/agglayer.rs index d00590a044..efc0aea7fc 100644 --- a/crates/testing/test-node-genesis/src/agglayer.rs +++ b/crates/testing/test-node-genesis/src/agglayer.rs @@ -1,9 +1,11 @@ //! Builds the agglayer genesis accounts (bridge admin, GER manager, bridge, faucet) included in //! the genesis configuration when agglayer support is requested. +use std::collections::BTreeSet; + use ::rand::{RngExt, random}; use anyhow::{Context, Result}; -use miden_agglayer::{create_agglayer_faucet, create_bridge_account}; +use miden_agglayer::{BridgeRoles, create_agglayer_faucet, create_bridge_account}; use miden_protocol::account::auth::{AuthScheme, AuthSecretKey}; use miden_protocol::account::{ Account, @@ -19,6 +21,13 @@ use miden_standards::account::wallets::BasicWallet; use rand_chacha::ChaCha20Rng; use rand_chacha::rand_core::SeedableRng; +/// The `AggLayer` network ID assigned to the Miden chain. +/// +/// Bridge-in asserts that a claim leaf's `destination_network` equals the value the bridge account +/// was built with, so this must match the `MIDEN_NETWORK_ID` used to generate the Solidity test +/// vectors in `bin/integration-tests/foundry-vectors`. +pub const MIDEN_NETWORK_ID: u32 = 77; + /// File names for agglayer genesis account exports. pub const BRIDGE_ADMIN_ACCOUNT_FILE: &str = "bridge_admin.mac"; pub const GER_MANAGER_ACCOUNT_FILE: &str = "ger_manager.mac"; @@ -61,8 +70,13 @@ pub fn create_agglayer_genesis_accounts() -> Result { // 3. Create and deploy the Bridge account (unconfigured; configured at test time). let bridge_seed: Word = rng.random::<[u32; 4]>().map(Felt::from).into(); - let bridge = - create_bridge_account(bridge_seed, admin_account.id(), ger_account.id(), ger_account.id()); + let roles = BridgeRoles::new( + BTreeSet::from([admin_account.id()]), + BTreeSet::from([ger_account.id()]), + BTreeSet::from([ger_account.id()]), + ) + .context("failed to build bridge roles")?; + let bridge = create_bridge_account(bridge_seed, admin_account.id(), roles, MIDEN_NETWORK_ID); let bridge = set_nonce_to_one(bridge); // 4. Create and deploy the Faucet. In protocol 0.15 the faucet no longer stores conversion @@ -95,14 +109,14 @@ fn build_wallet_account(rng: &mut ChaCha20Rng, secret: &AuthSecretKey) -> Result let seed: [u8; 32] = rng.random(); let acc_component = AccountComponent::new( - BasicWallet::code().as_library().clone(), + BasicWallet::code().as_package().clone(), vec![], AccountComponentMetadata::new("miden::testing::basic_wallet"), ) .context("failed to create wallet component")?; let account = AccountBuilder::new(seed) - .with_auth_component(AuthSingleSig::new(Approver::new( + .with_component(AuthSingleSig::new(Approver::new( secret.public_key().to_commitment(), AuthScheme::Falcon512Poseidon2, ))) diff --git a/crates/testing/test-node-genesis/src/lib.rs b/crates/testing/test-node-genesis/src/lib.rs index 5d72290287..862e39ee13 100644 --- a/crates/testing/test-node-genesis/src/lib.rs +++ b/crates/testing/test-node-genesis/src/lib.rs @@ -31,7 +31,6 @@ use miden_standards::account::faucets::{ }; use miden_standards::account::policies::{BurnPolicy, MintPolicy, TokenPolicyManager}; use miden_standards::account::wallets::BasicWallet; -use miden_standards::testing::faucet::user_faucet_single_sig_acl; use rand_chacha::ChaCha20Rng; use rand_chacha::rand_core::SeedableRng; @@ -138,10 +137,10 @@ fn generate_genesis_account() -> anyhow::Result { let mut rng = ChaCha20Rng::from_seed(random()); let secret = AuthSecretKey::new_falcon512_poseidon2_with_rng(&mut rng); - let auth_component = user_faucet_single_sig_acl( + let auth_component = AuthSingleSig::new(Approver::new( secret.public_key().to_commitment(), AuthScheme::Falcon512Poseidon2, - ); + )); let symbol = TokenSymbol::try_from("TST").expect("TST should be a valid token symbol"); let name = TokenName::new(&symbol.to_string()).expect("token symbol is a valid token name"); @@ -230,10 +229,10 @@ fn create_single_test_faucet(index: u128, secret: &AuthSecretKey) -> anyhow::Res .try_into() .expect("concatenating two 16-byte arrays yields exactly 32 bytes"); - let auth_component = user_faucet_single_sig_acl( + let auth_component = AuthSingleSig::new(Approver::new( secret.public_key().to_commitment(), AuthScheme::Falcon512Poseidon2, - ); + )); let symbol = TokenSymbol::new("TKN")?; let name = TokenName::new(&symbol.to_string()).expect("token symbol is a valid token name"); @@ -265,7 +264,7 @@ fn create_test_account_with_many_assets(faucets: &[Account]) -> anyhow::Result anyhow::Result