diff --git a/CHANGELOG.md b/CHANGELOG.md index 873f63208b..b10f0b4009 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ * [BREAKING][type][rust] Added the `TransactionRequestError::SwapNoteWithZeroAsset` variant, so exhaustive matches on `TransactionRequestError` must handle it ([#2459](https://github.com/0xMiden/rust-sdk/pull/2459)). * [BREAKING][removal][test] Loose helper functions in `miden_client::testing::common` are now methods on `TestClient`. `TestClient::keystore()` exposes the client's keystore, so `ClientConfig::into_client` and `into_unsynced_client` return just the `TestClient` instead of a client/keystore pair ([#2481](https://github.com/0xMiden/rust-sdk/pull/2481)). +* [BREAKING][rust,rpc,store] Updated protocol dependencies to `0.17.0-rc.3`, VM dependencies to `0.32`, and `miden-debug` to `0.15`. Updated node protobuf bindings to [#2570](https://github.com/0xMiden/node/pull/2570). Requires a compatible node and a new client database. +* [BREAKING][rust] Added protocol configuration registration through `ClientBuilder::protocol_config` and `Client::add_protocol_config`. Execution and note screening require the configuration committed by the reference block. The node does not yet provide it over RPC. The CLI, benchmarks, and integration tests accept a serialized configuration through `MIDEN_PROTOCOL_CONFIG`; the CLI also accepts `fee_faucet_id` in its configuration to select the current protocol configuration. +* [BREAKING][rust] Renamed the `ClientError::TransactionScriptError` and `StoreError::TransactionScriptError` variants to `MastForestScriptError`, matching the upstream type that now backs both note scripts and transaction scripts. +* [BREAKING][rust] `AccountReader::get_balance` now returns an error instead of `AssetAmount::ZERO` when the stored asset cannot be read as a fungible asset. A missing asset still reports a zero balance. +* [BREAKING][type][rust] `NodeRpcClient::get_block_by_number` returns a `SignedBlock` instead of a `ProvenBlock`. The response carries the block and its proof in separate fields, and the block field holds a signed block. +* [BREAKING][rust] Replaced the `ValidatorKeys` re-export with `ValidatorConfig` and `ProvingOptions` with `Prover`. Removed the upstream `FungibleAssetDelta`, `NonFungibleAssetDelta`, `NonFungibleDeltaAction`, and `SmtForest` re-exports. `TransactionRequest::incoming_assets` now returns `Vec` for assets without fungible amounts. ### Fixes diff --git a/Cargo.lock b/Cargo.lock index 4309716253..405bce0570 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2149,15 +2149,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.15.0" @@ -2458,21 +2449,22 @@ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "miden-ace-codegen" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ff2a44c7f7dc497ac56c74dca5b3465b4b46be066fa88c2c58a8eb1bcb2dc8" +checksum = "1205d711fa2237f0c12bd00ff639b5b00f830704ad19eed337465a2341d72193" dependencies = [ "miden-constraint-compiler", "miden-core", "miden-crypto", + "miden-field", "thiserror", ] [[package]] name = "miden-agglayer" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9340d981c2aaefded2a28ca66f10169dd4170c912538d33fe8690ea549e468e" +checksum = "e579ddb489e95caa827d1877f048ce53e5097459bc1c091ccec20f711c31fd3f" dependencies = [ "alloy-sol-types", "fs-err", @@ -2493,15 +2485,16 @@ dependencies = [ [[package]] name = "miden-air" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b6d3f3336c8a2da5cd0924c42dd1f339e6c3d5adf3221bc1c005b444fd0bf0" +checksum = "b07865434d24d0217bab657d2a4e65fe472a894868b8f8edce31379f1ca229b2" dependencies = [ "miden-ace-codegen", "miden-core", "miden-crypto", "miden-utils-indexing", "p3-field", + "p3-security", "proptest", "thiserror", "tracing", @@ -2509,9 +2502,9 @@ dependencies = [ [[package]] name = "miden-assembly" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644b31bdda941328f9ff2088382b7de41569c1cc83d6090f63e43d261e9cd262" +checksum = "42e7f7a3e02a31f1c5690b60c529eed11de3a897af84754c0a4b99a3152ca463" dependencies = [ "env_logger", "log", @@ -2527,9 +2520,9 @@ dependencies = [ [[package]] name = "miden-assembly-syntax" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad0d5174833b17b498d541d1ef62d73929a143ea56ea5eba719339c15cd0968" +checksum = "37b3f2354462165f247c58c7c5216ba4f3938f673e9e0d6063ff0c4920137188" dependencies = [ "env_logger", "log", @@ -2550,29 +2543,30 @@ dependencies = [ [[package]] name = "miden-assembly-syntax-cst" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff301e56d9201821a4458564ed19ae9b95c7a219662a422e47bb61d17e0fa7b1" +checksum = "513403ea4accd4255c14c1ac8026a18c25c9eab17fb49a44693b44c81f4bd64f" dependencies = [ "miden-debug-types", "miden-rowan", "miden-utils-diagnostics", - "thiserror", ] [[package]] name = "miden-block-prover" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e34859c5f2005e95cfc5ba97ae0dffec15bb44460fc23262532e5e2aee49155" +checksum = "c912411805cedecfb066bf2c67c68a41106b2a08816ffdd3bb432a2ac0d4ea20" dependencies = [ + "miden-processor", "miden-protocol", + "miden-prover", "thiserror", ] [[package]] name = "miden-client" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -2613,7 +2607,7 @@ dependencies = [ [[package]] name = "miden-client-bench" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "assert_cmd", @@ -2630,7 +2624,7 @@ dependencies = [ [[package]] name = "miden-client-cli" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "assert_cmd", @@ -2659,7 +2653,7 @@ dependencies = [ [[package]] name = "miden-client-integration-tests" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "assert_matches", @@ -2683,7 +2677,7 @@ dependencies = [ [[package]] name = "miden-client-sqlite-store" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -2702,7 +2696,7 @@ dependencies = [ [[package]] name = "miden-client-unit-tests" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "miden-client", @@ -2719,9 +2713,9 @@ dependencies = [ [[package]] name = "miden-constraint-compiler" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ef51ec02f0899c5fc6aa4af11eb050094d98e5e6bf8767a4da555d210f2de6" +checksum = "1760d033707d03cf00965e99fdfadf9a905f83b7c4bc1604f331cf580af2e863" dependencies = [ "miden-core", "miden-crypto", @@ -2729,28 +2723,28 @@ dependencies = [ [[package]] name = "miden-core" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b27f9f91988c5e74b50b543c4e6d37ec729eabcf70db63cf752dedd780f8a90" +checksum = "2e21b43b9d95efd36333bcc4dbf978a54d923b2904ed922480e336cf990a2737" dependencies = [ "derive_more", "log", "miden-crypto", "miden-debug-types", "miden-formatting", + "miden-serde-utils", "miden-utils-core-derive", "miden-utils-indexing", "miden-utils-sync", "proptest", - "serde", "thiserror", ] [[package]] name = "miden-core-lib" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14df9652fc4963f20d11df9ceb576ccb7831b5dc72fabec5c1b602f51e57909c" +checksum = "4bf796fb15f11e9770273b6d87d498692e643e1fce817ea63e6eca42e3de4d48" dependencies = [ "env_logger", "fs-err", @@ -2769,19 +2763,20 @@ dependencies = [ [[package]] name = "miden-core-lib-codegen" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad0b8badcf1636150cac0d74aabadd395ba7d570227eb0923ff14f02a278fff" +checksum = "25fd10c163d02a2b7f945554075a1fda7558925f613812a45a5c00bf5449caea" dependencies = [ "miden-core", "miden-precompiles", + "tempfile", ] [[package]] name = "miden-crypto" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c917b0342d911ae4b7a549bb3ca791c093dac4770f88b02e23b43f3fa8179f5" +checksum = "ba74f29ee9756631ed85794c0a15f5099a29758436526f57b607e1a1cadf293f" dependencies = [ "blake3", "cc", @@ -2821,9 +2816,9 @@ dependencies = [ [[package]] name = "miden-crypto-derive" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c3165dfd7fd6f587ea5731efd1cc8083ca55c23d2d9b3000f83a3948486044" +checksum = "e7578de2aff9443eab6852c12b7a0fbf12e937a0a27e92c33605a3df1abd8da2" dependencies = [ "quote", "syn 2.0.119", @@ -2831,14 +2826,14 @@ dependencies = [ [[package]] name = "miden-debug" -version = "0.10.3" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2afcb84bfe3450e610a07533a98d4bd2d527668878129a5cdcc5454fbc41b263" +checksum = "6cd28945aa9a631365bbba867834d1867bdf33b9866afc3a5d6b4064a4a34a06" dependencies = [ "clap", "compact_str", "env_logger", - "futures", + "futures-executor", "log", "miden-assembly", "miden-assembly-syntax", @@ -2849,17 +2844,14 @@ dependencies = [ "miden-package-registry", "miden-processor", "miden-project", - "pyo3-build-config", "thiserror", - "tokio", - "tokio-util", ] [[package]] name = "miden-debug-dap" -version = "0.9.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d974ad4982cd62cb8357977a19c6ecc0a1c1daaccb068d45262cc3783985afa5" +checksum = "04260fe075edb18357cd25cd1f064c02668c37fa2d533f75fb1642f47d4dfd12" dependencies = [ "serde", "serde_json", @@ -2868,15 +2860,14 @@ dependencies = [ [[package]] name = "miden-debug-engine" -version = "0.12.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1abbddd96a289747ebba7d9d8737781f45cffe7454a33fbf3c7ca5fe348c7cbd" +checksum = "49c579d755403a9ec1c039f6c6ed7903f8475ba6c9a5d0200ae280b18c45fcc5" dependencies = [ "clap", - "glob", + "hashbrown 0.17.1", "inventory", "log", - "miden-assembly", "miden-assembly-syntax", "miden-core", "miden-debug-dap", @@ -2884,8 +2875,10 @@ dependencies = [ "miden-mast-package", "miden-package-registry", "miden-processor", - "miden-project", + "miden-utils-sync", "num-traits", + "regex", + "regex-syntax", "rustc-demangle", "rustc-hash", "serde", @@ -2898,9 +2891,9 @@ dependencies = [ [[package]] name = "miden-debug-types" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9f3f8e4a8f54a36fbf00330ac8bd1947627c1786cd49b94a08b741590ed173" +checksum = "3817a333b7985dc0080bb3cff469e40cddf45b9f97cd92c1cf3c5d3cc01a6b5b" dependencies = [ "memchr", "miden-crypto", @@ -2918,9 +2911,9 @@ dependencies = [ [[package]] name = "miden-field" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cf9de55b88ec86ad272ff4224d76b3e0cbda49e242e78776b0037ba9b0e857" +checksum = "b98bd4d24d3ab2cda622cf530fc32c1e93b4f552eea2763935013eab2e0c1ded" dependencies = [ "miden-serde-utils", "num-bigint 0.5.1", @@ -2946,9 +2939,9 @@ dependencies = [ [[package]] name = "miden-lifted-air" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67e06d47e246db853a9f3e52ec87fa33a8ffc0fe5be0dd99288b2439312f206" +checksum = "2d02a60f2a8e334e143afab7a3368467ff320d6c49c85383d8299751d33d68db" dependencies = [ "p3-air", "p3-challenger", @@ -2960,9 +2953,9 @@ dependencies = [ [[package]] name = "miden-lifted-stark" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ee320597c7712698d06811d9144b0e4f2275a21224ef0238652c947b01198b" +checksum = "f06988129906e9ae1228ea4d8e286e6d93e3331b1b79e73ce22e4d89b886f4d4" dependencies = [ "miden-lifted-air", "miden-stark-transcript", @@ -2983,12 +2976,11 @@ dependencies = [ [[package]] name = "miden-mast-package" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1355a2563a52af4399b4a93120a4398f81415b1fc4edb58310de5034cfa3781d" +checksum = "8e376af0269a87f2b1fd82b24aeb723576bda9c63296d101618c7ce8f9982957" dependencies = [ "hashbrown 0.17.1", - "log", "miden-assembly-syntax", "miden-core", "miden-debug-types", @@ -3037,9 +3029,8 @@ dependencies = [ [[package]] name = "miden-node-proto-build" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724a79e7663157e73de1fc19fcd6e30c7cee4e4c4189d44477922a3969797acb" +version = "0.17.0-rc.1" +source = "git+https://github.com/0xMiden/node?rev=f64fe50f31ea58bcb791a35b826f71e99e74034c#f64fe50f31ea58bcb791a35b826f71e99e74034c" dependencies = [ "build-rs", "codegen", @@ -3063,9 +3054,9 @@ dependencies = [ [[package]] name = "miden-package-registry" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a799e66245492c193b0444c3e0ff0fe42418009ec668a3e80c40d9f5b1454aac" +checksum = "8444acad2bc21dc662a845d3fd57ccfb57b93abddeac3017e60781d15c89264a" dependencies = [ "miden-assembly-syntax", "miden-core", @@ -3079,29 +3070,44 @@ dependencies = [ [[package]] name = "miden-precompiles" -version = "0.29.4" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64ed605e6320c507ab620dda1edfeba66ef724b685d59b5424fc36d587bb3f0" +dependencies = [ + "miden-core", + "miden-crypto", + "ruint", +] + +[[package]] +name = "miden-precompiles-air" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "073ebeeb4413b9a03c60b0b066f94b8edaa6f50150017a92dc09d3ace92d6976" +checksum = "59088ac195be1b19e67e8eebee431f93fed6a568c235df5c4c84f5d43891f063" dependencies = [ + "miden-air", "miden-core", "miden-crypto", + "miden-lifted-air", + "miden-lifted-stark", + "miden-precompiles", + "p3-security", + "ruint", ] [[package]] name = "miden-precompiles-prover" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76663c4d90cc073f9e2d2aa2349b9dcd25bf6c40db5020d27ce59990b6bd5af" +checksum = "30dd301d04535670c466447194b2fb319aa10169b6df0134ab03b34bc3f1f36e" dependencies = [ - "miden-ace-codegen", "miden-air", "miden-core", "miden-crypto", "miden-lifted-air", "miden-lifted-stark", "miden-precompiles", - "miden-serde-utils", - "ruint", + "miden-precompiles-air", "serde", "serde-wincode", "thiserror", @@ -3109,11 +3115,30 @@ dependencies = [ "wincode", ] +[[package]] +name = "miden-precompiles-verifier" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8556c5da1c78d30c91146d0a9dd3b9aa50f8d278ed65ae945e87bfa35549b5ce" +dependencies = [ + "miden-ace-codegen", + "miden-core", + "miden-crypto", + "miden-lifted-air", + "miden-lifted-stark", + "miden-precompiles-air", + "miden-serde-utils", + "serde", + "serde-wincode", + "thiserror", + "wincode", +] + [[package]] name = "miden-processor" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7331ab96f00f922d29e2f59285f539299061a44ffdeea31b853d2c071f8056" +checksum = "b76c2477a17a83ac74a6956a2fec521b1f7a4847a617a318a6a4602fae856390" dependencies = [ "hashbrown 0.17.1", "itertools 0.15.0", @@ -3132,12 +3157,13 @@ dependencies = [ [[package]] name = "miden-project" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8201d3a6d0c85c747092309c3c420de42e61e76f71df2189a46411100d120a" +checksum = "4c576320a3dedda186b00c1429327d9f11d658c5986e0935bb4efedc76c864f8" dependencies = [ "miden-assembly-syntax", "miden-core", + "miden-debug-types", "miden-mast-package", "miden-package-registry", "proptest", @@ -3149,9 +3175,9 @@ dependencies = [ [[package]] name = "miden-protocol" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ccf181d3a4e90b9e6ac107547ce1db30f085dfe5696a7735b1de03ac02f6ba" +checksum = "2156f076ad20f1e271ed7fc7c404393ee206f44307c5684d7c43d1ab7923e20e" dependencies = [ "bech32", "fs-err", @@ -3164,6 +3190,7 @@ dependencies = [ "miden-crypto-derive", "miden-mast-package", "miden-package-registry", + "miden-precompiles", "miden-processor", "miden-protocol-build-utils", "miden-utils-sync", @@ -3180,9 +3207,9 @@ dependencies = [ [[package]] name = "miden-protocol-build-utils" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d16cdd96c1d0b3b2d57342d37eaadd15cc7c633bda965fc8c3b23ca249965b4" +checksum = "f88ff1be87aa49de41fdf45b3c52b5851270fc0293fa10b3993db0d6bbda49b3" dependencies = [ "fs-err", "miden-assembly", @@ -3196,9 +3223,9 @@ dependencies = [ [[package]] name = "miden-prover" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b20c4cabb7a032e7613adff4c637c267bbcaad0d0fa37f7c7addbe7d425bb5c4" +checksum = "f7f2af66603361338c69cfe4b44dcd3475b65fac947b8bbb5e1f113812a7daea" dependencies = [ "miden-air", "miden-core", @@ -3207,6 +3234,7 @@ dependencies = [ "miden-processor", "serde", "serde-wincode", + "thiserror", "tracing", ] @@ -3222,9 +3250,9 @@ dependencies = [ [[package]] name = "miden-serde-utils" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c21a2acdc1928f86803b3ff3c44564c3f614a7dc47dcd64969a5c856d27988" +checksum = "65ee80264ca8539c385d03accb546ce53acbeb7e83123f3fd1a1472bb3090922" dependencies = [ "p3-field", "p3-goldilocks", @@ -3233,9 +3261,9 @@ dependencies = [ [[package]] name = "miden-standards" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6fc2cdac6d1bb48ae4b0c2f0498e754490750283783b7a71b25c3017e68754" +checksum = "882ad707ef743ea4191c5d52b3cefecdeedeefe06da9047db9f9864724c54d42" dependencies = [ "bon", "miden-assembly", @@ -3250,9 +3278,9 @@ dependencies = [ [[package]] name = "miden-stark-transcript" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d503630c353389838fa5d668a0d4550130453c7b2a72b802d4adc1ea39ab5bee" +checksum = "5838c111819c2789e26e5fa2c891634c9617595af41800a17e41767a438c191c" dependencies = [ "p3-challenger", "p3-field", @@ -3262,9 +3290,9 @@ dependencies = [ [[package]] name = "miden-stateful-hasher" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c2008195bdb552eeb744074bfc8822049552ccdf7aef3321a32e1ab6be92e6" +checksum = "1e0da6e0925167bc8681bd4fed43ed8cc7f7276c2a3e54973427e199598d4d51" dependencies = [ "p3-field", "p3-symmetric", @@ -3272,9 +3300,9 @@ dependencies = [ [[package]] name = "miden-testing" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697ea989c4553c1676dd740e41ad29d35fa6b1ac2ab20893c647fa4c7ec6d9dd" +checksum = "8485920dd5a087a861097dd0bb5930740b903334c188f5bc33f0d3dbabee88b4" dependencies = [ "anyhow", "itertools 0.15.0", @@ -3293,9 +3321,9 @@ dependencies = [ [[package]] name = "miden-tx" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d5e8e69cf0db2d2f37f16909fc17d0b28730e1d21a587580ec90f27e19e309f" +checksum = "55a944c6c07c696a096df8edd654bd148234e11707302536047747232c1dca15" dependencies = [ "bon", "miden-agglayer", @@ -3308,9 +3336,9 @@ dependencies = [ [[package]] name = "miden-tx-batch" -version = "0.16.1" +version = "0.17.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06419d4c747d8e79674d2be1436f0a46abe70aa2598f1789e71a07c14106cfa9" +checksum = "8d63da10df2ac4f7830f0c360609326f728239f4814330e975707c134a9ea246" dependencies = [ "miden-processor", "miden-protocol", @@ -3321,9 +3349,9 @@ dependencies = [ [[package]] name = "miden-utils-core-derive" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107d04fcd05b0308e6347113ee6dc13599755e5b4d05ecc08d8b5c05f36a5a39" +checksum = "5b22f1e067b238d967e58d0f0bbd9b83884ce0d787fad85a609c3ceab0a43413" dependencies = [ "proc-macro2", "quote", @@ -3332,9 +3360,9 @@ dependencies = [ [[package]] name = "miden-utils-diagnostics" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b444d204bf082cdab14015ff10d5b0b43a10fba662fef09e4753f6d07faf1f" +checksum = "73b58b01977ed67d9d7a8f949408983506cafae0d057f0fd755b1d5c9813e083" dependencies = [ "miden-debug-types", "miden-miette", @@ -3343,21 +3371,20 @@ dependencies = [ [[package]] name = "miden-utils-indexing" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ff225060e2a5cc4dd6c898eef1f04739461d3401b6de1692bf443cfdd302b0" +checksum = "7aa1e042a7cc1f095259d9344b7cdec0a5e9b8a4e100b8d5aae3242b31fe6013" dependencies = [ "miden-serde-utils", "proptest", - "serde", "thiserror", ] [[package]] name = "miden-utils-sync" -version = "0.29.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b9cb00f01787f8687447cd8a45b3888b470eb35a132df1be9729779d311fd7" +checksum = "3f3d0f89c457b8357e6d6b5da329999bfd763a61ab7fe3a71b04f3e363912a26" dependencies = [ "lock_api", "loom", @@ -3367,15 +3394,14 @@ dependencies = [ [[package]] name = "miden-verifier" -version = "0.29.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e049df6008af1fea5a66df8ce98075cc9e00f16122fd5f4e7c4be9a263cae46" +checksum = "ec4e5cd6450f03cbda2cb7addec584acca088e97d38ea9855e2f9b35604870df" dependencies = [ "miden-air", "miden-core", "miden-crypto", - "miden-precompiles", - "miden-precompiles-prover", + "miden-precompiles-verifier", "miden-serde-utils", "serde", "serde-wincode", @@ -3384,14 +3410,12 @@ dependencies = [ [[package]] name = "midenc-hir-type" -version = "0.10.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdf2257de8f3486c8f3e93c45219b782bafad62a8694798c05d5b8f3f79c64e" +checksum = "fb7a80104367d0c2359fa48a4a82102c76ce41b6a1a68b2ad99c88b613a87e0c" dependencies = [ "miden-formatting", "miden-serde-utils", - "serde", - "serde_repr", "smallvec", "thiserror", ] @@ -3611,20 +3635,21 @@ checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" [[package]] name = "p3-air" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb1be05c0d6f691afe0c9f468018a9a37cfa904dee78a8081ec96eb3cdd88e8" +checksum = "1de1da5a48410a5a68356cb0c43e2642b6fab1bb5906d77bd33e3e4c4d2a7785" dependencies = [ "p3-field", "p3-matrix", + "serde", "tracing", ] [[package]] name = "p3-blake3" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f202f5fbcceb6f56f783d98efb5de27e5a171470e3364de97b0923b39c87ab5" +checksum = "04035123bce04faf2e6de7ef2fd2d5c250b225a3410f4591d3f352ffb1e8c9b8" dependencies = [ "blake3", "p3-symmetric", @@ -3633,13 +3658,12 @@ dependencies = [ [[package]] name = "p3-challenger" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d5d5e1ecf2c80b09b48ce870e8abd08b643454101c5dc9d0fd71bfbd78224d" +checksum = "d33cda6d6dadf1e541121a479589206b83877889d04a3e6a42610c834d348ed2" dependencies = [ "p3-field", "p3-maybe-rayon", - "p3-monty-31", "p3-symmetric", "p3-util", "tracing", @@ -3647,9 +3671,9 @@ dependencies = [ [[package]] name = "p3-dft" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4321a952da2721ecd85ca593ea189798dfb4e439a2cc1378ce1442091880f173" +checksum = "4344492a3a2981879411ef31b51b12fb364efeda59b9ac855d7d92559e7b46e8" dependencies = [ "itertools 0.15.0", "p3-field", @@ -3662,9 +3686,9 @@ dependencies = [ [[package]] name = "p3-field" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53db75d38e04fc255826f388eca9d05976733dc9754aa3db411bc9ea1a37c1a0" +checksum = "f45f7364ae3aac1bd42e8dfec4aa76d1bc9087c4749649c893a671e386e96727" dependencies = [ "itertools 0.15.0", "num-bigint 0.5.1", @@ -3678,12 +3702,11 @@ dependencies = [ [[package]] name = "p3-goldilocks" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b3f31080df31be723b876709246f8f1e532e1c5b82efb5281d705c8304c63" +checksum = "5c62b44c110832ba3d3a5c11160f591205e23f81a08ceb8c7be1a3a71fc4c214" dependencies = [ "num-bigint 0.5.1", - "p3-challenger", "p3-dft", "p3-field", "p3-mds", @@ -3699,9 +3722,9 @@ dependencies = [ [[package]] name = "p3-keccak" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae50c8c37eb847c660298fb275e53c025c49b2623a8cfabf67f5322258b2b4db" +checksum = "fc78b429da6c572d3d3764d5da86d711f75c0937c9821a8741dd0b4c2314819d" dependencies = [ "p3-symmetric", "p3-util", @@ -3710,9 +3733,9 @@ dependencies = [ [[package]] name = "p3-matrix" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473eb920c446a6f4536e0d3528fbdca2a23c0e24e1d0d7767452e6d385dd335c" +checksum = "92f322bd7dded657d51f4c3adcc64bed27ffe4894dbd0f9c077d5670ce73217e" dependencies = [ "itertools 0.15.0", "p3-field", @@ -3725,18 +3748,18 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fddfd435f96394769414cf5590b77058aa506659bf20d6592e9d1989e04440" +checksum = "486d6396b0d22274f862a6c5987bb25f9ea61b34f21b54c23a2ee53f2d8c20ea" dependencies = [ "rayon", ] [[package]] name = "p3-mds" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551ba0ab2cccd89f85a99450224898aff224e323bbf61f777ba6344f0896ef10" +checksum = "00e11f572a44aa3c91057e59625d0992aacc6ffdb80dc1b44948d5587d66a159" dependencies = [ "p3-dft", "p3-field", @@ -3746,59 +3769,48 @@ dependencies = [ ] [[package]] -name = "p3-monty-31" -version = "0.6.3" +name = "p3-poseidon1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f635f7340cd0868b17e43e0c98fefdafdaed90469d0725caf6d8372a2a47c" +checksum = "457e895bcf89b77e062653021b60c12ccd94dce599c54898d9ced4bfbabc820d" dependencies = [ - "itertools 0.15.0", - "num-bigint 0.5.1", - "p3-dft", "p3-field", - "p3-matrix", - "p3-maybe-rayon", "p3-mds", - "p3-poseidon1", - "p3-poseidon2", "p3-symmetric", - "p3-util", - "paste", "rand 0.10.2", - "serde", - "spin 0.12.3", - "tracing", ] [[package]] -name = "p3-poseidon1" -version = "0.6.3" +name = "p3-poseidon2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d0d304e9a1f29c0d66534aa84e69528e2118351fdce08dcf5898af4e0fecc32" +checksum = "65501f32d58b5055c9470ccff459b2576de5f4e6ba72e91f78457231bc67b1c6" dependencies = [ "p3-field", "p3-mds", "p3-symmetric", + "p3-util", "rand 0.10.2", ] [[package]] -name = "p3-poseidon2" -version = "0.6.3" +name = "p3-security" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43eb8a73a26d14becaed1c67c3e8a047e4311d7909b402383c82ca9643ba17c6" +checksum = "2347869521f4b61e8851ccb8327879a70e64291e884748d14ebc58bc0dd4dbe5" dependencies = [ + "libm", + "p3-air", "p3-field", - "p3-mds", - "p3-symmetric", "p3-util", - "rand 0.10.2", + "serde", ] [[package]] name = "p3-symmetric" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2015ea80cad969b6aabf27a04884286fe1354393b166d968ee0d80a95126b2a4" +checksum = "3335886a1e2bec45877e050f76e6bf7a1a77019111c5f599d8b41c5889a2ea1c" dependencies = [ "itertools 0.15.0", "p3-field", @@ -3808,11 +3820,11 @@ dependencies = [ [[package]] name = "p3-util" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5466fc40e6df89d3b291a2eff16b33e68e8571207790370137ec18090aadab" +checksum = "e020b468e9188da32310d8c876225e5183df105a1970368df97f8a76b85dcc5b" dependencies = [ - "rayon", + "p3-maybe-rayon", "serde", ] @@ -4189,9 +4201,9 @@ dependencies = [ [[package]] name = "proptest-derive" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6dc647500e84a25a85b100e76c85b8ace114c209432dc174f20aac11d4ed6c" +checksum = "c57924a81864dddafba92e1bf92f9bf82f97096c44489548a60e888e1547549b" dependencies = [ "proc-macro2", "quote", @@ -4215,7 +4227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" dependencies = [ "heck", - "itertools 0.14.0", + "itertools 0.13.0", "log", "multimap", "petgraph", @@ -4236,7 +4248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.119", @@ -4324,15 +4336,6 @@ dependencies = [ "pulldown-cmark", ] -[[package]] -name = "pyo3-build-config" -version = "0.28.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e" -dependencies = [ - "target-lexicon", -] - [[package]] name = "quote" version = "1.0.47" @@ -5000,17 +5003,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_repr" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - [[package]] name = "serde_spanned" version = "0.6.9" @@ -5318,12 +5310,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "target-lexicon" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" - [[package]] name = "target-triple" version = "1.0.1" @@ -5370,7 +5356,7 @@ checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-node-genesis" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "miden-agglayer", @@ -6449,7 +6435,7 @@ dependencies = [ [[package]] name = "xtask" -version = "0.16.0" +version = "0.17.0-rc.1" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 02a2a3c0f5..4e35298328 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ edition = "2024" license = "MIT" repository = "https://github.com/0xMiden/rust-sdk" rust-version = "1.98.1" -version = "0.16.0" +version = "0.17.0-rc.1" [profile.dev] codegen-units = 16 @@ -37,27 +37,27 @@ opt-level = 1 [workspace.dependencies] # Workspace crates -miden-client = { default-features = false, path = "crates/rust-client", version = "0.16" } -miden-client-integration-tests = { default-features = false, path = "bin/integration-tests", version = "0.16" } -miden-client-sqlite-store = { default-features = false, path = "crates/sqlite-store", version = "0.16" } +miden-client = { default-features = false, path = "crates/rust-client", version = "0.17.0-rc.1" } +miden-client-integration-tests = { default-features = false, path = "bin/integration-tests", version = "0.17.0-rc.1" } +miden-client-sqlite-store = { default-features = false, path = "crates/sqlite-store", version = "0.17.0-rc.1" } # Miden protocol dependencies -miden-agglayer = { default-features = false, version = "0.16" } -miden-protocol = { default-features = false, version = "0.16" } -miden-standards = { default-features = false, version = "0.16" } -miden-testing = { default-features = false, version = "0.16" } -miden-tx = { default-features = false, version = "0.16" } -miden-tx-batch = { default-features = false, version = "0.16" } +miden-agglayer = { default-features = false, version = "0.17.0-rc.3" } +miden-protocol = { default-features = false, version = "0.17.0-rc.3" } +miden-standards = { default-features = false, version = "0.17.0-rc.3" } +miden-testing = { default-features = false, version = "0.17.0-rc.3" } +miden-tx = { default-features = false, version = "0.17.0-rc.3" } +miden-tx-batch = { default-features = false, version = "0.17.0-rc.3" } # Miden node dependencies -miden-node-proto-build = { default-features = false, version = "0.16" } +miden-node-proto-build = { default-features = false, git = "https://github.com/0xMiden/node", rev = "f64fe50f31ea58bcb791a35b826f71e99e74034c" } # TODO: switch to crates.io release once available miden-note-transport-proto-build = { default-features = false, version = "0.5.0-rc.2" } # Miden debug dependency -miden-assembly-syntax = { default-features = false, version = "0.29" } -miden-debug = { default-features = false, features = ["dap", "std"], version = "0.10" } -miden-mast-package = { default-features = false, version = "0.29" } -miden-processor = { default-features = false, version = "0.29" } +miden-assembly-syntax = { default-features = false, version = "0.32" } +miden-debug = { default-features = false, features = ["dap", "std"], version = "0.15" } +miden-mast-package = { default-features = false, version = "0.32" } +miden-processor = { default-features = false, version = "0.32" } # External dependencies anyhow = { default-features = false, version = "1.0" } diff --git a/Makefile b/Makefile index d70be36700..de61497cff 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,11 @@ MIDEN_FUNDER_ACCOUNTS_DIR?=$(CURDIR)/data/funders # `start-test-node.sh`. Against a deployed network, point this at the accounts deployed there. AGGLAYER_ACCOUNTS_DIR?=$(CURDIR)/data +# The test node writes the serialized protocol configuration to this path. +MIDEN_PROTOCOL_CONFIG?=$(CURDIR)/data/protocol-config.bin + +integration-test integration-test-non-agglayer integration-test-agglayer integration-test-miden-bench integration-test-dev integration-test-binary: export MIDEN_PROTOCOL_CONFIG := $(MIDEN_PROTOCOL_CONFIG) + # Sizes the SQL store scaling benchmark sweeps over. Kept small enough to run on every PR, and # overridable for a deeper local run. STORE_BENCH_ARGS?=--notes 1000,10000 --accounts 100,1000 --iterations 5 diff --git a/bin/integration-tests/README.md b/bin/integration-tests/README.md index afb51e13b5..430b3195e7 100644 --- a/bin/integration-tests/README.md +++ b/bin/integration-tests/README.md @@ -126,6 +126,7 @@ The following environment variables configure both the standalone binary and the - `TEST_MIDEN_PROVER_URL` - Overrides the prover: `devnet`, `testnet`, `localhost`, or a custom URL (default: derived from network) - `TEST_MIDEN_NOTE_TRANSPORT_URL` - Overrides note transport: `devnet`, `testnet`, or a custom URL (default: derived from network) - `MIDEN_TEST_TIMEOUT` - Test timeout in milliseconds (default: `10000`) +- `MIDEN_PROTOCOL_CONFIG` - Path to the serialized protocol configuration for the target network. If unset, the tests load `data/protocol-config.bin` when it exists. The local node startup script generates this file. The integration test Make targets export its absolute path so CLI subprocesses can load it from their temporary directories. ### Network Presets diff --git a/bin/integration-tests/src/config.rs b/bin/integration-tests/src/config.rs index 67c9052829..60ef5d0347 100644 --- a/bin/integration-tests/src/config.rs +++ b/bin/integration-tests/src/config.rs @@ -13,10 +13,11 @@ use miden_client::note_transport::{ NOTE_TRANSPORT_DEVNET_ENDPOINT, NOTE_TRANSPORT_TESTNET_ENDPOINT, }; +use miden_client::protocol_config::ProtocolConfig; use miden_client::rpc::{Endpoint, GrpcClient, VerifyingRpcClient}; use miden_client::testing::common::{FilesystemKeyStore, TestClient, create_test_store_path}; use miden_client::testing::fee::FeeFunder; -use miden_client::{Felt, RemoteTransactionProver}; +use miden_client::{Deserializable, Felt, RemoteTransactionProver}; use miden_client_sqlite_store::ClientBuilderSqliteExt; use rand::RngExt; use uuid::Uuid; @@ -155,6 +156,18 @@ impl ClientConfig { .authenticator(Arc::new(keystore)) .tx_discard_delta(None); + let protocol_config_path = + std::env::var_os("MIDEN_PROTOCOL_CONFIG").map(PathBuf::from).or_else(|| { + let path = PathBuf::from("data/protocol-config.bin"); + path.exists().then_some(path) + }); + if let Some(protocol_config_path) = protocol_config_path { + let bytes = std::fs::read(&protocol_config_path) + .context("failed to read protocol configuration")?; + let config = ProtocolConfig::read_from_bytes(&bytes)?; + builder = builder.protocol_config(config); + } + if let Some(prover_url) = &self.prover_endpoint { builder = builder.prover(Arc::new(RemoteTransactionProver::new(prover_url))); } diff --git a/bin/integration-tests/src/fee_funding.rs b/bin/integration-tests/src/fee_funding.rs index 4fe72574a2..cfbeb2c5e1 100644 --- a/bin/integration-tests/src/fee_funding.rs +++ b/bin/integration-tests/src/fee_funding.rs @@ -200,7 +200,11 @@ impl Funder { .get_block_header_by_num(BlockNumber::GENESIS) .await? .context("genesis block header is not in the funder client's store")?; - let fee_faucet_id = genesis.fee_parameters().fee_faucet_id(); + let fee_faucet_id = client + .get_protocol_config(genesis.protocol_config_commitment()) + .await? + .fee_asset_id() + .faucet_id(); // The callback flag is part of the vault key, and both the wallet's balance and `pay_fee` // use plain assets, so the note has to carry the same flag to be spendable. diff --git a/bin/integration-tests/src/tests/batch.rs b/bin/integration-tests/src/tests/batch.rs index 9e20fdea3b..6cc122f042 100644 --- a/bin/integration-tests/src/tests/batch.rs +++ b/bin/integration-tests/src/tests/batch.rs @@ -52,11 +52,7 @@ pub async fn test_batch_builder_submits_two_p2id_on_one_account( let tx_request_1 = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Private, client.rng(), ) @@ -64,11 +60,7 @@ pub async fn test_batch_builder_submits_two_p2id_on_one_account( let tx_request_2 = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Private, client.rng(), ) @@ -185,7 +177,7 @@ pub async fn test_batch_builder_multiple_accounts(client_config: ClientConfig) - let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); let req_send = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id_a, account_id_b), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id_a, account_id_b), NoteType::Private, client.rng(), ) @@ -322,21 +314,21 @@ pub async fn test_batch_builder_interleaved_pushes(client_config: ClientConfig) let req_a_to_b_first = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id_a, account_id_b), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id_a, account_id_b), NoteType::Private, client.rng(), ) .unwrap(); let req_b_to_a = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id_b, account_id_a), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id_b, account_id_a), NoteType::Private, client.rng(), ) .unwrap(); let req_a_to_b_second = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id_a, account_id_b), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id_a, account_id_b), NoteType::Private, client.rng(), ) diff --git a/bin/integration-tests/src/tests/client.rs b/bin/integration-tests/src/tests/client.rs index 07d91fdbbf..47ebd95a14 100644 --- a/bin/integration-tests/src/tests/client.rs +++ b/bin/integration-tests/src/tests/client.rs @@ -97,22 +97,14 @@ pub async fn test_multiple_tx_on_same_block(client_config: ClientConfig) -> Resu let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); let tx_request_1 = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Private, client.rng(), ) .unwrap(); let tx_request_2 = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Private, client.rng(), ) @@ -446,8 +438,8 @@ pub async fn test_get_account_update(client_config: ClientConfig) -> Result<()> assert!(details1.is_none()); assert_matches!(details2, Some(account) if { account.vault().assets().any(|asset| matches!( - asset, - miden_client::asset::Asset::Fungible(fa) + asset.as_fungible(), + Some(fa) if fa.faucet_id() == faucet_account.id() && fa.amount().as_u64() == MINT_AMOUNT )) }); @@ -482,7 +474,7 @@ pub async fn test_sync_detail_values(client_config: ClientConfig) -> Result<()> // Do a transfer with recall from first account to second account let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); let tx_request = TransactionRequestBuilder::new().build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], from_account_id, to_account_id) + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) .with_reclaim_height(new_details.block_num + 5), NoteType::Public, client1.rng(), @@ -848,7 +840,7 @@ pub async fn test_import_consumed_note_with_proof(client_config: ClientConfig) - info!(from = %from_account_id, to = %to_account_id, "Running P2IDE transaction"); let tx_request = TransactionRequestBuilder::new().build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], from_account_id, to_account_id) + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) .with_reclaim_height(current_block_num), NoteType::Private, client_1.rng(), @@ -912,7 +904,7 @@ pub async fn test_import_consumed_note_with_id(client_config: ClientConfig) -> R info!(from = %from_account_id, to = %to_account_id, "Running P2IDE transaction (public)"); let tx_request = TransactionRequestBuilder::new().build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], from_account_id, to_account_id) + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) .with_reclaim_height(current_block_num), NoteType::Public, client_1.rng(), @@ -972,7 +964,7 @@ pub async fn test_import_note_with_proof(client_config: ClientConfig) -> Result< info!(from = %from_account_id, to = %to_account_id, "Running P2IDE transaction (with proof)"); let tx_request = TransactionRequestBuilder::new().build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], from_account_id, to_account_id) + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) .with_reclaim_height(current_block_num), NoteType::Private, client_1.rng(), @@ -1028,7 +1020,7 @@ pub async fn test_discarded_transaction(client_config: ClientConfig) -> Result<( info!(from = %from_account_id, to = %to_account_id, "Running P2IDE transaction (discarded)"); let tx_request = TransactionRequestBuilder::new().build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], from_account_id, to_account_id) + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) .with_reclaim_height(current_block_num), NoteType::Public, client_1.rng(), @@ -1733,7 +1725,7 @@ pub async fn test_get_account_returns_vault_details(client_config: ClientConfig) // The vault also holds the native fee asset where the chain charges one, so this checks for the // minted token rather than for it alone. - let minted = Asset::Fungible(FungibleAsset::new(faucet.id(), MINT_AMOUNT).unwrap()); + let minted = Asset::from(FungibleAsset::new(faucet.id(), MINT_AMOUNT).unwrap()); assert!( details.vault_details.assets.contains(&minted), "expected the minted token in the vault" diff --git a/bin/integration-tests/src/tests/network_transaction.rs b/bin/integration-tests/src/tests/network_transaction.rs index 70964bde63..9b33cbada1 100644 --- a/bin/integration-tests/src/tests/network_transaction.rs +++ b/bin/integration-tests/src/tests/network_transaction.rs @@ -203,8 +203,14 @@ pub(crate) async fn deploy_network_counter_contract( .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 fee_policy_manager = zero_fee_policy_manager( + client + .get_protocol_config(genesis.protocol_config_commitment()) + .await? + .fee_asset_id() + .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")?; @@ -337,7 +343,11 @@ async fn deploy_network_fungible_faucet( .await? .context("genesis block header is not in the store")?; let fee_policy_manager = zero_fee_policy_manager( - genesis.fee_parameters().fee_faucet_id(), + client + .get_protocol_config(genesis.protocol_config_commitment()) + .await? + .fee_asset_id() + .faucet_id(), allowed_roots.iter().copied(), ); let faucet = NetworkAccount::builder(init_seed, allowed_roots, fee_policy_manager)? @@ -432,7 +442,7 @@ fn build_non_standard_mint( ) .details_commitment(); - let mint_storage = MintNoteStorage::new_fungible_public( + let mint_storage = MintNoteStorage::new_public( recipient, expected_asset, NoteTag::with_account_target(target), @@ -742,7 +752,7 @@ pub async fn test_ntx_mint_produces_public_p2id(client_config: ClientConfig) -> ) .details_commitment(); - let mint_storage = MintNoteStorage::new_fungible_public( + let mint_storage = MintNoteStorage::new_public( bob_recipient, expected_asset, NoteTag::with_account_target(bob.id()), diff --git a/bin/integration-tests/src/tests/onchain.rs b/bin/integration-tests/src/tests/onchain.rs index 6533db61c7..b1467cdae8 100644 --- a/bin/integration-tests/src/tests/onchain.rs +++ b/bin/integration-tests/src/tests/onchain.rs @@ -262,7 +262,7 @@ pub async fn test_onchain_accounts(client_config: ClientConfig) -> Result<()> { info!(from = %from_account_id, to = %to_account_id, amount = TRANSFER_AMOUNT, "Running P2ID transaction"); let tx_request = TransactionRequestBuilder::new().build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], from_account_id, to_account_id), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Public, client_1.rng(), )?; diff --git a/bin/integration-tests/src/tests/pass_through.rs b/bin/integration-tests/src/tests/pass_through.rs index 8a35920592..c963007199 100644 --- a/bin/integration-tests/src/tests/pass_through.rs +++ b/bin/integration-tests/src/tests/pass_through.rs @@ -248,9 +248,15 @@ async fn pass_through_fee_asset return Ok(None); } + let fee_faucet_id = client + .get_protocol_config(genesis.protocol_config_commitment()) + .await? + .fee_asset_id() + .faucet_id(); + let worst_case_fee = TransactionFee::new(MAX_TX_EXECUTION_CYCLES)?.compute_fee(fee_parameters)?; - let funding = FungibleAsset::new(fee_parameters.fee_faucet_id(), worst_case_fee.as_u64())?; + let funding = FungibleAsset::new(fee_faucet_id, worst_case_fee.as_u64())?; let (probe_note, probe_details) = create_pass_through_note(sender, target, asset, Some(funding.into()), client.rng())?; @@ -263,7 +269,7 @@ async fn pass_through_fee_asset .executed_transaction() .compute_fee(); - Ok(Some(FungibleAsset::new(fee_parameters.fee_faucet_id(), fee.as_u64())?)) + Ok(Some(FungibleAsset::new(fee_faucet_id, fee.as_u64())?)) } fn get_pass_through_note_script() -> NoteScript { diff --git a/bin/integration-tests/src/tests/swap_transaction.rs b/bin/integration-tests/src/tests/swap_transaction.rs index 96e1b3f0d8..9de8ee3be7 100644 --- a/bin/integration-tests/src/tests/swap_transaction.rs +++ b/bin/integration-tests/src/tests/swap_transaction.rs @@ -59,8 +59,8 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> let tx_request = TransactionRequestBuilder::new().build_swap( &SwapTransactionData::new( account_a.id(), - Asset::Fungible(offered_asset), - Asset::Fungible(requested_asset), + Asset::from(offered_asset), + Asset::from(requested_asset), ), NoteType::Public, NoteType::Private, @@ -77,8 +77,8 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> let swap_note_tag = SwapNote::create_tag( NoteType::Public, - &Asset::Fungible(offered_asset), - &Asset::Fungible(requested_asset), + &Asset::from(offered_asset), + &Asset::from(requested_asset), ); // add swap note's tag to client2, we could technically avoid this step, but for the first @@ -180,8 +180,8 @@ pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { let tx_request = TransactionRequestBuilder::new().build_swap( &SwapTransactionData::new( account_a.id(), - Asset::Fungible(offered_asset), - Asset::Fungible(requested_asset), + Asset::from(offered_asset), + Asset::from(requested_asset), ), NoteType::Private, NoteType::Private, @@ -204,8 +204,8 @@ pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { let tag = SwapNote::create_tag( NoteType::Private, - &Asset::Fungible(offered_asset), - &Asset::Fungible(requested_asset), + &Asset::from(offered_asset), + &Asset::from(requested_asset), ); client2.add_note_tag(tag).await?; client2 diff --git a/bin/miden-bench/README.md b/bin/miden-bench/README.md index eefb1f26b4..d166d05999 100644 --- a/bin/miden-bench/README.md +++ b/bin/miden-bench/README.md @@ -16,6 +16,8 @@ After installation, the `miden-bench` binary will be available in your PATH. ## Commands +Network commands require the protocol configuration for the target network. Set `MIDEN_PROTOCOL_CONFIG` to the serialized configuration file before deploying an account. For the local testing node, use `export MIDEN_PROTOCOL_CONFIG="$PWD/data/protocol-config.bin"` after `make start-node-background`. The benchmark client stores the configuration for later commands. The `store` benchmark does not require this file. + ### `deploy` Deploys a public wallet with empty storage maps to the network. This is the first step in preparing an account for benchmarking. Storage maps are created empty; use `expand` to fill them with entries. diff --git a/bin/miden-bench/src/config.rs b/bin/miden-bench/src/config.rs index 8cf33981fc..107e5b9e05 100644 --- a/bin/miden-bench/src/config.rs +++ b/bin/miden-bench/src/config.rs @@ -4,8 +4,9 @@ use std::sync::Arc; use miden_client::builder::ClientBuilder; use miden_client::crypto::RandomCoin; use miden_client::keystore::FilesystemKeyStore; +use miden_client::protocol_config::ProtocolConfig; use miden_client::rpc::{Endpoint, GrpcClient, VerifyingRpcClient}; -use miden_client::{Client, Felt}; +use miden_client::{Client, Deserializable, Felt}; use miden_client_sqlite_store::ClientBuilderSqliteExt; use rand::RngExt; @@ -59,5 +60,10 @@ pub async fn create_client( .build() .await?; + if let Some(path) = std::env::var_os("MIDEN_PROTOCOL_CONFIG") { + let bytes = std::fs::read(path)?; + let config = ProtocolConfig::read_from_bytes(&bytes)?; + client.add_protocol_config(config).await?; + } Ok(client) } diff --git a/bin/miden-bench/src/generators/store_data.rs b/bin/miden-bench/src/generators/store_data.rs index 2463636a53..ea0ee31876 100644 --- a/bin/miden-bench/src/generators/store_data.rs +++ b/bin/miden-bench/src/generators/store_data.rs @@ -29,7 +29,7 @@ use miden_client::store::input_note_states::{ NoteSubmissionData, }; use miden_client::testing::account_id::ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE; -use miden_client::transaction::{TransactionId, TransactionKernel}; +use miden_client::transaction::TransactionId; use miden_client::utils::Serializable; use miden_client::{EMPTY_WORD, Felt, Word, ZERO}; @@ -203,7 +203,7 @@ fn note_metadata(sender: AccountId, index: usize) -> NoteMetadata { // ================================================================================================ fn mock_block_header(block_num: u32) -> BlockHeader { - BlockHeader::mock(block_num, None, None, &[], TransactionKernel.to_commitment()) + BlockHeader::mock(block_num, None, None, &[]) } // ACCOUNTS diff --git a/bin/miden-cli/Cargo.toml b/bin/miden-cli/Cargo.toml index 6585334916..8e05a8ab16 100644 --- a/bin/miden-cli/Cargo.toml +++ b/bin/miden-cli/Cargo.toml @@ -50,7 +50,7 @@ assert_cmd = { workspace = true } miden-client = { features = ["testing"], workspace = true } miden-client-integration-tests = { workspace = true } miden-mast-package = { features = ["std"], workspace = true } -midenc-hir-type = { version = "0.10" } +midenc-hir-type = { version = "0.14" } predicates = { workspace = true } regex = { workspace = true } serial_test = { features = ["file_locks"], version = "3.0" } diff --git a/bin/miden-cli/src/codecs/asset.rs b/bin/miden-cli/src/codecs/asset.rs index 7adc51647e..ad5ffe02ea 100644 --- a/bin/miden-cli/src/codecs/asset.rs +++ b/bin/miden-cli/src/codecs/asset.rs @@ -56,9 +56,9 @@ impl WitScalarCodec for AssetCodec { let value = Word::from([*v0, *v1, *v2, *v3]); let asset = Asset::from_id_and_value_words(id, value) .map_err(|_| malformed_asset("the felts are not a valid asset"))?; - Ok(match asset { - Asset::Fungible(f) => format!("asset({}::{})", f.amount(), f.faucet_id().to_hex()), - Asset::NonFungible(_) => "asset(non-fungible)".to_string(), + Ok(match asset.as_fungible() { + Some(f) => format!("asset({}::{})", f.amount(), f.faucet_id().to_hex()), + None => "asset(non-fungible)".to_string(), }) } } diff --git a/bin/miden-cli/src/commands/account.rs b/bin/miden-cli/src/commands/account.rs index 9abb45ea48..5c958111ee 100644 --- a/bin/miden-cli/src/commands/account.rs +++ b/bin/miden-cli/src/commands/account.rs @@ -13,7 +13,7 @@ use miden_client::account::{ StorageSlotContent, }; use miden_client::address::{Address, AddressInterface, NetworkId, RoutingParameters}; -use miden_client::asset::{Asset, TokenSymbol}; +use miden_client::asset::TokenSymbol; use miden_client::rpc::domain::account::GetAccountRequest; use miden_client::rpc::{GrpcClient, NodeRpcClient, VerifyingRpcClient}; use miden_client::transaction::{AccountComponentInterface, AccountInterface}; @@ -205,8 +205,8 @@ async fn show_account( let mut table = create_dynamic_table(&["Asset Type", "Faucet", "Amount"]); for asset in assets { - let (asset_type, faucet, amount) = match asset { - Asset::Fungible(fungible_asset) => { + let (asset_type, faucet, amount) = match asset.as_fungible() { + Some(fungible_asset) => { let faucet_id = fungible_asset.faucet_id(); let asset_amount = fungible_asset.amount(); let (faucet, amount) = match get_faucet_token_info(client, faucet_id).await { @@ -217,13 +217,9 @@ async fn show_account( }; ("Fungible Asset", faucet, amount) }, - Asset::NonFungible(non_fungible_asset) => { + None => { // TODO: Display non-fungible assets more clearly. - ( - "Non Fungible Asset", - non_fungible_asset.faucet_id().prefix().to_hex(), - 1.0.to_string(), - ) + ("Non Fungible Asset", asset.faucet_id().prefix().to_hex(), 1.0.to_string()) }, }; table.add_row(vec![asset_type, &faucet, &amount.clone()]); diff --git a/bin/miden-cli/src/commands/mod.rs b/bin/miden-cli/src/commands/mod.rs index f3cd2b8980..08632baa1f 100644 --- a/bin/miden-cli/src/commands/mod.rs +++ b/bin/miden-cli/src/commands/mod.rs @@ -25,7 +25,7 @@ fn report_replay_snapshot_write( ) -> Result<(), CliError> { match recorder.take() { Some(Ok(write)) => { - println!("Replay it offline with `miden-debug --replay {}`.", write.path.display()); + println!("Replay it offline with `miden-debug --replay {}`.", write.path); Ok(()) }, Some(Err(err)) => Err(CliError::ReplaySnapshot(Box::new(err))), diff --git a/bin/miden-cli/src/commands/new_account.rs b/bin/miden-cli/src/commands/new_account.rs index abda76c2fe..ac5db15843 100644 --- a/bin/miden-cli/src/commands/new_account.rs +++ b/bin/miden-cli/src/commands/new_account.rs @@ -628,8 +628,8 @@ fn process_packages( format!("error creating InitStorageData for Package {}", package.name), ) })?; - let account_component = - AccountComponent::from_package(&package, &init_data).map_err(|e| { + let account_component = AccountComponent::from_package(package.clone(), &init_data) + .map_err(|e| { CliError::Account( e, format!("error instantiating component from Package {}", package.name), diff --git a/bin/miden-cli/src/commands/new_transactions.rs b/bin/miden-cli/src/commands/new_transactions.rs index 62a8442475..b2d5d284d7 100644 --- a/bin/miden-cli/src/commands/new_transactions.rs +++ b/bin/miden-cli/src/commands/new_transactions.rs @@ -414,8 +414,8 @@ impl PswapCmd { client: Client, ) -> Result<(), CliError> { match &self.action { - PswapAction::Create(cmd) => cmd.execute(client).await, - PswapAction::Consume(cmd) => cmd.execute(client).await, + PswapAction::Create(cmd) => Box::pin(cmd.execute(client)).await, + PswapAction::Consume(cmd) => Box::pin(cmd.execute(client)).await, PswapAction::Cancel(cmd) => cmd.execute(client).await, } } diff --git a/bin/miden-cli/src/commands/notes.rs b/bin/miden-cli/src/commands/notes.rs index bcf4bb4334..b7d2d15d78 100644 --- a/bin/miden-cli/src/commands/notes.rs +++ b/bin/miden-cli/src/commands/notes.rs @@ -1,7 +1,6 @@ use clap::ValueEnum; use comfy_table::{Attribute, Cell, ContentArrangement, Table, presets}; use miden_client::address::Address; -use miden_client::asset::Asset; use miden_client::keystore::Keystore; use miden_client::note::{ Note, @@ -264,17 +263,13 @@ async fn show_note( let assets = assets.iter(); for asset in assets { - let (asset_type, faucet, amount) = match asset { - Asset::Fungible(fungible_asset) => { + let (asset_type, faucet, amount) = match asset.as_fungible() { + Some(fungible_asset) => { let (faucet, amount) = - resolver.format_fungible_asset(client, fungible_asset).await?; + resolver.format_fungible_asset(client, &fungible_asset).await?; ("Fungible Asset", faucet, amount) }, - Asset::NonFungible(non_fungible_asset) => ( - "Non Fungible Asset", - non_fungible_asset.faucet_id().prefix().to_hex(), - 1.0.to_string(), - ), + None => ("Non Fungible Asset", asset.faucet_id().prefix().to_hex(), 1.0.to_string()), }; table.add_row(vec![asset_type, &faucet, &amount.clone()]); } diff --git a/bin/miden-cli/src/config.rs b/bin/miden-cli/src/config.rs index 5979503d5e..f0ed6d321f 100644 --- a/bin/miden-cli/src/config.rs +++ b/bin/miden-cli/src/config.rs @@ -69,6 +69,8 @@ impl std::fmt::Display for ConfigDir { #[derive(Debug, Deserialize, Serialize)] pub struct CliConfig { + /// Native fee faucet for the current protocol configuration. + pub fee_faucet_id: Option, /// The directory this configuration was loaded from. Not part of the TOML file. #[serde(skip)] pub config_dir: Option, @@ -121,6 +123,7 @@ impl Default for CliConfig { // Create paths relative to the config file location (which is in .miden directory) These // will be resolved relative to the .miden directory when the config is loaded Self { + fee_faucet_id: None, config_dir: None, rpc: RpcConfig::default(), store_filepath: PathBuf::from(STORE_FILENAME), diff --git a/bin/miden-cli/src/lib.rs b/bin/miden-cli/src/lib.rs index 8864f14a76..f3ed8a480b 100644 --- a/bin/miden-cli/src/lib.rs +++ b/bin/miden-cli/src/lib.rs @@ -5,10 +5,12 @@ use std::sync::Arc; use clap::{Parser, Subcommand}; use comfy_table::{Attribute, Cell, ContentArrangement, Table, presets}; use errors::CliError; -use miden_client::account::AccountHeader; +use miden_client::account::{AccountHeader, AccountId}; +use miden_client::asset::AssetId; use miden_client::builder::ClientBuilder; use miden_client::keystore::{FilesystemKeyStore, Keystore}; use miden_client::note_transport::grpc::GrpcNoteTransportClient; +use miden_client::protocol_config::ProtocolConfig; use miden_client::rpc::{GrpcClient, VerifyingRpcClient}; use miden_client::store::{NoteFilter as ClientNoteFilter, OutputNoteRecord}; use miden_client_sqlite_store::ClientBuilderSqliteExt; @@ -142,6 +144,21 @@ impl CliClient { .authenticator(Arc::new(keystore)) .tx_discard_delta(Some(TX_DISCARD_DELTA)); + if let Some(faucet) = config.fee_faucet_id.as_deref() { + let faucet_id = AccountId::from_hex(faucet).map_err(|err| { + CliError::Config(Box::new(err), "invalid `fee_faucet_id`".to_string()) + })?; + let protocol_config = ProtocolConfig::current(AssetId::new_fungible(faucet_id)) + .map_err(|err| { + CliError::Config( + Box::new(err), + "failed to derive the protocol configuration from `fee_faucet_id`" + .to_string(), + ) + })?; + builder = builder.protocol_config(protocol_config); + } + if let Some(delta) = config.max_block_number_delta { builder = builder.max_block_number_delta(delta); } @@ -153,6 +170,16 @@ impl CliClient { } let client = builder.build().await.map_err(CliError::from)?; + if let Some(path) = std::env::var_os("MIDEN_PROTOCOL_CONFIG") { + let path = std::path::PathBuf::from(path); + let bytes = std::fs::read(&path).map_err(|err| { + CliError::Config(Box::new(err), format!("failed to read {}", path.display())) + })?; + let protocol_config = ProtocolConfig::read_from_bytes(&bytes).map_err(|err| { + CliError::Config(Box::new(err), format!("failed to decode {}", path.display())) + })?; + client.add_protocol_config(protocol_config).await.map_err(CliError::from)?; + } Ok(CliClient(client)) } diff --git a/bin/miden-cli/src/utils.rs b/bin/miden-cli/src/utils.rs index 422baa695c..8837c295dd 100644 --- a/bin/miden-cli/src/utils.rs +++ b/bin/miden-cli/src/utils.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use miden_client::account::{AccountId, FaucetMetadata}; use miden_client::address::{Address, AddressId}; -use miden_client::asset::{Asset, FungibleAsset}; +use miden_client::asset::FungibleAsset; use miden_client::transaction::{ExecutedTransaction, InputNote}; use miden_client::utils::{base_units_to_tokens, tokens_to_base_units}; use miden_client::vm::MIN_STACK_DEPTH; @@ -183,16 +183,16 @@ pub async fn print_executed_transaction( let mut table = create_dynamic_table(&["Asset Type", "Faucet ID", "New Amount"]); for asset in patch.vault().updated_assets() { - match asset { - Asset::Fungible(fungible) => { + match asset.as_fungible() { + Some(fungible) => { let (faucet_fmt, amount_fmt) = resolver.format_fungible_asset(client, &fungible).await?; table.add_row(vec!["Fungible Asset", &faucet_fmt, &amount_fmt]); }, - Asset::NonFungible(non_fungible) => { + None => { table.add_row(vec![ "Non Fungible Asset", - &non_fungible.faucet_id().prefix().to_hex(), + &asset.faucet_id().prefix().to_hex(), "1", ]); }, diff --git a/bin/miden-cli/tests/cli.rs b/bin/miden-cli/tests/cli.rs index 7e64ca1428..6be5093903 100644 --- a/bin/miden-cli/tests/cli.rs +++ b/bin/miden-cli/tests/cli.rs @@ -1778,13 +1778,13 @@ fn call_nonexistent_procedure() { fn call_test_exports(package: &Package) -> Vec { // The `account-id` core type as the compiler records it: a named record of two field elements. // Its name is what the CLI's `account-id` codec matches against. - let account_id = Type::Struct(Arc::new(StructType::named( + let account_id = Type::Struct(midenc_hir_type::StructRef::Plain(Arc::new(StructType::named( Arc::from("miden:base/core-types@1.0.0/account-id"), [ (Arc::::from("prefix"), Type::Felt), (Arc::::from("suffix"), Type::Felt), ], - ))); + )))); let signature_overrides: [(&str, FunctionType); 6] = [ ( diff --git a/crates/rust-client/src/account/account_reader.rs b/crates/rust-client/src/account/account_reader.rs index 7456354234..85bcc05962 100644 --- a/crates/rust-client/src/account/account_reader.rs +++ b/crates/rust-client/src/account/account_reader.rs @@ -12,7 +12,8 @@ use miden_protocol::account::{ StorageSlotName, }; use miden_protocol::address::Address; -use miden_protocol::asset::{Asset, AssetAmount, AssetId}; +use miden_protocol::asset::{Asset, AssetAmount, AssetComposition, AssetId}; +use miden_protocol::errors::AssetError; use miden_protocol::{Felt, Word}; use crate::errors::ClientError; @@ -135,20 +136,30 @@ impl AccountReader { /// Retrieves the balance of a fungible asset in the account's vault. /// - /// Returns [`AssetAmount::ZERO`] if the asset is not present in the vault or if the asset is - /// not a fungible asset. + /// Returns [`AssetAmount::ZERO`] if the asset is not present in the vault. /// /// To load the entire vault, use /// [`Client::get_account_vault`](crate::Client::get_account_vault). + /// + /// # Errors + /// Returns an error if the stored asset cannot be read as a fungible asset. The lookup key is + /// built as a fungible asset id, so that only happens for a stored value the protocol rejects. pub async fn get_balance(&self, faucet_id: AccountId) -> Result { let asset_id = AssetId::new_fungible(faucet_id); - if let Some((Asset::Fungible(fungible_asset), _)) = - self.store.get_account_asset(self.account_id, asset_id).await? - { - Ok(fungible_asset.amount()) - } else { - Ok(AssetAmount::ZERO) - } + let Some((asset, _)) = self.store.get_account_asset(self.account_id, asset_id).await? + else { + return Ok(AssetAmount::ZERO); + }; + + let fungible_asset = asset.as_fungible().ok_or_else(|| { + ClientError::AssetError(AssetError::AssetCompositionMismatch { + faucet_id, + expected: AssetComposition::Fungible, + actual: asset.id().composition(), + }) + })?; + + Ok(fungible_asset.amount()) } // STORAGE ACCESS diff --git a/crates/rust-client/src/builder.rs b/crates/rust-client/src/builder.rs index 3541e8ae9c..40db50b863 100644 --- a/crates/rust-client/src/builder.rs +++ b/crates/rust-client/src/builder.rs @@ -6,6 +6,7 @@ use alloc::vec::Vec; use miden_protocol::assembly::{DefaultSourceManager, SourceManagerSync}; use miden_protocol::block::BlockNumber; use miden_protocol::crypto::rand::RandomCoin; +use miden_protocol::protocol_config::ProtocolConfig; use miden_protocol::{Felt, MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES}; use miden_tx::auth::TransactionAuthenticator; use miden_tx::{ExecutionOptions, LocalTransactionProver}; @@ -85,6 +86,8 @@ pub trait StoreFactory { /// - **Store** ([`Store`]): Provides persistence for accounts, notes, and transaction history. /// Configure via [`store()`](Self::store). /// +/// - **Protocol configuration** ([`ProtocolConfig`]): Defines the protocol parameters for transaction execution and note screening. Register it with [`protocol_config()`](Self::protocol_config), or use a store that already contains it. +/// /// - **RNG** ([`FeltRng`](miden_protocol::crypto::rand::FeltRng)): Provides randomness for /// generating keys, serial numbers, and other cryptographic operations. If not provided, a random /// seed-based RNG is created automatically. Configure via [`rng()`](Self::rng). @@ -110,6 +113,8 @@ pub trait StoreFactory { /// transactions and account proofs to be considered valid. Configure via /// [`max_block_number_delta()`](Self::max_block_number_delta). pub struct ClientBuilder { + /// An optional protocol configuration, registered in the store when the client is built. + protocol_config: Option, /// An optional custom RPC client. If provided, this takes precedence over `rpc_endpoint`. rpc_api: Option>, /// An optional store provided by the user. @@ -145,6 +150,7 @@ pub struct ClientBuilder { impl Default for ClientBuilder { fn default() -> Self { Self { + protocol_config: None, rpc_api: None, store: None, rng: None, @@ -336,6 +342,13 @@ where self } + /// Registers a protocol configuration for execution and note screening. + #[must_use] + pub fn protocol_config(mut self, config: ProtocolConfig) -> Self { + self.protocol_config = Some(config); + self + } + /// Optionally provide a custom RNG. #[must_use] pub fn rng(mut self, rng: ClientRngBox) -> Self { @@ -515,7 +528,7 @@ where vec![Arc::new(PswapTransactionObserver::new(store.clone()))]; // Construct and return the Client - Ok(Client { + let client = Client { store, rng: ClientRng::new(rng), rpc_api, @@ -536,7 +549,11 @@ where cache_partial_mmr_in_memory: self.cache_partial_mmr_in_memory, partial_mmr: None, transaction_observers, - }) + }; + if let Some(config) = self.protocol_config { + client.add_protocol_config(config).await?; + } + Ok(client) } } diff --git a/crates/rust-client/src/errors.rs b/crates/rust-client/src/errors.rs index 3cb3a3c297..0b13bd6ebb 100644 --- a/crates/rust-client/src/errors.rs +++ b/crates/rust-client/src/errors.rs @@ -3,7 +3,6 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::fmt; -use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::crypto::merkle::MerkleError; pub use miden_protocol::errors::{ @@ -19,10 +18,10 @@ use miden_protocol::errors::{ ProposedBatchError, ProvenBatchError, TransactionInputError, - TransactionScriptError, }; use miden_protocol::note::NoteId; use miden_protocol::transaction::{ProvenTransaction, TransactionId, TransactionInputs}; +use miden_protocol::{MastForestScriptError, Word}; // RE-EXPORTS // ================================================================================================ pub use miden_standards::errors::CodeBuilderError; @@ -195,8 +194,8 @@ pub enum ClientError { TransactionRequestError(#[from] TransactionRequestError), #[error("failed to build the send-notes transaction script")] SendNotesTransactionScriptError(#[from] SendNotesTransactionScriptError), - #[error("transaction script error")] - TransactionScriptError(#[source] TransactionScriptError), + #[error("mast forest script error")] + MastForestScriptError(#[source] MastForestScriptError), #[error("client initialization error: {0}")] ClientInitializationError(String), #[error("expected full account data for account {0}, but only partial data is available")] diff --git a/crates/rust-client/src/lib.rs b/crates/rust-client/src/lib.rs index ffa3e1b552..ca419472b8 100644 --- a/crates/rust-client/src/lib.rs +++ b/crates/rust-client/src/lib.rs @@ -121,6 +121,7 @@ pub mod grpc_support; pub mod keystore; pub mod note; pub mod note_transport; +pub mod protocol_config; pub mod pswap; #[cfg(feature = "tonic")] pub mod remote_prover; @@ -174,12 +175,7 @@ pub mod assembly { /// Provides types and utilities for working with assets within the Miden network. pub mod asset { - pub use miden_protocol::account::delta::{ - AccountVaultDelta, - FungibleAssetDelta, - NonFungibleAssetDelta, - NonFungibleDeltaAction, - }; + pub use miden_protocol::account::delta::AccountVaultDelta; pub use miden_protocol::account::{ AccountStorageHeader, AssetCallbackFlag, @@ -235,7 +231,7 @@ pub mod auth { /// Provides types for working with blocks within the Miden network. pub mod block { - pub use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters, ValidatorKeys}; + pub use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters, ValidatorConfig}; } /// Provides cryptographic types and utilities used within the Miden rollup network. It re-exports @@ -278,7 +274,6 @@ pub mod crypto { LeafIndex, SMT_DEPTH, Smt, - SmtForest, SmtLeaf, SmtProof, VersionId, diff --git a/crates/rust-client/src/note/mod.rs b/crates/rust-client/src/note/mod.rs index 9f080a35d5..3159eae972 100644 --- a/crates/rust-client/src/note/mod.rs +++ b/crates/rust-client/src/note/mod.rs @@ -106,11 +106,11 @@ pub use miden_protocol::note::{ 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::config::NetworkAccountConfigNote; pub use miden_standards::note::{ FeeSponsorshipNote, MintNote, MintNoteStorage, - NetworkAccountConfigNote, NetworkAccountTarget, NoteConsumptionStatus, NoteExecutionHint, diff --git a/crates/rust-client/src/note/note_screener.rs b/crates/rust-client/src/note/note_screener.rs index 7e80433e34..96d0e1c1d7 100644 --- a/crates/rust-client/src/note/note_screener.rs +++ b/crates/rust-client/src/note/note_screener.rs @@ -252,6 +252,11 @@ impl NoteScreener { let Some(conversion_info) = native_fee_conversion_info( &account_code.interface(account_id), header.fee_parameters(), + &crate::protocol_config::load_protocol_config( + self.store.as_ref(), + header.protocol_config_commitment(), + ) + .await?, ) else { return Ok(tx_args); }; diff --git a/crates/rust-client/src/protocol_config.rs b/crates/rust-client/src/protocol_config.rs new file mode 100644 index 0000000000..8982986872 --- /dev/null +++ b/crates/rust-client/src/protocol_config.rs @@ -0,0 +1,53 @@ +//! Stores protocol configurations by their block header commitments. + +use alloc::format; + +use miden_protocol::Word; +pub use miden_protocol::errors::ProtocolConfigError; +pub use miden_protocol::protocol_config::{NextProtocolConfig, ProtocolConfig}; +use miden_protocol::utils::serde::{Deserializable, Serializable}; + +use crate::store::{SettingScope, Store, StoreError}; +use crate::{Client, ClientError}; + +impl Client { + /// Stores a protocol configuration for transaction execution and note screening. The + /// configuration must match the commitment in the transaction reference block. + pub async fn add_protocol_config(&self, config: ProtocolConfig) -> Result<(), ClientError> { + self.store + .set_setting( + SettingScope::Client, + config_key(config.to_commitment()), + config.to_bytes(), + ) + .await?; + Ok(()) + } + + /// Returns the stored protocol configuration for the specified commitment. + pub async fn get_protocol_config( + &self, + commitment: Word, + ) -> Result { + Ok(load_protocol_config(self.store.as_ref(), commitment).await?) + } +} + +fn config_key(commitment: Word) -> alloc::string::String { + format!("protocol_config:{commitment}") +} + +pub(crate) async fn load_protocol_config( + store: &dyn Store, + commitment: Word, +) -> Result { + let bytes = store + .get_setting(SettingScope::Client, config_key(commitment)) + .await? + .ok_or(StoreError::ProtocolConfigNotFound(commitment))?; + let config = ProtocolConfig::read_from_bytes(&bytes)?; + if config.to_commitment() != commitment { + return Err(StoreError::ProtocolConfigCommitmentMismatch(commitment)); + } + Ok(config) +} diff --git a/crates/rust-client/src/rpc/domain/block.rs b/crates/rust-client/src/rpc/domain/block.rs index 4c57f3afd7..7256ca2609 100644 --- a/crates/rust-client/src/rpc/domain/block.rs +++ b/crates/rust-client/src/rpc/domain/block.rs @@ -1,8 +1,9 @@ use alloc::string::ToString; use alloc::vec::Vec; -use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters, ValidatorKeys}; +use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters, ValidatorConfig}; use miden_protocol::crypto::dsa::ecdsa_k256_keccak; +use miden_protocol::protocol_config::NextProtocolConfig; use miden_protocol::utils::serde::{Deserializable, Serializable}; use crate::rpc::domain::MissingFieldHelper; @@ -15,7 +16,7 @@ use crate::rpc::generated as proto; impl From<&BlockHeader> for proto::blockchain::BlockHeader { fn from(header: &BlockHeader) -> Self { Self { - version: header.version(), + version: header.version().into(), prev_block_commitment: Some(header.prev_block_commitment().into()), block_num: header.block_num().as_u32(), chain_commitment: Some(header.chain_commitment().into()), @@ -23,13 +24,24 @@ impl From<&BlockHeader> for proto::blockchain::BlockHeader { nullifier_root: Some(header.nullifier_root().into()), note_root: Some(header.note_root().into()), tx_commitment: Some(header.tx_commitment().into()), - validator_keys: header - .validator_keys() - .as_keys() - .iter() - .map(|key| proto::blockchain::ValidatorPublicKey { validator_key: key.to_bytes() }) - .collect(), - tx_kernel_commitment: Some(header.tx_kernel_commitment().into()), + validator_config: Some(proto::blockchain::ValidatorConfig { + keys: header + .validator_config() + .keys() + .iter() + .map(|key| proto::blockchain::ValidatorPublicKey { + validator_key: key.to_bytes(), + }) + .collect(), + quorum: header.validator_config().quorum().into(), + }), + protocol_config_commitment: Some(header.protocol_config_commitment().into()), + next_protocol_config: header.next_protocol_config().map(|config| { + proto::blockchain::NextProtocolConfig { + effective_from: config.effective_from().as_u32(), + protocol_config: Some(config.protocol_config().into()), + } + }), fee_parameters: Some(header.fee_parameters().into()), timestamp: header.timestamp(), } @@ -39,7 +51,6 @@ impl From<&BlockHeader> for proto::blockchain::BlockHeader { impl From<&FeeParameters> for proto::blockchain::FeeParameters { fn from(fee_params: &FeeParameters) -> Self { Self { - native_asset_id: Some(fee_params.fee_faucet_id().into()), verification_base_fee: fee_params.verification_base_fee(), } } @@ -61,16 +72,36 @@ impl TryFrom for BlockHeader { type Error = RpcConversionError; fn try_from(value: proto::blockchain::BlockHeader) -> Result { - let validator_keys = value - .validator_keys + // Upstream builds only version 1 and keeps its constant private. + if value.version != 1 { + return Err(RpcConversionError::InvalidField(format!( + "unsupported block header version {}", + value.version + ))); + } + let config = value + .validator_config + .ok_or(proto::blockchain::BlockHeader::missing_field("validator_config"))?; + let keys = config + .keys .into_iter() .map(|key| ecdsa_k256_keccak::PublicKey::read_from_bytes(&key.validator_key)) .collect::, _>>()?; - let validator_keys = ValidatorKeys::new(validator_keys) + let validator_config = ValidatorConfig::new(keys, config.quorum.try_into()?) .map_err(|err| RpcConversionError::InvalidField(err.to_string()))?; + let next_protocol_config = value + .next_protocol_config + .map(|config| { + let commitment = config + .protocol_config + .ok_or(proto::blockchain::NextProtocolConfig::missing_field("protocol_config"))? + .try_into()?; + NextProtocolConfig::new(config.effective_from.into(), commitment) + .map_err(|err| RpcConversionError::InvalidField(err.to_string())) + }) + .transpose()?; Ok(BlockHeader::new( - value.version, value .prev_block_commitment .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!( @@ -98,17 +129,16 @@ impl TryFrom for BlockHeader { .tx_commitment .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(tx_commitment)))? .try_into()?, - value - .tx_kernel_commitment - .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!( - tx_kernel_commitment - )))? - .try_into()?, - validator_keys, + validator_config, value .fee_parameters .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(fee_parameters)))? .try_into()?, + value + .protocol_config_commitment + .ok_or(proto::blockchain::BlockHeader::missing_field("protocol_config_commitment"))? + .try_into()?, + next_protocol_config, value.timestamp, )) } @@ -118,13 +148,7 @@ impl TryFrom<&proto::blockchain::FeeParameters> for FeeParameters { type Error = RpcConversionError; fn try_from(value: &proto::blockchain::FeeParameters) -> Result { - let account_id = value - .native_asset_id - .clone() - .ok_or(proto::blockchain::FeeParameters::missing_field("account_id"))? - .try_into()?; - - Ok(FeeParameters::new(account_id, value.verification_base_fee)) + Ok(FeeParameters::new(value.verification_base_fee)) } } @@ -144,3 +168,58 @@ impl From for proto::blockchain::BlockNumber { Self { block_num: value.as_u32() } } } + +#[cfg(test)] +mod tests { + use miden_protocol::Word; + + use super::*; + + #[test] + fn block_header_round_trip_preserves_protocol_upgrade_and_quorum() { + let header = BlockHeader::mock(5, None, None, &[]); + let mut wire: proto::blockchain::BlockHeader = (&header).into(); + let (_, validators) = ValidatorConfig::random_with_signers(3); + wire.validator_config = Some(proto::blockchain::ValidatorConfig { + keys: validators + .keys() + .iter() + .map(|key| proto::blockchain::ValidatorPublicKey { validator_key: key.to_bytes() }) + .collect(), + quorum: validators.quorum().into(), + }); + wire.next_protocol_config = Some(proto::blockchain::NextProtocolConfig { + effective_from: 10, + protocol_config: Some(Word::from([1u32, 2, 3, 4]).into()), + }); + let decoded = BlockHeader::try_from(wire.clone()).unwrap(); + assert_eq!(proto::blockchain::BlockHeader::from(&decoded), wire); + assert_eq!(decoded.validator_config().keys(), validators.keys()); + assert_eq!(decoded.validator_config().quorum(), validators.quorum()); + assert_ne!(decoded.commitment(), header.commitment()); + } + + #[test] + fn block_header_rejects_malformed_wire_fields() { + let header = BlockHeader::mock(5, None, None, &[]); + let wire: proto::blockchain::BlockHeader = (&header).into(); + + // A version the client does not support. + let mut malformed = wire.clone(); + malformed.version = 256; + assert!(BlockHeader::try_from(malformed).is_err()); + + // A quorum that does not match the validator count. + let mut malformed = wire.clone(); + malformed.validator_config.as_mut().unwrap().quorum = 0; + assert!(BlockHeader::try_from(malformed).is_err()); + + // An upgrade scheduled at the genesis height. + let mut malformed = wire; + malformed.next_protocol_config = Some(proto::blockchain::NextProtocolConfig { + effective_from: 0, + protocol_config: Some(Word::empty().into()), + }); + assert!(BlockHeader::try_from(malformed).is_err()); + } +} diff --git a/crates/rust-client/src/rpc/domain/note.rs b/crates/rust-client/src/rpc/domain/note.rs index fb53e0faa6..86b467d052 100644 --- a/crates/rust-client/src/rpc/domain/note.rs +++ b/crates/rust-client/src/rpc/domain/note.rs @@ -693,7 +693,7 @@ impl TryFrom for NoteScript { fn try_from(note_script: proto::note::NoteScript) -> Result { let mast_forest = MastForest::read_from_bytes(¬e_script.mast)?; let entrypoint = MastNodeId::from_u32_safe(note_script.entrypoint, &mast_forest)?; - Ok(NoteScript::from_parts(alloc::sync::Arc::new(mast_forest), entrypoint)) + Ok(NoteScript::from_parts(alloc::sync::Arc::new(mast_forest), entrypoint)?) } } diff --git a/crates/rust-client/src/rpc/domain/smt.rs b/crates/rust-client/src/rpc/domain/smt.rs index 6e7c2df0d6..d5102fc9a5 100644 --- a/crates/rust-client/src/rpc/domain/smt.rs +++ b/crates/rust-client/src/rpc/domain/smt.rs @@ -1,4 +1,4 @@ -use alloc::collections::BTreeSet; +use alloc::collections::{BTreeMap, BTreeSet}; use alloc::string::ToString; use alloc::vec::Vec; @@ -6,7 +6,6 @@ use miden_protocol::Word; use miden_protocol::crypto::merkle::NodeIndex; use miden_protocol::crypto::merkle::smt::{ LeafIndex, - NodeValue, PartialSmt, SMT_DEPTH, SmtLeaf, @@ -125,62 +124,31 @@ impl TryFrom for UniqueNodes { /// rather than left to it, so a malformed response is reported as a specific invalid field /// instead of an opaque reconstruction failure. fn try_from(value: proto::primitives::PartialSmt) -> Result { - use proto::primitives::partial_smt_node::Value; - - let proto::primitives::PartialSmt { - root, - node_levels, - leaves, - value_only_leaves, - } = value; + let proto::primitives::PartialSmt { root, nodes, leaves, value_only_leaves } = value; let root: Word = root .ok_or(proto::primitives::PartialSmt::missing_field(stringify!(root)))? .try_into()?; - let mut seen_depths = BTreeSet::new(); - let mut decoded_levels = Vec::with_capacity(node_levels.len()); - for level in node_levels { - let depth = u8::try_from(level.depth)?; - // Depth 0 is the root, which is carried separately, and `SMT_DEPTH` is the leaf level. - // Only the strictly intermediate depths are boundary nodes. + let mut decoded_nodes = BTreeMap::new(); + for node in nodes { + let depth = u8::try_from(node.depth)?; if depth == 0 || depth >= SMT_DEPTH { return Err(RpcConversionError::InvalidField(format!( "partial SMT node depth {depth} must be in the range 1..{SMT_DEPTH}" ))); } - if !seen_depths.insert(depth) { + let index = NodeIndex::new(depth, node.position)?; + let value = node + .value + .ok_or(proto::primitives::PartialSmtNode::missing_field("value"))? + .try_into()?; + if decoded_nodes.insert(index, value).is_some() { return Err(RpcConversionError::InvalidField(format!( - "partial SMT contains duplicate node depth {depth}" + "partial SMT contains duplicate node index {} at depth {depth}", + node.position ))); } - - let mut seen_indices = BTreeSet::new(); - let mut decoded_nodes = Vec::with_capacity(level.nodes.len()); - for node in level.nodes { - NodeIndex::new(depth, node.index)?; - if !seen_indices.insert(node.index) { - return Err(RpcConversionError::InvalidField(format!( - "partial SMT contains duplicate node index {} at depth {depth}", - node.index - ))); - } - - let node_value = match node - .value - .ok_or(proto::primitives::PartialSmtNode::missing_field(stringify!(value)))? - { - Value::Digest(digest) => NodeValue::Present(digest.try_into()?), - Value::EmptySubtreeRoot(true) => NodeValue::EmptySubtreeRoot, - Value::EmptySubtreeRoot(false) => { - return Err(RpcConversionError::InvalidField( - "partial SMT empty_subtree_root marker must be true".into(), - )); - }, - }; - decoded_nodes.push((node.index, node_value)); - } - decoded_levels.push((depth, decoded_nodes)); } let mut seen_leaf_indices = BTreeSet::new(); @@ -224,9 +192,9 @@ impl TryFrom for UniqueNodes { Ok(UniqueNodes { root, - nodes: decoded_levels.into_iter().collect(), - leaves: decoded_leaves, - value_only_leaves: decoded_value_only_leaves, + nodes: decoded_nodes, + leaves: decoded_leaves.into_iter().collect(), + value_only_leaves: decoded_value_only_leaves.into_iter().collect(), }) } } diff --git a/crates/rust-client/src/rpc/domain/transaction.rs b/crates/rust-client/src/rpc/domain/transaction.rs index 0ae985886a..8f212d828f 100644 --- a/crates/rust-client/src/rpc/domain/transaction.rs +++ b/crates/rust-client/src/rpc/domain/transaction.rs @@ -225,6 +225,7 @@ fn convert_transaction_header( final_state_commitment.try_into()?, input_notes, output_note_headers, - ); + ) + .map_err(|err| RpcError::InvalidResponse(err.to_string()))?; Ok((transaction_header, committed_output_notes, erased_output_notes)) } diff --git a/crates/rust-client/src/rpc/encryption.rs b/crates/rust-client/src/rpc/encryption.rs index 0b8bc88b32..b24faaab6f 100644 --- a/crates/rust-client/src/rpc/encryption.rs +++ b/crates/rust-client/src/rpc/encryption.rs @@ -33,7 +33,7 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; -use miden_protocol::block::{BlockNumber, ValidatorKeys}; +use miden_protocol::block::{BlockNumber, ValidatorConfig}; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{ PublicKey as ValidatorPublicKey, Signature as ValidatorSignature, @@ -246,7 +246,7 @@ impl AttestedTransactionEncryptionKey { pub fn verify( self, genesis_commitment: Word, - validator_keys: &ValidatorKeys, + validator_keys: &ValidatorConfig, ) -> Result { validate_key_metadata(self.scheme, self.key_id.len()) .map_err(RpcError::TransactionEncryptionKeyRejected)?; @@ -263,7 +263,7 @@ impl AttestedTransactionEncryptionKey { self.next_key.as_ref(), ); - let recognized = validator_keys.as_keys(); + let recognized = validator_keys.keys(); let attested = self.attestations.iter().any(|attestation| { recognized.contains(&attestation.validator_key) && attestation.validator_key.verify(commitment, &attestation.signature) @@ -698,7 +698,7 @@ mod tests { fn verify_accepts_an_attestation_from_a_recognized_validator() { let (key, _) = key_pair(); let signer = ValidatorSigningKey::with_rng(&mut rng()); - let validator_keys = ValidatorKeys::new(vec![signer.public_key()]).unwrap(); + let validator_keys = ValidatorConfig::new(vec![signer.public_key()], 1).unwrap(); let verified = attested(&key, &signer, genesis()).verify(genesis(), &validator_keys).unwrap(); @@ -711,7 +711,7 @@ mod tests { let (key, _) = key_pair(); let impostor = ValidatorSigningKey::with_rng(&mut rng()); let committed = ValidatorSigningKey::with_rng(&mut ChaCha20Rng::seed_from_u64(7)); - let validator_keys = ValidatorKeys::new(vec![committed.public_key()]).unwrap(); + let validator_keys = ValidatorConfig::new(vec![committed.public_key()], 1).unwrap(); assert!(attested(&key, &impostor, genesis()).verify(genesis(), &validator_keys).is_err()); } @@ -722,7 +722,7 @@ mod tests { fn verify_rejects_a_substituted_public_key() { let (key, _) = key_pair(); let signer = ValidatorSigningKey::with_rng(&mut rng()); - let validator_keys = ValidatorKeys::new(vec![signer.public_key()]).unwrap(); + let validator_keys = ValidatorConfig::new(vec![signer.public_key()], 1).unwrap(); let substitute = KeyExchangeKey::with_rng(&mut ChaCha20Rng::seed_from_u64(99)); let mut response = attested(&key, &signer, genesis()); @@ -737,7 +737,7 @@ mod tests { fn verify_rejects_an_attestation_from_another_network() { let (key, _) = key_pair(); let signer = ValidatorSigningKey::with_rng(&mut rng()); - let validator_keys = ValidatorKeys::new(vec![signer.public_key()]).unwrap(); + let validator_keys = ValidatorConfig::new(vec![signer.public_key()], 1).unwrap(); let response = attested(&key, &signer, genesis()); @@ -750,7 +750,7 @@ mod tests { fn verify_rejects_an_injected_next_key() { let (key, _) = key_pair(); let signer = ValidatorSigningKey::with_rng(&mut rng()); - let validator_keys = ValidatorKeys::new(vec![signer.public_key()]).unwrap(); + let validator_keys = ValidatorConfig::new(vec![signer.public_key()], 1).unwrap(); let mut response = attested(&key, &signer, genesis()); response.next_key = Some(NextTransactionEncryptionKey { @@ -769,7 +769,7 @@ mod tests { fn verify_rejects_an_unsupported_scheme() { let (key, _) = key_pair(); let signer = ValidatorSigningKey::with_rng(&mut rng()); - let validator_keys = ValidatorKeys::new(vec![signer.public_key()]).unwrap(); + let validator_keys = ValidatorConfig::new(vec![signer.public_key()], 1).unwrap(); let mut response = attested(&key, &signer, genesis()); response.scheme = SUPPORTED_SCHEME + 1; diff --git a/crates/rust-client/src/rpc/mod.rs b/crates/rust-client/src/rpc/mod.rs index a43cb3b6db..723dd3bc78 100644 --- a/crates/rust-client/src/rpc/mod.rs +++ b/crates/rust-client/src/rpc/mod.rs @@ -66,7 +66,7 @@ use miden_protocol::Word; use miden_protocol::account::{Account, AccountId}; use miden_protocol::address::NetworkId; use miden_protocol::batch::{ProposedBatch, ProvenBatch}; -use miden_protocol::block::{BlockHeader, BlockNumber, ProvenBlock}; +use miden_protocol::block::{BlockHeader, BlockNumber, SignedBlock}; use miden_protocol::crypto::merkle::mmr::MmrProof; use miden_protocol::note::{ NoteAttachments, @@ -210,7 +210,7 @@ pub trait NodeRpcClient: Send + Sync { &self, block_num: BlockNumber, include_proof: bool, - ) -> Result; + ) -> Result; /// Fetches note-related data for a list of [`NoteId`] using the `/GetNotesById` RPC endpoint. /// diff --git a/crates/rust-client/src/rpc/tonic_client/mod.rs b/crates/rust-client/src/rpc/tonic_client/mod.rs index afd03dca6c..60f6922788 100644 --- a/crates/rust-client/src/rpc/tonic_client/mod.rs +++ b/crates/rust-client/src/rpc/tonic_client/mod.rs @@ -20,7 +20,7 @@ use miden_protocol::account::{ use miden_protocol::address::NetworkId; use miden_protocol::batch::{ProposedBatch, ProvenBatch}; use miden_protocol::block::account_tree::AccountWitness; -use miden_protocol::block::{BlockHeader, BlockNumber, ProvenBlock}; +use miden_protocol::block::{BlockHeader, BlockNumber, SignedBlock}; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{ PublicKey as ValidatorPublicKey, Signature as ValidatorSignature, @@ -800,7 +800,7 @@ impl NodeRpcClient for GrpcClient { &self, block_num: BlockNumber, include_proof: bool, - ) -> Result { + ) -> Result { let request = proto::blockchain::BlockRequest { block_num: block_num.as_u32(), include_proof: Some(include_proof), @@ -813,8 +813,10 @@ impl NodeRpcClient for GrpcClient { .await?; let response = response.into_inner(); + // The response carries the signed block and its proof in separate fields, so the block + // bytes decode as a `SignedBlock` and never as a `ProvenBlock`. let block = - ProvenBlock::read_from_bytes(&response.block.ok_or(RpcError::ExpectedDataMissing( + SignedBlock::read_from_bytes(&response.block.ok_or(RpcError::ExpectedDataMissing( "GetBlockByNumberResponse.block".to_string(), ))?)?; diff --git a/crates/rust-client/src/rpc/verifying_client/mod.rs b/crates/rust-client/src/rpc/verifying_client/mod.rs index db68d3e675..465437e3d3 100644 --- a/crates/rust-client/src/rpc/verifying_client/mod.rs +++ b/crates/rust-client/src/rpc/verifying_client/mod.rs @@ -7,7 +7,7 @@ use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::address::NetworkId; use miden_protocol::batch::{ProposedBatch, ProvenBatch}; -use miden_protocol::block::{BlockHeader, BlockNumber, ProvenBlock}; +use miden_protocol::block::{BlockHeader, BlockNumber, SignedBlock}; use miden_protocol::crypto::merkle::mmr::MmrProof; use miden_protocol::note::{NoteId, NoteScript, NoteTag}; use miden_protocol::transaction::ProvenTransaction; @@ -214,7 +214,7 @@ impl NodeRpcClient for VerifyingRpcClient { &self, block_num: BlockNumber, include_proof: bool, - ) -> Result { + ) -> Result { let block = self.0.get_block_by_number(block_num, include_proof).await?; verify_block_num(Some(block_num), block.header().block_num())?; Ok(block) diff --git a/crates/rust-client/src/rpc/verifying_client/tests.rs b/crates/rust-client/src/rpc/verifying_client/tests.rs index c892ed39e4..ec83b1c55b 100644 --- a/crates/rust-client/src/rpc/verifying_client/tests.rs +++ b/crates/rust-client/src/rpc/verifying_client/tests.rs @@ -7,14 +7,7 @@ use miden_protocol::account::AccountId; use miden_protocol::address::NetworkId; use miden_protocol::batch::{ProposedBatch, ProvenBatch}; use miden_protocol::block::account_tree::AccountWitness; -use miden_protocol::block::{ - BlockBody, - BlockHeader, - BlockNumber, - BlockProof, - BlockSignatures, - ProvenBlock, -}; +use miden_protocol::block::{BlockBody, BlockHeader, BlockNumber, BlockSignatures, SignedBlock}; use miden_protocol::crypto::merkle::mmr::MmrProof; use miden_protocol::crypto::merkle::{MerklePath, SparseMerklePath}; use miden_protocol::note::{ @@ -37,7 +30,6 @@ use miden_protocol::transaction::{ OrderedTransactionHeaders, ProvenTransaction, TransactionHeader, - TransactionKernel, }; use miden_protocol::{Felt, Word}; use miden_standards::note::StandardNote; @@ -88,10 +80,10 @@ fn nullifier_update(prefix: u16, block_num: u32) -> NullifierUpdate { } fn block_header(block_num: u32) -> BlockHeader { - BlockHeader::mock(block_num, None, None, &[], TransactionKernel.to_commitment()) + BlockHeader::mock(block_num, None, None, &[]) } -fn proven_block(block_num: u32) -> ProvenBlock { +fn signed_block(block_num: u32) -> SignedBlock { let body = BlockBody::new_unchecked( Vec::new(), Vec::new(), @@ -100,7 +92,7 @@ fn proven_block(block_num: u32) -> ProvenBlock { ); let signatures = BlockSignatures::new(Vec::new()).expect("no signatures is a valid set"); - ProvenBlock::new_unchecked(block_header(block_num), body, signatures, BlockProof::new_dummy()) + SignedBlock::new_unchecked(block_header(block_num), body, signatures) } fn inclusion_proof() -> NoteInclusionProof { @@ -155,7 +147,8 @@ fn transaction_record(account_id: AccountId) -> TransactionRecord { Word::default(), InputNotes::new_unchecked(vec![]), vec![], - ), + ) + .unwrap(), output_notes: vec![], erased_output_notes: vec![], consumed_note_refs: vec![], @@ -192,7 +185,7 @@ enum CannedScript { #[derive(Default)] struct CannedTransport { block_header: Option<(BlockHeader, Option)>, - block: Option, + block: Option, /// Note IDs to report from `get_notes_by_id`, wrapped into notes on each call because /// [`FetchedNote`] is not [`Clone`]. note_ids: Option>, @@ -270,7 +263,7 @@ impl NodeRpcClient for CannedTransport { &self, _block_num: BlockNumber, _include_proof: bool, - ) -> Result { + ) -> Result { self.canned(self.block.as_ref(), "test must set a canned get_block_by_number response") } @@ -413,7 +406,7 @@ async fn get_block_header_by_number_verifies_block_num() { #[tokio::test] async fn get_block_by_number_verifies_block_num() { let client = VerifyingRpcClient::new(CannedTransport { - block: Some(proven_block(5)), + block: Some(signed_block(5)), ..Default::default() }); diff --git a/crates/rust-client/src/store/data_store/mod.rs b/crates/rust-client/src/store/data_store/mod.rs index e7a6e6b0d6..8ac8015305 100644 --- a/crates/rust-client/src/store/data_store/mod.rs +++ b/crates/rust-client/src/store/data_store/mod.rs @@ -19,6 +19,7 @@ use miden_protocol::block::{BlockHeader, BlockNumber}; use miden_protocol::crypto::merkle::MerklePath; use miden_protocol::crypto::merkle::mmr::{InOrderIndex, MmrPeaks, PartialMmr}; use miden_protocol::note::{NoteScript, NoteScriptRoot}; +use miden_protocol::protocol_config::ProtocolConfig; use miden_protocol::transaction::{AccountInputs, PartialBlockchain}; use miden_protocol::vm::FutureMaybeSend; use miden_protocol::{Word, ZERO}; @@ -318,7 +319,8 @@ impl DataStore for ClientDataStore { &self, account_id: AccountId, mut block_refs: BTreeSet, - ) -> Result<(PartialAccount, BlockHeader, PartialBlockchain), DataStoreError> { + ) -> Result<(PartialAccount, BlockHeader, ProtocolConfig, PartialBlockchain), DataStoreError> + { // Last block is used as reference (it does not need to be authenticated manually) let ref_block = *block_refs.last().ok_or(DataStoreError::other("block set is empty"))?; @@ -427,7 +429,12 @@ impl DataStore for ClientDataStore { (block_header, partial_blockchain) }; - Ok((partial_account, block_header, partial_blockchain)) + let protocol_config = crate::protocol_config::load_protocol_config( + self.store.as_ref(), + block_header.protocol_config_commitment(), + ) + .await?; + Ok((partial_account, block_header, protocol_config, partial_blockchain)) } /// Retrieves witnesses for the requested assets from the local store, falling back to a single diff --git a/crates/rust-client/src/store/errors.rs b/crates/rust-client/src/store/errors.rs index a19912191b..6ab0a68b30 100644 --- a/crates/rust-client/src/store/errors.rs +++ b/crates/rust-client/src/store/errors.rs @@ -17,11 +17,10 @@ use miden_protocol::errors::{ AssetVaultError, NoteError, StorageMapError, - TransactionScriptError, }; use miden_protocol::utils::HexParseError; use miden_protocol::utils::serde::DeserializationError; -use miden_protocol::{Word, WordError}; +use miden_protocol::{MastForestScriptError, Word, WordError}; use miden_tx::DataStoreError; use thiserror::Error; @@ -34,6 +33,12 @@ use super::note_record::NoteRecordError; #[derive(Debug, Error)] #[allow(clippy::large_enum_variant)] pub enum StoreError { + #[error( + "protocol configuration {0} is not stored; register it with Client::add_protocol_config" + )] + ProtocolConfigNotFound(Word), + #[error("stored protocol configuration does not match commitment {0}")] + ProtocolConfigCommitmentMismatch(Word), #[error("asset error")] AssetError(#[from] AssetError), #[error("asset vault error")] @@ -90,8 +95,8 @@ pub enum StoreError { SmtProofError(#[from] SmtProofError), #[error("account storage map error")] StorageMapError(#[from] StorageMapError), - #[error("failed to instantiate transaction script")] - TransactionScriptError(#[from] TransactionScriptError), + #[error("failed to instantiate a script from its mast forest")] + MastForestScriptError(#[from] MastForestScriptError), #[error("account vault data for root {0} not found")] VaultDataNotFound(Word), #[error("vault key {0:?} (hashed to {1}) is not tracked in the vault")] diff --git a/crates/rust-client/src/store/note_record/input_note_record/states/unverified.rs b/crates/rust-client/src/store/note_record/input_note_record/states/unverified.rs index c63c7fb649..0e4e7bbc29 100644 --- a/crates/rust-client/src/store/note_record/input_note_record/states/unverified.rs +++ b/crates/rust-client/src/store/note_record/input_note_record/states/unverified.rs @@ -171,7 +171,6 @@ mod tests { use miden_protocol::account::{AccountIdVersion, AccountType, AssetCallbackFlag}; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{NoteAttachments, NoteTag, NoteType, PartialNoteMetadata}; - use miden_protocol::transaction::TransactionKernel; use super::*; @@ -202,7 +201,7 @@ mod tests { /// A header for `block_num` whose note root is `note_root`, so the same root can be placed in /// more than one block. fn header(block_num: u32, note_root: Word) -> BlockHeader { - BlockHeader::mock(block_num, None, Some(note_root), &[], TransactionKernel.to_commitment()) + BlockHeader::mock(block_num, None, Some(note_root), &[]) } #[test] diff --git a/crates/rust-client/src/store/smt_forest.rs b/crates/rust-client/src/store/smt_forest.rs index 1e9f5cb4e0..9e8091be10 100644 --- a/crates/rust-client/src/store/smt_forest.rs +++ b/crates/rust-client/src/store/smt_forest.rs @@ -229,7 +229,7 @@ impl AccountSmtForest { return Err(StoreError::VaultKeyNotTracked(asset_id, hashed_key)); } - let asset = Asset::from_id_and_value(asset_id, asset_word)?; + let asset = Asset::new(asset_id, asset_word)?; let witness = AssetWitness::new(proof, [asset_id])?; Ok((asset, witness)) } diff --git a/crates/rust-client/src/sync/block_header.rs b/crates/rust-client/src/sync/block_header.rs index 67498aabcb..07d5072211 100644 --- a/crates/rust-client/src/sync/block_header.rs +++ b/crates/rust-client/src/sync/block_header.rs @@ -74,7 +74,9 @@ impl Client { return Ok(()); } - *self.test_rpc_api() = Arc::new(MockRpcApi::default()); + let rpc = MockRpcApi::default(); + self.add_protocol_config(rpc.protocol_config()).await?; + *self.test_rpc_api() = Arc::new(rpc); self.ensure_genesis_in_place().await?; Ok(()) } @@ -247,7 +249,6 @@ mod tests { use miden_protocol::block::{BlockHeader, BlockNumber}; use miden_protocol::crypto::merkle::MerklePath; use miden_protocol::crypto::merkle::mmr::{Forest, InOrderIndex, Mmr, PartialMmr}; - use miden_protocol::transaction::TransactionKernel; use miden_protocol::{Felt, Word}; use super::{adjust_merkle_path_for_forest, authenticated_block_nodes}; @@ -378,7 +379,7 @@ mod tests { #[test] fn authenticated_block_nodes_include_leaf_commitment() { - let block_header = BlockHeader::mock(4, None, None, &[], TransactionKernel.to_commitment()); + let block_header = BlockHeader::mock(4, None, None, &[]); let path_nodes = vec![ (InOrderIndex::from_leaf_pos(4).sibling(), word(10)), (InOrderIndex::from_leaf_pos(4).parent().sibling(), word(11)), diff --git a/crates/rust-client/src/sync/state_sync.rs b/crates/rust-client/src/sync/state_sync.rs index 1f61d8fb45..731bfe608f 100644 --- a/crates/rust-client/src/sync/state_sync.rs +++ b/crates/rust-client/src/sync/state_sync.rs @@ -1502,7 +1502,6 @@ mod tests { fn header_with_account_root(header: &BlockHeader, account_root: Word) -> BlockHeader { BlockHeader::new( - header.version(), header.prev_block_commitment(), header.block_num(), header.chain_commitment(), @@ -1510,9 +1509,10 @@ mod tests { header.nullifier_root(), header.note_root(), header.tx_commitment(), - header.tx_kernel_commitment(), - header.validator_keys().clone(), + header.validator_config().clone(), header.fee_parameters().clone(), + header.protocol_config_commitment(), + header.next_protocol_config().cloned(), header.timestamp(), ) } @@ -1688,7 +1688,6 @@ mod tests { // Same block number so the request resolves, but a tampered account root the witness cannot // verify against. let tampered_header = BlockHeader::new( - real_header.version(), real_header.prev_block_commitment(), real_header.block_num(), real_header.chain_commitment(), @@ -1696,9 +1695,10 @@ mod tests { real_header.nullifier_root(), real_header.note_root(), real_header.tx_commitment(), - real_header.tx_kernel_commitment(), - real_header.validator_keys().clone(), + real_header.validator_config().clone(), real_header.fee_parameters().clone(), + real_header.protocol_config_commitment(), + real_header.next_protocol_config().cloned(), real_header.timestamp(), ); @@ -1884,7 +1884,8 @@ mod tests { word(final_state), input_notes, vec![], - ), + ) + .unwrap(), output_notes: vec![], erased_output_notes: vec![], consumed_note_refs: vec![], @@ -1932,7 +1933,8 @@ mod tests { Nullifier::from_raw(word(40)), )]), vec![], - ), + ) + .unwrap(), output_notes: vec![], erased_output_notes: vec![], consumed_note_refs: vec![], @@ -1994,7 +1996,8 @@ mod tests { word(final_state), InputNotes::new_unchecked(vec![]), vec![], - ), + ) + .unwrap(), output_notes: vec![], erased_output_notes: vec![], consumed_note_refs: vec![], @@ -2057,7 +2060,7 @@ mod tests { let account = builder.add_existing_mock_account(miden_testing::Auth::IncrNonce).unwrap(); let account_id = account.id(); - let asset = Asset::Fungible(FungibleAsset::new(faucet_id, 100u64).unwrap()); + let asset = Asset::from(FungibleAsset::new(faucet_id, 100u64).unwrap()); let note1 = builder .add_p2id_note(sender_id, account_id, &[asset], NoteType::Public) .unwrap(); @@ -2118,7 +2121,7 @@ mod tests { let account_id = account.id(); let sync_input = StateSyncInput { - accounts: vec![AccountHeader::from(account)], + accounts: vec![AccountHeader::from(&account)], note_tags, input_notes, output_notes: vec![], @@ -2511,7 +2514,7 @@ mod tests { builder.add_existing_mock_account(miden_testing::Auth::IncrNonce).unwrap(); let sender_id = sender_account.id(); - let asset = Asset::Fungible(FungibleAsset::new(faucet_id, 100u64).unwrap()); + let asset = Asset::from(FungibleAsset::new(faucet_id, 100u64).unwrap()); let note = builder .add_p2id_note(p2id_sender, sender_id, &[asset], NoteType::Public) .unwrap(); @@ -2580,7 +2583,7 @@ mod tests { let mut partial_mmr = PartialMmr::from_peaks(genesis_peaks); let sync_input = StateSyncInput { - accounts: vec![AccountHeader::from(sender_account), network_header], + accounts: vec![AccountHeader::from(&sender_account), network_header], note_tags: BTreeSet::new(), input_notes: vec![], output_notes: vec![output_note], @@ -2735,7 +2738,8 @@ mod tests { word(2), InputNotes::new_unchecked(vec![]), vec![], - ), + ) + .unwrap(), output_notes: vec![], erased_output_notes: vec![], consumed_note_refs: vec![], diff --git a/crates/rust-client/src/test_utils/mock.rs b/crates/rust-client/src/test_utils/mock.rs index e25fc64273..5a1fe64c7f 100644 --- a/crates/rust-client/src/test_utils/mock.rs +++ b/crates/rust-client/src/test_utils/mock.rs @@ -18,11 +18,12 @@ use miden_protocol::account::{ }; use miden_protocol::address::NetworkId; use miden_protocol::batch::{ProposedBatch, ProvenBatch}; -use miden_protocol::block::{BlockHeader, BlockNumber, ProvenBlock}; +use miden_protocol::block::{BlockHeader, BlockNumber, SignedBlock}; use miden_protocol::crypto::merkle::MerklePath; use miden_protocol::crypto::merkle::mmr::{Forest, Mmr, MmrProof}; use miden_protocol::crypto::merkle::smt::PartialSmt; use miden_protocol::note::{NoteAttachments, NoteHeader, NoteId, NoteScript, NoteTag}; +use miden_protocol::protocol_config::ProtocolConfig; use miden_protocol::transaction::{OutputNote, ProvenTransaction}; use miden_testing::{MockChain, MockChainNote}; use miden_tx::utils::sync::RwLock; @@ -160,6 +161,11 @@ impl MockRpcApi { self.mock_chain.read().blockchain().as_mmr().clone() } + /// Returns the protocol configuration the mock chain commits to. + pub fn protocol_config(&self) -> ProtocolConfig { + self.mock_chain.read().protocol_config().clone() + } + /// Returns the chain tip block number. pub fn get_chain_tip_block_num(&self) -> BlockNumber { self.mock_chain.read().latest_block_header().block_num() @@ -724,7 +730,7 @@ impl NodeRpcClient for MockRpcApi { &self, block_num: BlockNumber, _include_proof: bool, - ) -> Result { + ) -> Result { let block = self .mock_chain .read() @@ -733,8 +739,9 @@ impl NodeRpcClient for MockRpcApi { .find(|b| b.header().block_num() == block_num) .unwrap() .clone(); + let (header, body, signatures, _proof) = block.into_parts(); - Ok(block) + Ok(SignedBlock::new_unchecked(header, body, signatures)) } async fn get_note_script_by_root(&self, root: Word) -> Result, RpcError> { diff --git a/crates/rust-client/src/transaction/batch/data_store.rs b/crates/rust-client/src/transaction/batch/data_store.rs index 292f023b57..060c349090 100644 --- a/crates/rust-client/src/transaction/batch/data_store.rs +++ b/crates/rust-client/src/transaction/batch/data_store.rs @@ -22,6 +22,7 @@ use miden_protocol::asset::{AssetId, AssetWitness, PartialVault}; use miden_protocol::block::{BlockHeader, BlockNumber}; use miden_protocol::crypto::merkle::smt::{PartialSmt, SmtProof}; use miden_protocol::note::{NoteScript, NoteScriptRoot}; +use miden_protocol::protocol_config::ProtocolConfig; use miden_protocol::transaction::{AccountInputs, ExecutedTransaction, PartialBlockchain}; use miden_protocol::vm::FutureMaybeSend; use miden_protocol::{EMPTY_WORD, Word, ZERO}; @@ -352,15 +353,16 @@ impl DataStore for InMemoryBatchDataStore { &self, account_id: AccountId, ref_blocks: BTreeSet, - ) -> Result<(PartialAccount, BlockHeader, PartialBlockchain), DataStoreError> { - let (mut partial_account, block_header, partial_blockchain) = + ) -> Result<(PartialAccount, BlockHeader, ProtocolConfig, PartialBlockchain), DataStoreError> + { + let (mut partial_account, block_header, protocol_config, partial_blockchain) = self.inner.get_transaction_inputs(account_id, ref_blocks).await?; if let Some(state) = self.current_accounts.get(&account_id) { partial_account = state.account.clone(); } - Ok((partial_account, block_header, partial_blockchain)) + Ok((partial_account, block_header, protocol_config, partial_blockchain)) } async fn get_vault_asset_witnesses( diff --git a/crates/rust-client/src/transaction/batch/mod.rs b/crates/rust-client/src/transaction/batch/mod.rs index 432279062d..f2780a0845 100644 --- a/crates/rust-client/src/transaction/batch/mod.rs +++ b/crates/rust-client/src/transaction/batch/mod.rs @@ -190,7 +190,8 @@ where // 6. Execute the batch kernel, then prove synchronously. let executed_batch = BatchExecutor::new().execute(proposed_batch.clone())?; - let proven_batch = LocalBatchProver::new().prove(executed_batch)?; + let proven_batch = + LocalBatchProver::new(miden_tx::Prover::default()).prove(executed_batch)?; // 7. Seal each transaction's inputs, then submit via RPC. Each entry is sealed against its // own transaction id. diff --git a/crates/rust-client/src/transaction/chain_anchor.rs b/crates/rust-client/src/transaction/chain_anchor.rs index 45bec482a4..f79935c35e 100644 --- a/crates/rust-client/src/transaction/chain_anchor.rs +++ b/crates/rust-client/src/transaction/chain_anchor.rs @@ -205,7 +205,6 @@ pub enum ChainAnchorError { mod tests { use alloc::vec::Vec; - use miden_protocol::Word; use miden_protocol::block::BlockHeader; use miden_protocol::crypto::merkle::mmr::{Mmr, PartialMmr}; use miden_protocol::transaction::PartialBlockchain; @@ -219,13 +218,7 @@ mod tests { let mut mmr = Mmr::default(); let mut headers = Vec::with_capacity(chain_length); for block_num in 0..chain_length { - let header = BlockHeader::mock( - u32::try_from(block_num).unwrap(), - None, - None, - &[], - Word::empty(), - ); + let header = BlockHeader::mock(u32::try_from(block_num).unwrap(), None, None, &[]); mmr.add(header.commitment()).unwrap(); headers.push(header); } @@ -246,7 +239,6 @@ mod tests { Some(peaks.hash_peaks()), None, &[], - Word::empty(), ); (header, chain) @@ -266,8 +258,7 @@ mod tests { fn new_rejects_a_chain_length_that_does_not_match_the_header() { let (_, chain) = anchor_parts(8, &[3]); // Commit to the right chain, so the block number is the only defect. - let header = - BlockHeader::mock(9, Some(chain.peaks().hash_peaks()), None, &[], Word::empty()); + let header = BlockHeader::mock(9, Some(chain.peaks().hash_peaks()), None, &[]); let err = ChainAnchor::new(header, chain).unwrap_err(); @@ -278,7 +269,7 @@ mod tests { fn new_rejects_peaks_that_do_not_hash_to_the_chain_commitment() { let (_, chain) = anchor_parts(8, &[3]); // Right block number, but a header committing to an unrelated chain commitment. - let header = BlockHeader::mock(8, None, None, &[], Word::empty()); + let header = BlockHeader::mock(8, None, None, &[]); let err = ChainAnchor::new(header, chain).unwrap_err(); @@ -314,7 +305,7 @@ mod tests { let mut mmr = Mmr::default(); let mut headers = Vec::new(); for block_num in 0..4u32 { - let header = BlockHeader::mock(block_num, None, None, &[], Word::empty()); + let header = BlockHeader::mock(block_num, None, None, &[]); mmr.add(header.commitment()).unwrap(); headers.push(header); } @@ -329,7 +320,7 @@ mod tests { let bytes = { let mut buf = Vec::new(); - let header = BlockHeader::mock(4, Some(peaks.hash_peaks()), None, &[], Word::empty()); + let header = BlockHeader::mock(4, Some(peaks.hash_peaks()), None, &[]); header.write_into(&mut buf); PartialBlockchain::new_unchecked(partial_mmr, [headers[3].clone()]) .unwrap() diff --git a/crates/rust-client/src/transaction/dap_executor.rs b/crates/rust-client/src/transaction/dap_executor.rs index b417927c6e..4eafd02617 100644 --- a/crates/rust-client/src/transaction/dap_executor.rs +++ b/crates/rust-client/src/transaction/dap_executor.rs @@ -9,7 +9,7 @@ use std::string::ToString; use std::sync::Arc; -use miden_processor::advice::AdviceInputs; +use miden_processor::advice::{AdviceError, AdviceInputs}; use miden_processor::{ ExecutionError, ExecutionOptions, @@ -36,7 +36,15 @@ use miden_protocol::vm::{ use miden_tx::ProgramExecutor; /// [`ProgramExecutor`] adapter for [`miden_debug::DapExecutor`]. -pub struct DapProgramExecutor(miden_debug::DapExecutor); +/// +/// The debug information reaches the executor before execution. The package the debugger consumes +/// can only be built once the program is known. Both configured values are therefore held here +/// until [`ProgramExecutor::execute`] assembles the package. +pub struct DapProgramExecutor { + executor: miden_debug::DapExecutor, + package_debug_info: PackageDebugInfo, + entrypoint_source_node: Option, +} impl DapProgramExecutor { fn execute_package( @@ -46,7 +54,7 @@ impl DapProgramExecutor { ) -> impl FutureMaybeSend> { async move { let package = package?; - self.0.execute_async(package, host).await + self.executor.execute_async(package, host).await } } } @@ -56,27 +64,34 @@ impl ProgramExecutor for DapProgramExecutor { stack_inputs: StackInputs, advice_inputs: AdviceInputs, options: ExecutionOptions, - ) -> Self { - Self(miden_debug::DapExecutor::new(stack_inputs, advice_inputs, options)) + ) -> Result { + Ok(Self { + executor: miden_debug::DapExecutor::new(stack_inputs, advice_inputs, options), + package_debug_info: PackageDebugInfo::default(), + entrypoint_source_node: None, + }) } - fn execute( - self, - program: &Program, - host: &mut H, - ) -> impl FutureMaybeSend> { - let package = build_dap_package(program, &PackageDebugInfo::default(), None); - self.execute_package(package, host) + fn with_debug_info(mut self, package_debug_info: PackageDebugInfo) -> Self { + self.package_debug_info = package_debug_info; + self + } + + fn with_entrypoint_source_node( + mut self, + entrypoint_source_node: Option, + ) -> Self { + self.entrypoint_source_node = entrypoint_source_node; + self } - fn execute_with_package_debug_info( + fn execute( self, program: &Program, - package_debug_info: &PackageDebugInfo, - entrypoint_source_node: Option, host: &mut H, ) -> impl FutureMaybeSend> { - let package = build_dap_package(program, package_debug_info, entrypoint_source_node); + let package = + build_dap_package(program, &self.package_debug_info, self.entrypoint_source_node); self.execute_package(package, host) } } diff --git a/crates/rust-client/src/transaction/mod.rs b/crates/rust-client/src/transaction/mod.rs index d8f0995df4..24017197fc 100644 --- a/crates/rust-client/src/transaction/mod.rs +++ b/crates/rust-client/src/transaction/mod.rs @@ -69,7 +69,7 @@ use alloc::sync::Arc; use alloc::vec::Vec; use miden_protocol::account::{AccountCode, AccountCodeInterface, AccountId, PartialAccount}; -use miden_protocol::asset::{Asset, NonFungibleAsset}; +use miden_protocol::asset::Asset; use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters}; use miden_protocol::errors::AssetError; use miden_protocol::note::{ @@ -81,6 +81,7 @@ use miden_protocol::note::{ NoteScript, NoteTag, }; +use miden_protocol::protocol_config::ProtocolConfig; use miden_protocol::transaction::{AccountInputs, PartialBlockchain}; use miden_protocol::vm::MIN_STACK_DEPTH; use miden_protocol::{Felt, Word}; @@ -189,7 +190,7 @@ pub use miden_tx::auth::TransactionAuthenticator; pub use miden_tx::{ DataStoreError, LocalTransactionProver, - ProvingOptions, + Prover, TransactionExecutorError, TransactionProverError, }; @@ -330,12 +331,12 @@ where account_id: AccountId, transaction_request: TransactionRequest, ) -> Result { - self.execute_transaction_with_mode( + Box::pin(self.execute_transaction_with_mode( account_id, transaction_request, TransactionExecutionMode::Standard, None, - ) + )) .await } @@ -706,6 +707,7 @@ where &mut transaction_request, &account_code_interface, &reference_header, + &self.get_protocol_config(reference_header.protocol_config_commitment()).await?, )?; let tx_args = transaction_request.into_transaction_args(tx_script); @@ -828,7 +830,7 @@ where let genesis_commitment = self.trusted_block_header(BlockNumber::GENESIS).await?.commitment(); let chain_tip = self.store.get_sync_height().await?; - let validator_keys = self.trusted_block_header(chain_tip).await?.validator_keys().clone(); + let validator_keys = self.trusted_block_header(chain_tip).await?.validator_config().clone(); let key = attested.verify(genesis_commitment, &validator_keys)?; self.store.set_transaction_encryption_key(&key).await?; @@ -1482,7 +1484,7 @@ impl PreparedTransaction { /// notes wouldn't be included. fn get_outgoing_assets( transaction_request: &TransactionRequest, -) -> (BTreeMap, Vec) { +) -> (BTreeMap, Vec) { let mut own_notes_assets = match transaction_request.script_template() { Some(TransactionScriptTemplate::SendNotes(notes)) => notes .iter() @@ -1523,6 +1525,7 @@ fn attach_native_fee_conversion_info( transaction_request: &mut TransactionRequest, account_code_interface: &AccountCodeInterface, reference_header: &BlockHeader, + protocol_config: &ProtocolConfig, ) -> Result<(), ClientError> { // An auth arg the caller set is the caller's business: it may carry a commitment the caller // computed itself, or something else entirely. An empty word commits nothing, so it does not @@ -1540,15 +1543,17 @@ fn attach_native_fee_conversion_info( match FeeAuth::of(account_code_interface) { FeeAuth::FixedSalt => { transaction_request.commit_native_fee_conversion_info( - fee_parameters.fee_faucet_id(), + protocol_config.fee_asset_id().faucet_id(), declared_salt.unwrap_or(NATIVE_FEE_CONVERSION_SALT), ); Ok(()) }, FeeAuth::CallerChosenSalt(component) => match declared_salt { Some(salt) => { - transaction_request - .commit_native_fee_conversion_info(fee_parameters.fee_faucet_id(), salt); + transaction_request.commit_native_fee_conversion_info( + protocol_config.fee_asset_id().faucet_id(), + salt, + ); Ok(()) }, None => Err(ClientError::TransactionRequestError( @@ -1637,6 +1642,7 @@ impl FeeAuth { pub(crate) fn native_fee_conversion_info( account_code_interface: &AccountCodeInterface, fee_parameters: &FeeParameters, + protocol_config: &ProtocolConfig, ) -> Option { if fee_parameters.verification_base_fee() == 0 { return None; @@ -1645,7 +1651,9 @@ pub(crate) fn native_fee_conversion_info( // Only a fixed salt can be paired with this info by anyone other than the caller: where the // salt is the account's replay guard, the caller is the one who has to choose it. match FeeAuth::of(account_code_interface) { - FeeAuth::FixedSalt => Some(FeeConversionInfo::one_to_one(fee_parameters.fee_faucet_id())), + FeeAuth::FixedSalt => { + Some(FeeConversionInfo::one_to_one(protocol_config.fee_asset_id().faucet_id())) + }, FeeAuth::CallerChosenSalt(_) | FeeAuth::Ignored(_) => None, } } @@ -1710,7 +1718,7 @@ fn validate_basic_account_request( // may occupy more than one callback-flag vault key, so all matching entries are summed. let mut available_fungible: BTreeMap = BTreeMap::new(); for asset in vault_assets { - if let Asset::Fungible(fungible) = asset { + if let Some(fungible) = asset.as_fungible() { let balance = available_fungible.entry(fungible.faucet_id()).or_default(); *balance = balance.saturating_add(fungible.amount().as_u64()); } @@ -1732,9 +1740,7 @@ fn validate_basic_account_request( // Check if the account balance plus incoming assets is greater than or equal to the outgoing // non fungible assets for non_fungible in &non_fungible_set { - let held = vault_assets - .iter() - .any(|asset| matches!(asset, Asset::NonFungible(nf) if nf == non_fungible)); + let held = vault_assets.iter().any(|asset| asset == non_fungible); if !held && !incoming_non_fungible_balance_set.contains(non_fungible) { return Err(ClientError::TransactionRequestError( TransactionRequestError::MissingNonFungibleAsset(non_fungible.faucet_id()), @@ -1873,17 +1879,17 @@ mod tests { AccountId, AccountType, }; - use miden_protocol::asset::FungibleAsset; + use miden_protocol::asset::{AssetId, FungibleAsset}; use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters}; use miden_protocol::crypto::rand::RandomCoin; use miden_protocol::note::{Note, NoteType}; + use miden_protocol::protocol_config::ProtocolConfig; use miden_protocol::testing::account_id::{ ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, ACCOUNT_ID_SENDER, }; - use miden_protocol::testing::validator_keys::random_validator_set; use miden_standards::account::AccountBuilderSchemaCommitmentExt; use miden_standards::account::auth::{ Approver, @@ -2052,17 +2058,17 @@ mod tests { /// in so the two can be told apart. const NATIVE_FEE_FAUCET: u128 = ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET; - /// Builds a block header whose fee parameters charge `verification_base_fee` in - /// [`NATIVE_FEE_FAUCET`]'s asset. + fn test_protocol_config() -> ProtocolConfig { + ProtocolConfig::current(AssetId::new_fungible(NATIVE_FEE_FAUCET.try_into().unwrap())) + .unwrap() + } + + /// Builds a block header with fees in the [`NATIVE_FEE_FAUCET`] asset. fn header_with_base_fee(verification_base_fee: u32) -> BlockHeader { - let fee_parameters = FeeParameters::new( - AccountId::try_from(NATIVE_FEE_FAUCET).unwrap(), - verification_base_fee, - ); - let (_, validator_keys) = random_validator_set(1); + let fee_parameters = FeeParameters::new(verification_base_fee); + let (_, validator_keys) = miden_protocol::block::ValidatorConfig::random_with_signers(1); BlockHeader::new( - 1, Word::empty(), BlockNumber::from(1u32), Word::empty(), @@ -2070,9 +2076,10 @@ mod tests { Word::empty(), Word::empty(), Word::empty(), - Word::empty(), validator_keys, fee_parameters, + test_protocol_config().to_commitment(), + None, 0, ) } @@ -2088,6 +2095,7 @@ mod tests { &mut request, &account.code_interface(), &header_with_base_fee(verification_base_fee), + &test_protocol_config(), ); *request.auth_arg() } @@ -2102,6 +2110,7 @@ mod tests { &mut request, &account.code_interface(), &header_with_base_fee(verification_base_fee), + &test_protocol_config(), )?; Ok(*request.auth_arg()) } diff --git a/crates/rust-client/src/transaction/request/mod.rs b/crates/rust-client/src/transaction/request/mod.rs index 6b6540b1c9..1ed12b9bae 100644 --- a/crates/rust-client/src/transaction/request/mod.rs +++ b/crates/rust-client/src/transaction/request/mod.rs @@ -6,9 +6,8 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::num::NonZeroU16; -use miden_protocol::Word; use miden_protocol::account::{AccountCodeInterface, AccountId}; -use miden_protocol::asset::{Asset, NonFungibleAsset}; +use miden_protocol::asset::Asset; use miden_protocol::crypto::merkle::MerkleError; use miden_protocol::crypto::merkle::store::MerkleStore; use miden_protocol::errors::{ @@ -18,7 +17,6 @@ use miden_protocol::errors::{ NoteError, StorageMapError, TransactionInputError, - TransactionScriptError, }; use miden_protocol::note::{ Note, @@ -32,6 +30,7 @@ use miden_protocol::note::{ }; use miden_protocol::transaction::{InputNote, InputNotes, TransactionArgs, TransactionScript}; use miden_protocol::vm::AdviceMap; +use miden_protocol::{MastForestScriptError, Word}; use miden_standards::account::auth::{FeeConversionInfo, commit_fee_conversion_info}; use miden_standards::errors::CodeBuilderError; use miden_standards::tx_script::{SendNotesTransactionScript, SendNotesTransactionScriptError}; @@ -150,7 +149,7 @@ impl TransactionRequest { } /// Returns the assets held by the transaction's input notes. - pub fn incoming_assets(&self) -> (BTreeMap, Vec) { + pub fn incoming_assets(&self) -> (BTreeMap, Vec) { collect_assets(self.input_notes.iter().flat_map(|note| note.assets().iter())) } @@ -524,26 +523,26 @@ impl Deserializable for TransactionRequest { // ================================================================================================ /// Accumulates fungible totals and collectable non-fungible assets from an iterator of assets. +/// +/// An asset that is neither fungible nor non-fungible is left out of both buckets, since neither +/// balance arithmetic applies to it. Execution judges such an asset instead. pub(crate) fn collect_assets<'a>( assets: impl Iterator, -) -> (BTreeMap, Vec) { +) -> (BTreeMap, Vec) { let mut fungible_balance_map = BTreeMap::new(); let mut non_fungible_set = Vec::new(); - assets.for_each(|asset| match asset { - Asset::Fungible(fungible) => { + for asset in assets { + if let Some(fungible) = asset.as_fungible() { let amount = fungible.amount().as_u64(); fungible_balance_map .entry(fungible.faucet_id()) .and_modify(|balance| *balance += amount) .or_insert(amount); - }, - Asset::NonFungible(non_fungible) => { - if !non_fungible_set.contains(non_fungible) { - non_fungible_set.push(*non_fungible); - } - }, - }); + } else if asset.is_non_fungible() && !non_fungible_set.contains(asset) { + non_fungible_set.push(*asset); + } + } (fungible_balance_map, non_fungible_set) } @@ -599,7 +598,7 @@ pub enum TransactionRequestError { )] FeeConversionInfoRequired(String), #[error("invalid transaction script")] - InvalidTransactionScript(#[from] TransactionScriptError), + InvalidTransactionScript(#[from] MastForestScriptError), #[error("merkle proof error")] MerkleError(#[from] MerkleError), #[error("empty transaction: the request has no input notes and no account state changes")] diff --git a/crates/rust-client/src/transaction/store_update.rs b/crates/rust-client/src/transaction/store_update.rs index 677463f9f9..5218680488 100644 --- a/crates/rust-client/src/transaction/store_update.rs +++ b/crates/rust-client/src/transaction/store_update.rs @@ -139,7 +139,7 @@ mod tests { // real `ExecutedTransaction`. let sender_id = ACCOUNT_ID_SENDER.try_into().unwrap(); let faucet_id = ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET.try_into().unwrap(); - let asset = Asset::Fungible(FungibleAsset::new(faucet_id, 100u64).unwrap()); + let asset = Asset::from(FungibleAsset::new(faucet_id, 100u64).unwrap()); let mut builder = MockChainBuilder::new(); let account = builder.add_existing_mock_account(miden_testing::Auth::IncrNonce).unwrap(); diff --git a/crates/sqlite-store/src/account/tests.rs b/crates/sqlite-store/src/account/tests.rs index ed7a0c857c..57f9c86140 100644 --- a/crates/sqlite-store/src/account/tests.rs +++ b/crates/sqlite-store/src/account/tests.rs @@ -182,7 +182,7 @@ async fn apply_account_patch_additions() -> anyhow::Result<()> { SqliteStore::apply_account_patch( &tx, &mut smt_forest, - &account.into(), + &(&account).into(), &final_state, &patch, )?; @@ -282,7 +282,7 @@ async fn apply_account_patch_preserves_fungible_callback_flag() -> anyhow::Resul SqliteStore::apply_account_patch( &tx, &mut smt_forest, - &account.into(), + &(&account).into(), &final_state, &patch, )?; @@ -379,7 +379,7 @@ async fn apply_account_patch_removes_slots_and_assets() -> anyhow::Result<()> { SqliteStore::apply_account_patch( &tx, &mut smt_forest, - &account.into(), + &(&account).into(), &final_state, &patch, )?; diff --git a/crates/sqlite-store/src/chain_data.rs b/crates/sqlite-store/src/chain_data.rs index d730f1867c..39aacd3f5f 100644 --- a/crates/sqlite-store/src/chain_data.rs +++ b/crates/sqlite-store/src/chain_data.rs @@ -122,8 +122,10 @@ impl SqliteStore { PartialBlockchainFilter::Forest(forest) if forest.is_empty() => Ok(BTreeMap::new()), PartialBlockchainFilter::Forest(forest) => { - let max_index = i64::try_from(forest.rightmost_in_order_index().inner()) - .expect("id is a valid i64"); + let max_index = i64::try_from( + forest.rightmost_in_order_index().expect("forest is not empty").inner(), + ) + .expect("id is a valid i64"); query_partial_blockchain_nodes( conn, @@ -405,18 +407,14 @@ mod test { use miden_client::store::{PartialBlockchainFilter, Store}; use miden_client::utils::Serializable; use miden_protocol::crypto::merkle::mmr::Mmr; - use miden_protocol::transaction::TransactionKernel; use rusqlite::params; use crate::SqliteStore; use crate::tests::create_test_store; async fn insert_dummy_block_headers(store: &mut SqliteStore) -> Vec { - let block_headers: Vec = (0..5) - .map(|block_num| { - BlockHeader::mock(block_num, None, None, &[], TransactionKernel.to_commitment()) - }) - .collect(); + let block_headers: Vec = + (0..5).map(|block_num| BlockHeader::mock(block_num, None, None, &[])).collect(); let block_headers_clone = block_headers.clone(); store @@ -472,10 +470,9 @@ mod test { async fn insert_block_header_stores_header_and_nodes() { let store = create_test_store().await; const TOTAL_BLOCKS: usize = 8; - let tx_kernel = TransactionKernel.to_commitment(); let headers: Vec = (0..TOTAL_BLOCKS) - .map(|n| BlockHeader::mock(u32::try_from(n).unwrap(), None, None, &[], tx_kernel)) + .map(|n| BlockHeader::mock(u32::try_from(n).unwrap(), None, None, &[])) .collect(); let mut mmr = Mmr::default(); for header in &headers { @@ -512,7 +509,7 @@ mod test { #[tokio::test] async fn insert_block_header_rolls_back_header_when_nodes_fail() { let store = create_test_store().await; - let header = BlockHeader::mock(5, None, None, &[], TransactionKernel.to_commitment()); + let header = BlockHeader::mock(5, None, None, &[]); // One node so the node insert actually runs (an empty slice would be a no-op). let nodes = [(InOrderIndex::from_leaf_pos(5), header.commitment())]; @@ -544,17 +541,8 @@ mod test { let store = create_test_store().await; const TOTAL_BLOCKS: usize = 7300; - let tx_kernel_commitment = TransactionKernel.to_commitment(); let block_headers: Vec = (0..TOTAL_BLOCKS) - .map(|block_num| { - BlockHeader::mock( - u32::try_from(block_num).unwrap(), - None, - None, - &[], - tx_kernel_commitment, - ) - }) + .map(|block_num| BlockHeader::mock(u32::try_from(block_num).unwrap(), None, None, &[])) .collect(); let mut mmr = Mmr::default(); @@ -694,10 +682,9 @@ mod test { async fn prune_irrelevant_blocks_removes_redundant_auth_nodes() { let store = create_test_store().await; const TOTAL_BLOCKS: usize = 16; - let tx_kernel = TransactionKernel.to_commitment(); let headers: Vec = (0..TOTAL_BLOCKS) - .map(|n| BlockHeader::mock(u32::try_from(n).unwrap(), None, None, &[], tx_kernel)) + .map(|n| BlockHeader::mock(u32::try_from(n).unwrap(), None, None, &[])) .collect(); let mut mmr = Mmr::default(); for h in &headers { diff --git a/crates/testing/miden-client-tests/src/tests.rs b/crates/testing/miden-client-tests/src/tests.rs index 8202785f4d..f157eb1eac 100644 --- a/crates/testing/miden-client-tests/src/tests.rs +++ b/crates/testing/miden-client-tests/src/tests.rs @@ -355,7 +355,7 @@ async fn get_account_by_id() { Ok(header_and_status) => header_and_status, Err(err) => panic!("Error retrieving account: {err}"), }; - assert_eq!(AccountHeader::from(account), acc_from_db); + assert_eq!(AccountHeader::from(&account), acc_from_db); // Retrieving a non existing account should return error let invalid_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2).unwrap(); @@ -1112,7 +1112,7 @@ async fn note_without_asset() { let error = TransactionRequestBuilder::new() .build_pay_to_id( PaymentNoteDescription::new( - vec![Asset::Fungible(FungibleAsset::new(faucet.id(), 0).unwrap())], + vec![Asset::from(FungibleAsset::new(faucet.id(), 0).unwrap())], faucet.id(), wallet.id(), ), @@ -1148,8 +1148,8 @@ async fn swap_note_with_zero_asset() { // carrying the requested asset, so neither side may be zero. let other_faucet = client.insert_faucet(AccountType::Private).await.unwrap(); - let zero_asset = Asset::Fungible(FungibleAsset::new(faucet.id(), 0).unwrap()); - let some_asset = Asset::Fungible(FungibleAsset::new(other_faucet.id(), 100).unwrap()); + let zero_asset = Asset::from(FungibleAsset::new(faucet.id(), 0).unwrap()); + let some_asset = Asset::from(FungibleAsset::new(other_faucet.id(), 100).unwrap()); let error = TransactionRequestBuilder::new() .build_swap( @@ -1348,11 +1348,7 @@ async fn p2id_transfer() { println!("Running P2ID tx..."); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Private, client.rng(), ) @@ -1441,7 +1437,7 @@ async fn input_note_reader_finds_externally_consumed_notes() { let consumer = builder.add_existing_mock_account(miden_testing::Auth::IncrNonce).unwrap(); let consumer_id = consumer.id(); - let asset = Asset::Fungible(FungibleAsset::new(faucet_id, 100u64).unwrap()); + let asset = Asset::from(FungibleAsset::new(faucet_id, 100u64).unwrap()); let p2id_note = builder .add_p2id_note(sender_id, consumer_id, &[asset], NoteType::Public) .unwrap(); @@ -1548,7 +1544,7 @@ async fn import_by_id_already_consumed_note_is_findable_by_id() { let consumer = builder.add_existing_mock_account(miden_testing::Auth::IncrNonce).unwrap(); let consumer_id = consumer.id(); - let asset = Asset::Fungible(FungibleAsset::new(faucet_id, 100u64).unwrap()); + let asset = Asset::from(FungibleAsset::new(faucet_id, 100u64).unwrap()); let p2id_note = builder .add_p2id_note(sender_id, consumer_id, &[asset], NoteType::Public) .unwrap(); @@ -1787,11 +1783,7 @@ async fn p2id_transfer_failing_not_enough_balance() { println!("Running P2ID tx..."); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id), NoteType::Private, client.rng(), ) @@ -1878,12 +1870,8 @@ async fn p2ide_transfer_consumed_by_target() { println!("Running P2IDE tx..."); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ) - .with_reclaim_height(current_block_num + RECALL_HEIGHT_DELTA), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) + .with_reclaim_height(current_block_num + RECALL_HEIGHT_DELTA), NoteType::Private, client.rng(), ) @@ -1970,12 +1958,8 @@ async fn p2ide_transfer_consumed_by_sender() { println!("Running P2IDE tx..."); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ) - .with_reclaim_height(current_block_num + RECALL_HEIGHT_DELTA), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) + .with_reclaim_height(current_block_num + RECALL_HEIGHT_DELTA), NoteType::Private, client.rng(), ) @@ -2073,13 +2057,9 @@ async fn p2ide_timelocked() { let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ) - .with_timelock_height(current_block_num + RECALL_HEIGHT_DELTA) - .with_reclaim_height(current_block_num), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) + .with_timelock_height(current_block_num + RECALL_HEIGHT_DELTA) + .with_reclaim_height(current_block_num), NoteType::Public, client.rng(), ) @@ -2183,12 +2163,8 @@ async fn get_consumable_notes() { println!("Running P2IDE tx..."); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], - from_account_id, - to_account_id, - ) - .with_reclaim_height(100.into()), + PaymentNoteDescription::new(vec![Asset::from(asset)], from_account_id, to_account_id) + .with_reclaim_height(100.into()), NoteType::Private, client.rng(), ) @@ -2441,7 +2417,7 @@ async fn get_output_notes() { let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( PaymentNoteDescription::new( - vec![Asset::Fungible(asset)], + vec![Asset::from(asset)], from_account_id, random_account_id, ), @@ -2501,7 +2477,7 @@ async fn account_rollback() { let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id, account_id), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id, account_id), NoteType::Public, client.rng(), ) @@ -2577,7 +2553,7 @@ async fn account_rollback() { // Apply a new transaction let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id, account_id), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id, account_id), NoteType::Public, client.rng(), ) @@ -2661,7 +2637,7 @@ async fn subsequent_discarded_transactions() { let tx_request = TransactionRequestBuilder::new() .expiration_delta(2) .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id, account_id), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id, account_id), NoteType::Public, client.rng(), ) @@ -2684,7 +2660,7 @@ async fn subsequent_discarded_transactions() { let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); let tx_request = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id, account_id), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id, account_id), NoteType::Public, client.rng(), ) @@ -2876,8 +2852,8 @@ async fn swap_chain_test() { .build_swap( &SwapTransactionData::new( pairs[0].0.id(), - Asset::Fungible(FungibleAsset::new(pairs[0].1.id(), 1).unwrap()), - Asset::Fungible(FungibleAsset::new(pairs[1].1.id(), 1).unwrap()), + Asset::from(FungibleAsset::new(pairs[0].1.id(), 1).unwrap()), + Asset::from(FungibleAsset::new(pairs[1].1.id(), 1).unwrap()), ), NoteType::Private, NoteType::Private, @@ -2950,8 +2926,8 @@ async fn swap_public_payback_test() { .build_swap( &SwapTransactionData::new( wallet_a.id(), - Asset::Fungible(FungibleAsset::new(faucet_a.id(), 1).unwrap()), - Asset::Fungible(FungibleAsset::new(faucet_b.id(), 1).unwrap()), + Asset::from(FungibleAsset::new(faucet_a.id(), 1).unwrap()), + Asset::from(FungibleAsset::new(faucet_b.id(), 1).unwrap()), ), NoteType::Private, NoteType::Public, @@ -3024,8 +3000,8 @@ async fn partial_output_note_receives_inclusion_proof_after_sync() { client.sync_state().await.unwrap(); // Wallet A creates a SWAP note: offers 1 unit of faucet_a, requests 1 unit of faucet_b. - let offered_asset = Asset::Fungible(FungibleAsset::new(faucet_a.id(), 1).unwrap()); - let requested_asset = Asset::Fungible(FungibleAsset::new(faucet_b.id(), 1).unwrap()); + let offered_asset = Asset::from(FungibleAsset::new(faucet_a.id(), 1).unwrap()); + let requested_asset = Asset::from(FungibleAsset::new(faucet_b.id(), 1).unwrap()); let swap_tx_request = TransactionRequestBuilder::new() .build_swap( @@ -4689,7 +4665,7 @@ async fn sync_large_public_account() { let assets: Vec = faucets .iter() - .map(|faucet| Asset::Fungible(FungibleAsset::new(faucet.id(), 100).unwrap())) + .map(|faucet| Asset::from(FungibleAsset::new(faucet.id(), 100).unwrap())) .collect(); let mock_account = builder @@ -4786,7 +4762,6 @@ async fn sync_large_public_account() { async fn prepare_offline_bootstrap_inserts_mock_chain_genesis() { use miden_protocol::block::account_tree::AccountTree; use miden_protocol::crypto::merkle::smt::Smt; - use miden_protocol::transaction::TransactionKernel; let mut rng_seed = rand::rng(); let coin_seed: [u64; 4] = rng_seed.random(); @@ -4820,9 +4795,15 @@ async fn prepare_offline_bootstrap_inserts_mock_chain_genesis() { assert_eq!(stored_genesis.block_num(), BlockNumber::GENESIS); assert_eq!(stored_genesis.account_root(), expected_genesis.account_root()); - assert_eq!(stored_genesis.tx_kernel_commitment(), expected_genesis.tx_kernel_commitment()); + assert_eq!( + stored_genesis.protocol_config_commitment(), + expected_genesis.protocol_config_commitment() + ); assert_eq!(stored_genesis.account_root(), AccountTree::::default().root()); - assert_eq!(stored_genesis.tx_kernel_commitment(), TransactionKernel.to_commitment()); + assert_eq!( + stored_genesis.protocol_config_commitment(), + reference_rpc.protocol_config().to_commitment() + ); } // HELPERS @@ -4839,6 +4820,10 @@ pub async fn create_test_client() -> (TestClient, MockRpcApi) { /// Gives a mock-backed client the transaction encryption key that submission seals against. pub async fn seed_mock_transaction_encryption_key(client: &mut MockClient) { + client + .add_protocol_config(MockChain::new().protocol_config().clone()) + .await + .unwrap(); let genesis_commitment = client .get_block_header_by_num(BlockNumber::GENESIS) .await @@ -4870,6 +4855,7 @@ pub async fn create_test_client_builder() -> (ClientBuilder, let arc_rpc_api = Arc::new(rpc_api.clone()); let builder = ClientBuilder::new() + .protocol_config(rpc_api.protocol_config()) .rpc(arc_rpc_api) .rng(Box::new(rng)) .sqlite_store(create_test_store_path()) @@ -5248,3 +5234,5 @@ async fn execute_transaction_fails_for_watched_account() { other => panic!("expected AccountIsWatched, got {other:?}"), } } + +mod protocol_config; diff --git a/crates/testing/miden-client-tests/src/tests/batch.rs b/crates/testing/miden-client-tests/src/tests/batch.rs index 7a8a3f8df3..db34339ed0 100644 --- a/crates/testing/miden-client-tests/src/tests/batch.rs +++ b/crates/testing/miden-client-tests/src/tests/batch.rs @@ -299,7 +299,7 @@ async fn batch_builder_push_succeeds_when_balance_depends_on_prior_push() { let push2 = TransactionRequestBuilder::new() .build_pay_to_id( PaymentNoteDescription::new( - vec![Asset::Fungible(oversend)], + vec![Asset::from(oversend)], from_account_id, to_account_id, ), @@ -484,7 +484,7 @@ async fn batch_builder_serves_witnesses_for_state_untouched_by_prior_push() { let held_asset = FungibleAsset::new(held_faucet_id, TRANSFER_AMOUNT).unwrap(); let push2 = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(held_asset)], from_id, to_id), + PaymentNoteDescription::new(vec![Asset::from(held_asset)], from_id, to_id), NoteType::Private, client.rng(), ) @@ -732,7 +732,7 @@ async fn batch_builder_cross_account_note_flow() { let asset = FungibleAsset::new(faucet_account_id, MINT_AMOUNT).unwrap(); let req_send = TransactionRequestBuilder::new() .build_pay_to_id( - PaymentNoteDescription::new(vec![Asset::Fungible(asset)], account_id_a, account_id_b), + PaymentNoteDescription::new(vec![Asset::from(asset)], account_id_a, account_id_b), NoteType::Private, client.rng(), ) diff --git a/crates/testing/miden-client-tests/src/tests/protocol_config.rs b/crates/testing/miden-client-tests/src/tests/protocol_config.rs new file mode 100644 index 0000000000..7dd315e1da --- /dev/null +++ b/crates/testing/miden-client-tests/src/tests/protocol_config.rs @@ -0,0 +1,80 @@ +use miden_client::account::AccountType; +use miden_client::asset::AssetId; +use miden_client::protocol_config::ProtocolConfig; +use miden_client::store::{SettingScope, StoreError}; +use miden_client::transaction::TransactionRequestBuilder; +use miden_client::{ClientError, Serializable, Word}; +use miden_protocol::testing::account_id::ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2; + +use super::create_test_client; + +#[tokio::test] +async fn protocol_configs_are_selected_by_commitment() { + let (client, rpc) = create_test_client().await; + let original = rpc.protocol_config(); + let other = ProtocolConfig::current(AssetId::new_fungible( + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2.try_into().unwrap(), + )) + .unwrap(); + client.add_protocol_config(other.clone()).await.unwrap(); + assert_eq!(client.get_protocol_config(original.to_commitment()).await.unwrap(), original); + assert_eq!(client.get_protocol_config(other.to_commitment()).await.unwrap(), other); + assert!(matches!( + client.get_protocol_config(Word::empty()).await, + Err(ClientError::StoreError(StoreError::ProtocolConfigNotFound(_))) + )); +} + +#[tokio::test] +async fn protocol_config_rejects_a_substituted_preimage() { + let (mut client, rpc) = create_test_client().await; + let commitment = rpc.protocol_config().to_commitment(); + let other = ProtocolConfig::current(AssetId::new_fungible( + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2.try_into().unwrap(), + )) + .unwrap(); + assert_ne!(other.to_commitment(), commitment); + client + .test_store() + .set_setting( + SettingScope::Client, + format!("protocol_config:{commitment}"), + other.to_bytes(), + ) + .await + .unwrap(); + assert!(matches!( + client.get_protocol_config(commitment).await, + Err(ClientError::StoreError(StoreError::ProtocolConfigCommitmentMismatch(_))) + )); +} + +#[tokio::test] +async fn execution_requires_the_reference_block_protocol_config() { + let (mut client, rpc) = create_test_client().await; + client.sync_state().await.unwrap(); + let wallet = client.insert_wallet(AccountType::Private).await.unwrap(); + let config = rpc.protocol_config(); + let commitment = config.to_commitment(); + client + .test_store() + .remove_setting(SettingScope::Client, format!("protocol_config:{commitment}")) + .await + .unwrap(); + let other = ProtocolConfig::current(AssetId::new_fungible( + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2.try_into().unwrap(), + )) + .unwrap(); + assert_ne!(other.to_commitment(), commitment); + client.add_protocol_config(other).await.unwrap(); + + let request = TransactionRequestBuilder::new().build().unwrap(); + assert!(matches!( + client.execute_transaction(wallet.id(), request.clone()).await, + Err(ClientError::StoreError(StoreError::ProtocolConfigNotFound(missing))) + if missing == commitment + )); + + client.add_protocol_config(config).await.unwrap(); + client.execute_transaction(wallet.id(), request).await.unwrap(); +} diff --git a/crates/testing/test-node-genesis/README.md b/crates/testing/test-node-genesis/README.md index da27f1641c..0e46cce1fc 100644 --- a/crates/testing/test-node-genesis/README.md +++ b/crates/testing/test-node-genesis/README.md @@ -64,3 +64,5 @@ consumes, so this crate stays decoupled from the node's internal crates. ## License This project is [MIT licensed](../../../LICENSE). + +The generator writes `protocol-config.bin` with the configuration for the native fee faucet. The node startup script copies it to `data/protocol-config.bin`. Set `MIDEN_PROTOCOL_CONFIG` to this file when using the CLI or network benchmarks. Integration tests use `data/protocol-config.bin` by default. The client checks the configuration against the reference block commitment before execution. diff --git a/crates/testing/test-node-genesis/src/agglayer.rs b/crates/testing/test-node-genesis/src/agglayer.rs index 32de8a723a..08c36da184 100644 --- a/crates/testing/test-node-genesis/src/agglayer.rs +++ b/crates/testing/test-node-genesis/src/agglayer.rs @@ -13,14 +13,13 @@ use miden_protocol::account::{ AccountComponent, AccountComponentMetadata, AccountFile, - AccountId, AccountType, }; use miden_protocol::asset::{Asset, AssetAmount}; use miden_protocol::note::NoteScriptRoot; use miden_protocol::{Felt, Word}; use miden_standards::account::auth::{Approver, AuthSingleSig}; -use miden_standards::account::fees::{BasicConstantFeePolicy, FeePolicy, FeePolicyManager}; +use miden_standards::account::fees::BasicConstantFeePolicy; use miden_standards::account::wallets::BasicWallet; use rand_chacha::ChaCha20Rng; use rand_chacha::rand_core::SeedableRng; @@ -81,6 +80,8 @@ pub fn create_agglayer_genesis_accounts(fee_balance: Asset) -> Result Result Result().map(Felt::from).into(); let faucet = AggLayerFaucet::account_builder( faucet_seed, - "AGG", + miden_standards::account::faucets::TokenName::new("AggLayer Token").unwrap(), + miden_protocol::asset::TokenSymbol::new("AGG").unwrap(), 12, - Felt::from(1_000_000_000u32), - Felt::ZERO, + AssetAmount::new(1_000_000_000).unwrap(), + AssetAmount::ZERO, + admin_account.id(), admin_account.id(), bridge.id(), - zero_fee_policy_manager(fee_balance.faucet_id(), AggLayerFaucet::allowed_notes()), + fee_balance.faucet_id(), + zero_fee_policy(AggLayerFaucet::allowed_notes()), ) .build() .context("failed to build agglayer faucet account")?; @@ -135,18 +140,9 @@ pub fn create_agglayer_genesis_accounts(fee_balance: Asset) -> Result, -) -> FeePolicyManager { - let fee_policy: FeePolicy = BasicConstantFeePolicy::new() +fn zero_fee_policy(allowed_notes: BTreeSet) -> BasicConstantFeePolicy { + BasicConstantFeePolicy::new() .with_fees(allowed_notes.into_iter().map(|root| (root, AssetAmount::ZERO))) - .into(); - - FeePolicyManager::builder() - .fee_faucet_id(fee_faucet_id) - .active_fee_policy(fee_policy) - .build() } fn build_wallet_account(rng: &mut ChaCha20Rng, secret: &AuthSecretKey) -> Result { diff --git a/crates/testing/test-node-genesis/src/lib.rs b/crates/testing/test-node-genesis/src/lib.rs index f3d747ef41..902faceacb 100644 --- a/crates/testing/test-node-genesis/src/lib.rs +++ b/crates/testing/test-node-genesis/src/lib.rs @@ -21,7 +21,9 @@ use miden_protocol::account::{ StorageMap, StorageMapKey, }; -use miden_protocol::asset::{Asset, AssetAmount, FungibleAsset, TokenSymbol}; +use miden_protocol::asset::{Asset, AssetAmount, AssetId, FungibleAsset, TokenSymbol}; +use miden_protocol::protocol_config::ProtocolConfig; +use miden_protocol::utils::serde::Serializable; use miden_protocol::{ONE, Word}; use miden_standards::account::access::AccessControl; use miden_standards::account::auth::{Approver, AuthSingleSig}; @@ -117,6 +119,8 @@ pub fn write_genesis_config( generate_faucet_operator().context("failed to create the native faucet operator")?; let native_faucet = generate_native_faucet(operator.id()).context("failed to create the native fee faucet")?; + let protocol_config = ProtocolConfig::current(AssetId::new_fungible(native_faucet.id()))?; + std::fs::write(output_dir.join("protocol-config.bin"), protocol_config.to_bytes())?; let fee_balance: Asset = FungibleAsset::new(native_faucet.id(), GENESIS_ACCOUNT_FEE_BALANCE)?.into(); AccountFile::new(into_genesis_account(native_faucet, fee_balance)?, vec![]) @@ -171,7 +175,6 @@ pub fn write_genesis_config( // public keys on the command line, and `start-test-node.sh` generates the key-pair it passes // there alongside the matching signing key. let config = GenesisConfig { - version: 1, timestamp, native_faucet: NATIVE_FAUCET_FILE.to_string(), fee_parameters: FeeParametersEntry { verification_base_fee }, @@ -203,7 +206,6 @@ pub fn write_genesis_config( /// table, so the scalars have to stay above `fee_parameters` and the two arrays of tables. #[derive(Serialize)] struct GenesisConfig { - version: u32, timestamp: u32, /// File name of the faucet whose asset the chain charges fees in. native_faucet: String, @@ -442,7 +444,7 @@ fn create_test_account_with_many_assets(faucets: &[Account]) -> anyhow::Result