From 56d6d9f4e96d6297241c99562897e8e0fe47ee3e Mon Sep 17 00:00:00 2001 From: Mohammad Fawaz Date: Tue, 4 Aug 2026 09:16:44 -0400 Subject: [PATCH 1/5] enforce deployment limits --- Cargo.lock | 174 +++++++++++++++++---------------------------------- Cargo.toml | 8 ++- src/start.rs | 112 ++++++++++++++++++++++++++++++--- 3 files changed, 170 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b55eba9..2d36582 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3051,8 +3051,7 @@ dependencies = [ [[package]] name = "snarkvm" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea37705e6ba5f11a8da0f61393ba14aa320fcaf9fb410dff835c396ba20283a" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "dotenvy", @@ -3072,8 +3071,7 @@ dependencies = [ [[package]] name = "snarkvm-algorithms" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d54fee12c2bb1c58ef9a46be861f4b0b07285046b67918ce8ca61757d9a70" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3100,8 +3098,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e67a5337192cb95713736c724e4209c82b73c8ca2208033b80efc9d9e0d1dfe" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -3115,8 +3112,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-account" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f096425d431e6f3b6bd190756016464cee1627435d043ee1edcd2fd368a96e5d" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-network", "snarkvm-circuit-types", @@ -3126,8 +3122,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-algorithms" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3620f97ce1946468e0771bf6f5c2cd4cad53835e65a6369556813e364e61f26e" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-types", "snarkvm-console-algorithms", @@ -3137,8 +3132,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-collections" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb124eb7120d08fdf493248a1b0a992549b6c3c0d6a5952f7ccd4cfb39f9e88" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-types", @@ -3148,8 +3142,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eedb2cc4f93b8ecda8c1f05a4faaac10e55127f0fc09d7749dfc610d4bcbaa0f" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "indexmap", @@ -3169,14 +3162,12 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment-witness" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2351fbdbb775fc850617ab0043b1b0033a47a6151b5bf516cc49c3c883b08a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" [[package]] name = "snarkvm-circuit-network" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292c9506df0d1ec32dd4ef58d52e56716b6ccd3ca4ce4769852afeeb47856b5e" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-collections", @@ -3187,8 +3178,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-program" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df200abab8279b37fc386fb419e0bcdb83efa8ba291e8d62a893427d7f23d4b1" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -3202,8 +3192,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f0060b2c07f80a26b0f9547ef040f47b1c37c6aa5adb1983a19c144e091518" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-address", @@ -3218,8 +3207,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-address" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f104b0d3c7637f37d8abeb743c8ba31a518127ce0117b190879e0fac48c933d0" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3232,8 +3220,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-boolean" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad042be95bb0b5c9545ac3a12f9f3fde852f1167481d47d1c13a3aae3cdcdb9" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-console-types-boolean", @@ -3242,8 +3229,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-field" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65d5d37de0ae246a7f734c1d897c4b8eb9f5df7a1fdddf420ac65d3b64a4bcf5" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3253,8 +3239,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-group" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dcf26d059063dc16a37f3a923583c66899ec13d52a0e86c8fa141d78e776e02" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3266,8 +3251,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-integers" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d83fd4b20ee4f964bb1c40459d67e0741872f56197898b45df8e86e639926c" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3279,8 +3263,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-scalar" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8b1a4e94e49487f02d8b308e03d6c56f50dbb5a1441ad3a74f04f6ba745b4b" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3291,8 +3274,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-string" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "665506fbf883d0aa0b152b06b324a609841742064a88dc9a355753ed90da57d8" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3304,8 +3286,7 @@ dependencies = [ [[package]] name = "snarkvm-console" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b611f443daa6140f2c5bbdf5d184567f2b88cf73be5d7160500c3a5d56ca209f" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-account", "snarkvm-console-algorithms", @@ -3318,8 +3299,7 @@ dependencies = [ [[package]] name = "snarkvm-console-account" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adbf603ba5930c02d18bdd748c14418c2bbaf4bf6041f786571d510eac5db21" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "bs58", "snarkvm-console-network", @@ -3330,8 +3310,7 @@ dependencies = [ [[package]] name = "snarkvm-console-algorithms" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb693083ea8c9d1ed2a71880730b7251410aa45003602c16f89fbcda8b9ba860" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "blake2s_simd", "hex", @@ -3348,8 +3327,7 @@ dependencies = [ [[package]] name = "snarkvm-console-collections" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad460b844a736bae3f4fadb393313d2c2c7cdbdce3d228d8c339cec387251011" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "parking_lot", @@ -3362,8 +3340,7 @@ dependencies = [ [[package]] name = "snarkvm-console-network" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97bc1b423cf6304ab4f35a71b995be7bf9c5429bed1f92578a212c933b161f84" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "enum-iterator", @@ -3383,8 +3360,7 @@ dependencies = [ [[package]] name = "snarkvm-console-network-environment" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "272b60c9c736f7cc4aec0ad66ff960ddaa575657e4c5fcc6a69207ba60fb19cc" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "bech32", @@ -3402,8 +3378,7 @@ dependencies = [ [[package]] name = "snarkvm-console-program" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26501fe0d11bb0601267efb42ca51c495ad86793878a1747cf16ed097b0f1342" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "enum-iterator", "enum_index", @@ -3424,8 +3399,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da6c236d32f2f37b430d4d6ef134ff9395cb35f16c8af6bd4e0fb388ae1195f7" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-address", @@ -3440,8 +3414,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-address" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ee19a161735abffdea99051ed7200c0fae13201ab57dc2f375a9403bd1bb11" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3452,8 +3425,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-boolean" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "649f21d68e74d94c28936fd01b53e2acd7d26c31d01a894497bbf6f41b05c4bd" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", ] @@ -3461,8 +3433,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-field" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a004d12492258c3e6e9847d8b6b2462c3c03721c5f643c338a93f08f97ef3ad" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3472,8 +3443,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-group" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977fcf939d3d2f1398d041ede04dd1ed4eed82febc6ea91e41e0ef26d1a11b01" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3484,8 +3454,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-integers" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceaca4e72d54890d115a05d3798c5d3d8e785aedf471cb5d47aa80ac3a7169b" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3496,8 +3465,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-scalar" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50234ae5b7cbeb042d5c768d821c555b649df36f3c0bbf5d2d053639a67274b0" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3508,8 +3476,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-string" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b42f0e1b1730ab805ba02c4a2f30a31bdd62600301d23913399675aa896346" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3520,8 +3487,7 @@ dependencies = [ [[package]] name = "snarkvm-curves" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7e845865d40b36069fa76ef88a9e78f7f9c33f64c4e19f7cfd601922fab702" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "rand 0.10.1", "rustc_version", @@ -3534,8 +3500,7 @@ dependencies = [ [[package]] name = "snarkvm-fields" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4121086d60733b44bba6a7cb56c8b740d38257326bc86bc74ec96b92b6952c47" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3552,8 +3517,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8509cbe5ca45ce545db05a3fb706422770c01515f2f92065faaf7b10a30a52" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3583,8 +3547,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-authority" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e32462f86a9cb94444976c434c527ed5b10759d434e03f1196c3b02a2823b53" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "rand 0.10.1", @@ -3596,8 +3559,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-block" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a29e2ba2899708c5ed75c38fa240b90ef1c93b09666d294f7d70d7f0fd6c7d" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "indexmap", @@ -3621,8 +3583,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-committee" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6eb6a7fde1b507454297556a66db81423201d351e1806c13408ee94cde0889" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "indexmap", "rayon", @@ -3634,8 +3595,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5c565c1efc362a10db86b29a3c1337ecb66a028b3e1d6b8ff2318640e4233b" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-ledger-narwhal-batch-certificate", "snarkvm-ledger-narwhal-batch-header", @@ -3648,8 +3608,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-certificate" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2239748ed6c1259ccc2ee221a2efc0c7567f9c4e7cacf5d3580a6423bbe5438" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "indexmap", "rayon", @@ -3662,8 +3621,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-header" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685d70bba106e3dc276e7a056542b5f0682ba192bba9afde47c2c0cd55655fc7" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "indexmap", "rayon", @@ -3675,8 +3633,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-data" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8111c3baf730cb815b594fccefab73d52a7621e99a65c6298f98e9248db7a4" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "bytes", "serde_json", @@ -3687,8 +3644,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-subdag" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4e3831d8473ea7f5239f69a417c6bfc7d7a7531c544957b1ea94d9a7c75cc7" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "indexmap", "rayon", @@ -3703,8 +3659,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c2f87d46761bf5408f08f81c9a55adc09f84b58121344d892363efd3f246c9" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "bytes", "serde_json", @@ -3717,8 +3672,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission-id" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c7159701d1dc29c891bcfff338471fb1c331923a85338650c499a42dff52dd" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "snarkvm-console", "snarkvm-ledger-puzzle", @@ -3727,8 +3681,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "270240b6d6f04754b6d5fd22db59448b14a80fff11d92ffb897edaa169f58f08" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3748,8 +3701,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle-epoch" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3192db98219ba7abc3a11542c882a481efc3061973c38983aa67416e5d011a0" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3771,8 +3723,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-query" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61045a320a7fb64e43ecf3aa588277f0d7a9e5803c55d5e1b4d9bb6dea953fb2" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "async-trait", @@ -3789,8 +3740,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-store" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8dd8b8f01f14ef8683ec7ac8eaa23a18d78f7f7f93bc697c82df1eecdbc6a4b" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std-storage", "anyhow", @@ -3817,8 +3767,7 @@ dependencies = [ [[package]] name = "snarkvm-parameters" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3199f958582fccc99b949b8f8ba9c5da993f54d5281a62620fca7c25686e1465" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3840,8 +3789,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7224e637c7c9816bee7d3b2b844b558810fc716267d06fec1c08b9fda2696750" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3876,8 +3824,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-error" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "846083cbef396e56e9df9fdfe6cb5382c1cc2404cc83b498a1cf2d7c2fd2e860" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "anyhow", "snarkvm-circuit-environment", @@ -3889,8 +3836,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-process" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55f65479f0c1ab873f6e941b08cc027a0f92b40c6815cb116c793d7910bd7b1" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "colored", @@ -3916,8 +3862,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-program" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d568a98d96a400b4da9057a53c3f6f557c16d4533181a72e0e1d0e1e29e76c11" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "enum-iterator", "indexmap", @@ -3938,8 +3883,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-snark" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a0ab870d9ced282db29593e69021ccd4f11edc67580e35530daac2ac054444" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "bincode", "serde_json", @@ -3952,8 +3896,7 @@ dependencies = [ [[package]] name = "snarkvm-utilities" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01620a5549a87084e24478a253d98965277f4d963e14b462ad7eb57f698b6081" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "aleo-std", "anyhow", @@ -3976,8 +3919,7 @@ dependencies = [ [[package]] name = "snarkvm-utilities-derives" version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e90f015f504dc18b7faecc6e2056b90178af6511d4b15e412e76826635eedb" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" dependencies = [ "proc-macro2", "quote 1.0.46", diff --git a/Cargo.toml b/Cargo.toml index c4fded4..2938c1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,13 @@ reqwest = { version = "0.13", features = ["blocking", "json"] } self_update = { version = "0.41.0", features = ["archive-zip", "compression-zip-deflate"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -snarkvm = { version = "4.9.0", features = ["rocks", "test_consensus_heights", "dev_skip_checks", "test_targets", "history"] } +snarkvm = { git = "https://github.com/ProvableHQ/snarkVM.git", rev = "544566b3951aa775cddee57c69b6ae7693965b40", version = "4.9.0", features = [ + "rocks", + "test_consensus_heights", + "dev_skip_checks", + "test_targets", + "history", +] } tokio = { version = "1.52.3", features = ["full"] } tower-http = { version = "0.6.10", features = ["cors", "trace"] } tower_governor = "0.8" diff --git a/src/start.rs b/src/start.rs index 83da4a0..2246b51 100644 --- a/src/start.rs +++ b/src/start.rs @@ -14,13 +14,7 @@ use aleo_std_storage::StorageMode; use snarkvm::{ ledger::store::helpers::{memory::ConsensusMemory, rocksdb::ConsensusDB}, prelude::{ - Block, - FromBytes, - Ledger, - PrivateKey, - TEST_CONSENSUS_VERSION_HEIGHTS, - TestnetV0, - store::ConsensusStorage, + Block, FromBytes, Ledger, PrivateKey, TEST_CONSENSUS_VERSION_HEIGHTS, TestnetV0, store::ConsensusStorage, }, }; @@ -187,6 +181,15 @@ Please either: #[cfg(test)] mod tests { use super::*; + use crate::accounts::FUNDED_ACCOUNTS; + use snarkvm::{ + ledger::{authority::Authority, narwhal::Subdag}, + prelude::{ + Address, Certificate, ConsensusVersion, Deployment, Fee, Field, Network, Program, ProgramOwner, + Transaction, VerifyingKey, deployment_cost, + }, + }; + use std::sync::Arc; const VALID_PRIVATE_KEY: &str = "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH"; const INVALID_PRIVATE_KEY: &str = "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWa"; @@ -207,4 +210,99 @@ mod tests { fn test_valid_private_key_from_flag() { assert!(resolve_private_key(&Some(VALID_PRIVATE_KEY.to_string())).is_ok()); } + + #[test] + fn test_beacon_authority_enforces_block_limits() { + let private_key = resolve_private_key(&Some(VALID_PRIVATE_KEY.to_string())).unwrap(); + let mut rng = rand::rng(); + let authority = Authority::::new_beacon(&private_key, Field::from_u64(0), &mut rng).unwrap(); + let v16_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V16).unwrap(); + let v18_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V18).unwrap(); + + assert_eq!(authority.spend_limit(v16_height), Subdag::::min_spend_limit(v16_height)); + assert!(authority.spend_limit(v16_height).is_some()); + assert_eq!(authority.synthesis_limit(v16_height), None); + assert_eq!(authority.synthesis_limit(v18_height), Subdag::::min_synthesis_limit(v18_height)); + assert!(authority.synthesis_limit(v18_height).is_some()); + } + + fn placeholder_deployment( + ledger: &Ledger>, + private_key: &PrivateKey, + program_name: &str, + density: u64, + rng: &mut (impl rand::Rng + rand::CryptoRng), + ) -> Transaction { + const PLACEHOLDER_CERTIFICATE: &str = "certificate1qyqsqqqqqqqqqqxvwszp09v860w62s2l4g6eqf0kzppyax5we36957ywqm2dplzwvvlqg0kwlnmhzfatnax7uaqt7yqqqw0sc4u"; + + let program = Program::from_str(&format!( + "program {program_name}.aleo;\n\nfunction run:\n assert.eq true true;\n\nconstructor:\n assert.eq true true;\n" + )) + .unwrap(); + let function_name = *program.functions().keys().next().unwrap(); + let program_checksum = program.to_checksum(); + let mut circuit_key = TestnetV0::get_credits_verifying_key("fee_public".to_string()).unwrap().as_ref().clone(); + circuit_key.circuit_info.num_non_zero_a = usize::try_from(density).unwrap(); + circuit_key.circuit_info.num_non_zero_b = 0; + circuit_key.circuit_info.num_non_zero_c = 0; + let verifying_key = VerifyingKey::new(Arc::new(circuit_key), 1); + let certificate = Certificate::from_str(PLACEHOLDER_CERTIFICATE).unwrap(); + let owner_address = Address::try_from(private_key).unwrap(); + let deployment = Deployment::new( + 0, + program, + vec![(function_name, (verifying_key, certificate))], + Some(program_checksum), + Some(owner_address), + ) + .unwrap(); + + let deployment_id = deployment.to_deployment_id().unwrap(); + let owner = ProgramOwner::new(private_key, deployment_id, rng).unwrap(); + let consensus_version = TestnetV0::CONSENSUS_VERSION(ledger.latest_height() + 1).unwrap(); + let (base_fee, _) = deployment_cost(ledger.vm().process(), &deployment, consensus_version).unwrap(); + let authorization = ledger.vm().authorize_fee_public(private_key, base_fee, 0, deployment_id, rng).unwrap(); + let fee_transition = authorization.transitions().into_values().next().unwrap(); + let fee = Fee::from(fee_transition, ledger.latest_state_root(), None).unwrap(); + + Transaction::from_deployment(owner, deployment, fee).unwrap() + } + + #[test] + fn test_beacon_block_aborts_deployment_over_synthesis_limit() { + let genesis = Block::from_bytes_le(include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/resources/genesis_8d710d7e2_40val_snarkos_dev_network.bin" + ))) + .unwrap(); + let ledger: Ledger> = + Ledger::load(genesis, StorageMode::new_test(None)).unwrap(); + let beacon_key = PrivateKey::from_str(FUNDED_ACCOUNTS[0].1).unwrap(); + let mut rng = rand::rng(); + let v18_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V18).unwrap(); + + while ledger.latest_height() + 1 < v18_height { + let block = + ledger.prepare_advance_to_next_beacon_block(&beacon_key, vec![], vec![], vec![], &mut rng).unwrap(); + ledger.advance_to_next_block(&block).unwrap(); + } + + let synthesis_limit = Subdag::::min_synthesis_limit(v18_height).unwrap(); + let deployment_density = synthesis_limit / 2 + 1; + let first_key = PrivateKey::from_str(FUNDED_ACCOUNTS[1].1).unwrap(); + let second_key = PrivateKey::from_str(FUNDED_ACCOUNTS[2].1).unwrap(); + let first = placeholder_deployment(&ledger, &first_key, "limit_first", deployment_density, &mut rng); + let second = placeholder_deployment(&ledger, &second_key, "limit_second", deployment_density, &mut rng); + let first_id = first.id(); + let second_id = second.id(); + let block = ledger + .prepare_advance_to_next_beacon_block(&beacon_key, vec![], vec![], vec![first, second], &mut rng) + .unwrap(); + + assert_eq!(block.height(), v18_height); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().as_slice(), &[second_id]); + assert!(block.transactions().get(&first_id).is_some()); + } } From 731c3dcc0c5f2a1a8c8ab16fc82a3986d123d725 Mon Sep 17 00:00:00 2001 From: Mohammad Fawaz Date: Tue, 4 Aug 2026 11:04:59 -0400 Subject: [PATCH 2/5] return errors for aborted deployments --- docs/rest-api.md | 4 +- src/rest/routes.rs | 205 +++++++++++++++++++++++++++++++++++++++++++-- src/start.rs | 87 +------------------ 3 files changed, 201 insertions(+), 95 deletions(-) diff --git a/docs/rest-api.md b/docs/rest-api.md index 0ee2843..b1be735 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -43,7 +43,7 @@ curl -X POST http://127.0.0.1:3030/testnet/transaction/broadcast \ **When to use:** every time you want to commit a transaction. In **auto mode** (default) a successful broadcast *immediately mints one block* containing the transaction — nothing else is needed. In **`--manual-block-creation` mode** the transaction is only buffered; it does not land on the ledger until you call `POST /block/create`. -Returns `200` with the transaction ID on success. Failure modes: `400` (transaction exceeds the byte limit), `422` (malformed JSON body or failed validation), `429` (too many in-flight verifications — bounded per type by `VM::MAX_PARALLEL_EXECUTE_VERIFICATIONS` / `MAX_PARALLEL_DEPLOY_VERIFICATIONS`; retry with backoff). +Returns `200` with the transaction ID on success. In automatic mode, block preparation must accept the transaction before the devnode creates the block. The `/v2` route returns `422` if block preparation aborts the transaction. The legacy routes return `500` for this error. Other failure modes are `400` for a transaction that exceeds the byte limit, `422` for malformed JSON or failed validation, and `429` when too many verifications are active. ### `POST /block/create` — mint blocks on demand @@ -63,7 +63,7 @@ curl -X POST http://127.0.0.1:3030/testnet/block/create \ - In **`--manual-block-creation` mode**: this is how buffered broadcasts actually get committed. Broadcast N transactions, then call this once to seal them into a block. Use this when a test needs several transactions in a *single* block, or precise control over block boundaries/timing. - In **auto mode**: the buffer is always empty (broadcasts self-seal), so calling this just mints *empty* blocks — handy to advance height or trigger time/height-gated logic without any transactions. -Returns the last created block as JSON. `400` if `num_blocks` is `0` or exceeds `1000`. +Returns the last created block as JSON. The `/v2` route returns `422` if block preparation aborts a buffered transaction. The devnode removes each aborted transaction and keeps the other buffered transactions. It does not create a block for the failed request. The legacy routes return `500` for this error. The route returns `400` if `num_blocks` is `0` or exceeds `1000`. ### `POST /snapshot` — checkpoint the ledger (online) diff --git a/src/rest/routes.rs b/src/rest/routes.rs index 077c076..a82eb5a 100644 --- a/src/rest/routes.rs +++ b/src/rest/routes.rs @@ -7,7 +7,9 @@ use super::*; use crate::restore::snapshots_sibling_dir; use snarkvm::{ - prelude::{ConsensusVersion, Identifier, LimitedWriter, Plaintext, Program, ToBytes, Transaction, VM, Value}, + prelude::{ + Block, ConsensusVersion, Identifier, LimitedWriter, Plaintext, Program, ToBytes, Transaction, VM, Value, + }, synthesizer::program::{FinalizeGlobalState, StackTrait}, }; @@ -26,6 +28,19 @@ fn ledger_err(err: anyhow::Error) -> RestError { if err.to_string().contains("Missing") { RestError::not_found(err) } else { RestError::from(err) } } +/// Returns an error if block preparation aborted one or more transactions. +fn ensure_no_aborted_transactions(block: &Block) -> Result<(), RestError> { + let aborted_transaction_ids = block.aborted_transaction_ids(); + if aborted_transaction_ids.is_empty() { + return Ok(()); + } + + let transaction_ids = aborted_transaction_ids.iter().map(ToString::to_string).collect::>().join(", "); + Err(RestError::unprocessable_entity(anyhow!( + "Block preparation aborted the following transactions: {transaction_ids}" + ))) +} + /// Deserialize a CSV string into a vector of strings. fn de_csv<'de, D>(de: D) -> std::result::Result, D::Error> where @@ -545,13 +560,16 @@ impl> Rest { if !rest.manual_block_creation { // Prepare and advance in a single blocking task to prevent concurrent broadcasts // from both preparing a block at the same height and racing to advance the ledger. - tokio::task::spawn_blocking(move || { + tokio::task::spawn_blocking(move || -> Result<(), RestError> { let _guard = rest.block_creation_lock.lock(); let new_block = rest .ledger .prepare_advance_to_next_beacon_block(&rest.private_key, vec![], vec![], vec![tx], &mut rand::rng()) - .map_err(|e| anyhow!("{e}"))?; - rest.ledger.advance_to_next_block(&new_block).map_err(|e| anyhow!("{e}")) + .map_err(|e| RestError::internal_server_error(anyhow!("Failed to prepare block: {e}")))?; + ensure_no_aborted_transactions(&new_block)?; + rest.ledger + .advance_to_next_block(&new_block) + .map_err(|e| RestError::internal_server_error(anyhow!("Failed to advance block: {e}"))) }) .await .map_err(|e| RestError::internal_server_error(anyhow!("Task panicked: {}", e)))??; @@ -675,14 +693,15 @@ impl> Rest { let _guard = rest.block_creation_lock.lock(); let mut last_block = None; - // Take all unconfirmed transactions from the buffer. + // Copy all unconfirmed transactions from the buffer. Remove them only after the block advances. let mut unconfirmed_txs = Some({ - let mut buffer = rest.buffer.lock(); - buffer.drain(..).collect() + let buffer = rest.buffer.lock(); + buffer.clone() }); for _ in 0..num_blocks { let txs = unconfirmed_txs.take().unwrap_or_default(); + let num_txs = txs.len(); // Prepare the new block. Note that transactions in the buffer are added to the first block. // If there are no transactions left in the buffer, create an empty block. @@ -691,11 +710,22 @@ impl> Rest { .prepare_advance_to_next_beacon_block(&rest.private_key, vec![], vec![], txs, &mut rand::rng()) .map_err(|e| RestError::internal_server_error(anyhow!("Failed to prepare block: {}", e)))?; + if let Err(error) = ensure_no_aborted_transactions(&new_block) { + let aborted_transaction_ids = new_block.aborted_transaction_ids(); + rest.buffer.lock().retain(|tx| !aborted_transaction_ids.contains(&tx.id())); + return Err(error); + } + // Update the ledger to the new block. rest.ledger .advance_to_next_block(&new_block) .map_err(|e| RestError::internal_server_error(anyhow!("Failed to advance block: {}", e)))?; + // Remove the transactions that were committed. Transactions received during block creation remain buffered. + if num_txs > 0 { + rest.buffer.lock().drain(..num_txs); + } + last_block = Some(new_block); } @@ -802,3 +832,164 @@ impl> Rest { Ok(ErasedJson::new(output_strings)) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::accounts::FUNDED_ACCOUNTS; + use aleo_std_storage::StorageMode; + use axum::response::IntoResponse; + use snarkvm::{ + ledger::{narwhal::Subdag, store::helpers::memory::ConsensusMemory}, + prelude::{ + Address, Certificate, Deployment, Fee, FromBytes, Ledger, PrivateKey, ProgramOwner, TestnetV0, + VerifyingKey, deployment_cost, + }, + }; + use std::{str::FromStr, sync::Arc}; + + fn placeholder_deployment( + ledger: &Ledger>, + private_key: &PrivateKey, + program_name: &str, + density: u64, + rng: &mut (impl rand::Rng + rand::CryptoRng), + ) -> Transaction { + const PLACEHOLDER_CERTIFICATE: &str = "certificate1qyqsqqqqqqqqqqxvwszp09v860w62s2l4g6eqf0kzppyax5we36957ywqm2dplzwvvlqg0kwlnmhzfatnax7uaqt7yqqqw0sc4u"; + + let program = Program::from_str(&format!( + "program {program_name}.aleo;\n\nfunction run:\n assert.eq true true;\n\nconstructor:\n assert.eq true true;\n" + )) + .unwrap(); + let function_name = *program.functions().keys().next().unwrap(); + let program_checksum = program.to_checksum(); + let mut circuit_key = TestnetV0::get_credits_verifying_key("fee_public".to_string()).unwrap().as_ref().clone(); + circuit_key.circuit_info.num_non_zero_a = usize::try_from(density).unwrap(); + circuit_key.circuit_info.num_non_zero_b = 0; + circuit_key.circuit_info.num_non_zero_c = 0; + let verifying_key = VerifyingKey::new(Arc::new(circuit_key), 1); + let certificate = Certificate::from_str(PLACEHOLDER_CERTIFICATE).unwrap(); + let owner_address = Address::try_from(private_key).unwrap(); + let deployment = Deployment::new( + 0, + program, + vec![(function_name, (verifying_key, certificate))], + Some(program_checksum), + Some(owner_address), + ) + .unwrap(); + + let deployment_id = deployment.to_deployment_id().unwrap(); + let owner = ProgramOwner::new(private_key, deployment_id, rng).unwrap(); + let consensus_version = TestnetV0::CONSENSUS_VERSION(ledger.latest_height() + 1).unwrap(); + let (base_fee, _) = deployment_cost(ledger.vm().process(), &deployment, consensus_version).unwrap(); + let authorization = ledger.vm().authorize_fee_public(private_key, base_fee, 0, deployment_id, rng).unwrap(); + let fee_transition = authorization.transitions().into_values().next().unwrap(); + let fee = Fee::from(fee_transition, ledger.latest_state_root(), None).unwrap(); + + Transaction::from_deployment(owner, deployment, fee).unwrap() + } + + fn test_rest( + ledger: &Ledger>, + private_key: PrivateKey, + manual_block_creation: bool, + buffer: Vec>, + ) -> Rest> { + Rest { + ledger: ledger.clone(), + buffer: Arc::new(Mutex::new(buffer)), + handles: Default::default(), + num_verifying_deploys: Default::default(), + num_verifying_executions: Default::default(), + manual_block_creation, + private_key, + block_creation_lock: Default::default(), + shutdown_tx: Default::default(), + storage_path: None, + } + } + + #[test] + fn test_aborted_deployments_fail_block_requests() { + let genesis = Block::from_bytes_le(include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/resources/genesis_8d710d7e2_40val_snarkos_dev_network.bin" + ))) + .unwrap(); + let ledger: Ledger> = + Ledger::load(genesis, StorageMode::new_test(None)).unwrap(); + let beacon_key = PrivateKey::from_str(FUNDED_ACCOUNTS[0].1).unwrap(); + let mut rng = rand::rng(); + let v18_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V18).unwrap(); + + while ledger.latest_height() + 1 < v18_height { + let block = + ledger.prepare_advance_to_next_beacon_block(&beacon_key, vec![], vec![], vec![], &mut rng).unwrap(); + ledger.advance_to_next_block(&block).unwrap(); + } + + let synthesis_limit = Subdag::::min_synthesis_limit(v18_height).unwrap(); + let deployment_density = synthesis_limit / 2 + 1; + let first_key = PrivateKey::from_str(FUNDED_ACCOUNTS[1].1).unwrap(); + let second_key = PrivateKey::from_str(FUNDED_ACCOUNTS[2].1).unwrap(); + let first = placeholder_deployment(&ledger, &first_key, "limit_first", deployment_density, &mut rng); + let second = placeholder_deployment(&ledger, &second_key, "limit_second", deployment_density, &mut rng); + let first_id = first.id(); + let second_id = second.id(); + let block = ledger + .prepare_advance_to_next_beacon_block( + &beacon_key, + vec![], + vec![], + vec![first.clone(), second.clone()], + &mut rng, + ) + .unwrap(); + + assert_eq!(block.height(), v18_height); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().as_slice(), &[second_id]); + assert!(block.transactions().get(&first_id).is_some()); + + let oversized = + placeholder_deployment(&ledger, &first_key, "limit_oversized", synthesis_limit.saturating_add(1), &mut rng); + let initial_height = ledger.latest_height(); + let rest = test_rest(&ledger, beacon_key, false, vec![]); + let runtime = tokio::runtime::Runtime::new().unwrap(); + let response = runtime.block_on(async { + match Rest::transaction_broadcast( + State(rest), + Query(CheckTransaction { check_transaction: Some(false) }), + Ok(Json(oversized)), + ) + .await + { + Ok(_) => panic!("oversized deployment broadcast succeeded"), + Err(error) => error.into_response(), + } + }); + + assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); + assert_eq!(ledger.latest_height(), initial_height); + + let rest = test_rest(&ledger, beacon_key, true, vec![first, second]); + let response = runtime.block_on(async { + match Rest::create_block(State(rest.clone()), Json(CreateBlockRequest { num_blocks: Some(1) })).await { + Ok(_) => panic!("block creation accepted an aborted deployment"), + Err(error) => error.into_response(), + } + }); + + assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); + assert_eq!(ledger.latest_height(), initial_height); + assert_eq!(rest.buffer.lock().iter().map(Transaction::id).collect::>(), vec![first_id]); + + let _ = runtime + .block_on(Rest::create_block(State(rest.clone()), Json(CreateBlockRequest { num_blocks: Some(1) }))) + .expect("valid buffered deployment should create a block"); + assert_eq!(ledger.latest_height(), v18_height); + assert!(rest.buffer.lock().is_empty()); + } +} diff --git a/src/start.rs b/src/start.rs index 2246b51..4d9b07e 100644 --- a/src/start.rs +++ b/src/start.rs @@ -181,15 +181,10 @@ Please either: #[cfg(test)] mod tests { use super::*; - use crate::accounts::FUNDED_ACCOUNTS; use snarkvm::{ ledger::{authority::Authority, narwhal::Subdag}, - prelude::{ - Address, Certificate, ConsensusVersion, Deployment, Fee, Field, Network, Program, ProgramOwner, - Transaction, VerifyingKey, deployment_cost, - }, + prelude::{ConsensusVersion, Field, Network}, }; - use std::sync::Arc; const VALID_PRIVATE_KEY: &str = "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH"; const INVALID_PRIVATE_KEY: &str = "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWa"; @@ -225,84 +220,4 @@ mod tests { assert_eq!(authority.synthesis_limit(v18_height), Subdag::::min_synthesis_limit(v18_height)); assert!(authority.synthesis_limit(v18_height).is_some()); } - - fn placeholder_deployment( - ledger: &Ledger>, - private_key: &PrivateKey, - program_name: &str, - density: u64, - rng: &mut (impl rand::Rng + rand::CryptoRng), - ) -> Transaction { - const PLACEHOLDER_CERTIFICATE: &str = "certificate1qyqsqqqqqqqqqqxvwszp09v860w62s2l4g6eqf0kzppyax5we36957ywqm2dplzwvvlqg0kwlnmhzfatnax7uaqt7yqqqw0sc4u"; - - let program = Program::from_str(&format!( - "program {program_name}.aleo;\n\nfunction run:\n assert.eq true true;\n\nconstructor:\n assert.eq true true;\n" - )) - .unwrap(); - let function_name = *program.functions().keys().next().unwrap(); - let program_checksum = program.to_checksum(); - let mut circuit_key = TestnetV0::get_credits_verifying_key("fee_public".to_string()).unwrap().as_ref().clone(); - circuit_key.circuit_info.num_non_zero_a = usize::try_from(density).unwrap(); - circuit_key.circuit_info.num_non_zero_b = 0; - circuit_key.circuit_info.num_non_zero_c = 0; - let verifying_key = VerifyingKey::new(Arc::new(circuit_key), 1); - let certificate = Certificate::from_str(PLACEHOLDER_CERTIFICATE).unwrap(); - let owner_address = Address::try_from(private_key).unwrap(); - let deployment = Deployment::new( - 0, - program, - vec![(function_name, (verifying_key, certificate))], - Some(program_checksum), - Some(owner_address), - ) - .unwrap(); - - let deployment_id = deployment.to_deployment_id().unwrap(); - let owner = ProgramOwner::new(private_key, deployment_id, rng).unwrap(); - let consensus_version = TestnetV0::CONSENSUS_VERSION(ledger.latest_height() + 1).unwrap(); - let (base_fee, _) = deployment_cost(ledger.vm().process(), &deployment, consensus_version).unwrap(); - let authorization = ledger.vm().authorize_fee_public(private_key, base_fee, 0, deployment_id, rng).unwrap(); - let fee_transition = authorization.transitions().into_values().next().unwrap(); - let fee = Fee::from(fee_transition, ledger.latest_state_root(), None).unwrap(); - - Transaction::from_deployment(owner, deployment, fee).unwrap() - } - - #[test] - fn test_beacon_block_aborts_deployment_over_synthesis_limit() { - let genesis = Block::from_bytes_le(include_bytes!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/resources/genesis_8d710d7e2_40val_snarkos_dev_network.bin" - ))) - .unwrap(); - let ledger: Ledger> = - Ledger::load(genesis, StorageMode::new_test(None)).unwrap(); - let beacon_key = PrivateKey::from_str(FUNDED_ACCOUNTS[0].1).unwrap(); - let mut rng = rand::rng(); - let v18_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V18).unwrap(); - - while ledger.latest_height() + 1 < v18_height { - let block = - ledger.prepare_advance_to_next_beacon_block(&beacon_key, vec![], vec![], vec![], &mut rng).unwrap(); - ledger.advance_to_next_block(&block).unwrap(); - } - - let synthesis_limit = Subdag::::min_synthesis_limit(v18_height).unwrap(); - let deployment_density = synthesis_limit / 2 + 1; - let first_key = PrivateKey::from_str(FUNDED_ACCOUNTS[1].1).unwrap(); - let second_key = PrivateKey::from_str(FUNDED_ACCOUNTS[2].1).unwrap(); - let first = placeholder_deployment(&ledger, &first_key, "limit_first", deployment_density, &mut rng); - let second = placeholder_deployment(&ledger, &second_key, "limit_second", deployment_density, &mut rng); - let first_id = first.id(); - let second_id = second.id(); - let block = ledger - .prepare_advance_to_next_beacon_block(&beacon_key, vec![], vec![], vec![first, second], &mut rng) - .unwrap(); - - assert_eq!(block.height(), v18_height); - assert_eq!(block.transactions().num_accepted(), 1); - assert_eq!(block.transactions().num_rejected(), 0); - assert_eq!(block.aborted_transaction_ids().as_slice(), &[second_id]); - assert!(block.transactions().get(&first_id).is_some()); - } } From 609f796bf49878f441b602bbef22f34c5f816f6e Mon Sep 17 00:00:00 2001 From: Mohammad Fawaz Date: Tue, 4 Aug 2026 12:06:26 -0400 Subject: [PATCH 3/5] enforce limits on snarkvm 4.9.0 --- Cargo.lock | 174 ++++++++++++++++--------- Cargo.toml | 8 +- docs/rest-api.md | 4 +- src/rest/routes.rs | 319 +++++++++++++++++++++++++++++++++++++++++---- src/start.rs | 22 +--- 5 files changed, 420 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d36582..b55eba9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3051,7 +3051,8 @@ dependencies = [ [[package]] name = "snarkvm" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea37705e6ba5f11a8da0f61393ba14aa320fcaf9fb410dff835c396ba20283a" dependencies = [ "anyhow", "dotenvy", @@ -3071,7 +3072,8 @@ dependencies = [ [[package]] name = "snarkvm-algorithms" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d54fee12c2bb1c58ef9a46be861f4b0b07285046b67918ce8ca61757d9a70" dependencies = [ "aleo-std", "anyhow", @@ -3098,7 +3100,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e67a5337192cb95713736c724e4209c82b73c8ca2208033b80efc9d9e0d1dfe" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -3112,7 +3115,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-account" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f096425d431e6f3b6bd190756016464cee1627435d043ee1edcd2fd368a96e5d" dependencies = [ "snarkvm-circuit-network", "snarkvm-circuit-types", @@ -3122,7 +3126,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-algorithms" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3620f97ce1946468e0771bf6f5c2cd4cad53835e65a6369556813e364e61f26e" dependencies = [ "snarkvm-circuit-types", "snarkvm-console-algorithms", @@ -3132,7 +3137,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-collections" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb124eb7120d08fdf493248a1b0a992549b6c3c0d6a5952f7ccd4cfb39f9e88" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-types", @@ -3142,7 +3148,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eedb2cc4f93b8ecda8c1f05a4faaac10e55127f0fc09d7749dfc610d4bcbaa0f" dependencies = [ "anyhow", "indexmap", @@ -3162,12 +3169,14 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment-witness" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2351fbdbb775fc850617ab0043b1b0033a47a6151b5bf516cc49c3c883b08a3" [[package]] name = "snarkvm-circuit-network" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "292c9506df0d1ec32dd4ef58d52e56716b6ccd3ca4ce4769852afeeb47856b5e" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-collections", @@ -3178,7 +3187,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-program" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df200abab8279b37fc386fb419e0bcdb83efa8ba291e8d62a893427d7f23d4b1" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -3192,7 +3202,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f0060b2c07f80a26b0f9547ef040f47b1c37c6aa5adb1983a19c144e091518" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-address", @@ -3207,7 +3218,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-address" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f104b0d3c7637f37d8abeb743c8ba31a518127ce0117b190879e0fac48c933d0" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3220,7 +3232,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-boolean" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad042be95bb0b5c9545ac3a12f9f3fde852f1167481d47d1c13a3aae3cdcdb9" dependencies = [ "snarkvm-circuit-environment", "snarkvm-console-types-boolean", @@ -3229,7 +3242,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-field" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d5d37de0ae246a7f734c1d897c4b8eb9f5df7a1fdddf420ac65d3b64a4bcf5" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3239,7 +3253,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-group" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dcf26d059063dc16a37f3a923583c66899ec13d52a0e86c8fa141d78e776e02" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3251,7 +3266,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-integers" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4d83fd4b20ee4f964bb1c40459d67e0741872f56197898b45df8e86e639926c" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3263,7 +3279,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-scalar" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8b1a4e94e49487f02d8b308e03d6c56f50dbb5a1441ad3a74f04f6ba745b4b" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3274,7 +3291,8 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-string" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "665506fbf883d0aa0b152b06b324a609841742064a88dc9a355753ed90da57d8" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -3286,7 +3304,8 @@ dependencies = [ [[package]] name = "snarkvm-console" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b611f443daa6140f2c5bbdf5d184567f2b88cf73be5d7160500c3a5d56ca209f" dependencies = [ "snarkvm-console-account", "snarkvm-console-algorithms", @@ -3299,7 +3318,8 @@ dependencies = [ [[package]] name = "snarkvm-console-account" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adbf603ba5930c02d18bdd748c14418c2bbaf4bf6041f786571d510eac5db21" dependencies = [ "bs58", "snarkvm-console-network", @@ -3310,7 +3330,8 @@ dependencies = [ [[package]] name = "snarkvm-console-algorithms" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb693083ea8c9d1ed2a71880730b7251410aa45003602c16f89fbcda8b9ba860" dependencies = [ "blake2s_simd", "hex", @@ -3327,7 +3348,8 @@ dependencies = [ [[package]] name = "snarkvm-console-collections" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad460b844a736bae3f4fadb393313d2c2c7cdbdce3d228d8c339cec387251011" dependencies = [ "aleo-std", "parking_lot", @@ -3340,7 +3362,8 @@ dependencies = [ [[package]] name = "snarkvm-console-network" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97bc1b423cf6304ab4f35a71b995be7bf9c5429bed1f92578a212c933b161f84" dependencies = [ "anyhow", "enum-iterator", @@ -3360,7 +3383,8 @@ dependencies = [ [[package]] name = "snarkvm-console-network-environment" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "272b60c9c736f7cc4aec0ad66ff960ddaa575657e4c5fcc6a69207ba60fb19cc" dependencies = [ "anyhow", "bech32", @@ -3378,7 +3402,8 @@ dependencies = [ [[package]] name = "snarkvm-console-program" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26501fe0d11bb0601267efb42ca51c495ad86793878a1747cf16ed097b0f1342" dependencies = [ "enum-iterator", "enum_index", @@ -3399,7 +3424,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da6c236d32f2f37b430d4d6ef134ff9395cb35f16c8af6bd4e0fb388ae1195f7" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-address", @@ -3414,7 +3440,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-address" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ee19a161735abffdea99051ed7200c0fae13201ab57dc2f375a9403bd1bb11" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3425,7 +3452,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-boolean" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649f21d68e74d94c28936fd01b53e2acd7d26c31d01a894497bbf6f41b05c4bd" dependencies = [ "snarkvm-console-network-environment", ] @@ -3433,7 +3461,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-field" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a004d12492258c3e6e9847d8b6b2462c3c03721c5f643c338a93f08f97ef3ad" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3443,7 +3472,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-group" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977fcf939d3d2f1398d041ede04dd1ed4eed82febc6ea91e41e0ef26d1a11b01" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3454,7 +3484,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-integers" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ceaca4e72d54890d115a05d3798c5d3d8e785aedf471cb5d47aa80ac3a7169b" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3465,7 +3496,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-scalar" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50234ae5b7cbeb042d5c768d821c555b649df36f3c0bbf5d2d053639a67274b0" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3476,7 +3508,8 @@ dependencies = [ [[package]] name = "snarkvm-console-types-string" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b42f0e1b1730ab805ba02c4a2f30a31bdd62600301d23913399675aa896346" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -3487,7 +3520,8 @@ dependencies = [ [[package]] name = "snarkvm-curves" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7e845865d40b36069fa76ef88a9e78f7f9c33f64c4e19f7cfd601922fab702" dependencies = [ "rand 0.10.1", "rustc_version", @@ -3500,7 +3534,8 @@ dependencies = [ [[package]] name = "snarkvm-fields" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4121086d60733b44bba6a7cb56c8b740d38257326bc86bc74ec96b92b6952c47" dependencies = [ "aleo-std", "anyhow", @@ -3517,7 +3552,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8509cbe5ca45ce545db05a3fb706422770c01515f2f92065faaf7b10a30a52" dependencies = [ "aleo-std", "anyhow", @@ -3547,7 +3583,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-authority" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e32462f86a9cb94444976c434c527ed5b10759d434e03f1196c3b02a2823b53" dependencies = [ "anyhow", "rand 0.10.1", @@ -3559,7 +3596,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-block" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a29e2ba2899708c5ed75c38fa240b90ef1c93b09666d294f7d70d7f0fd6c7d" dependencies = [ "anyhow", "indexmap", @@ -3583,7 +3621,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-committee" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c6eb6a7fde1b507454297556a66db81423201d351e1806c13408ee94cde0889" dependencies = [ "indexmap", "rayon", @@ -3595,7 +3634,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5c565c1efc362a10db86b29a3c1337ecb66a028b3e1d6b8ff2318640e4233b" dependencies = [ "snarkvm-ledger-narwhal-batch-certificate", "snarkvm-ledger-narwhal-batch-header", @@ -3608,7 +3648,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-certificate" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2239748ed6c1259ccc2ee221a2efc0c7567f9c4e7cacf5d3580a6423bbe5438" dependencies = [ "indexmap", "rayon", @@ -3621,7 +3662,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-header" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685d70bba106e3dc276e7a056542b5f0682ba192bba9afde47c2c0cd55655fc7" dependencies = [ "indexmap", "rayon", @@ -3633,7 +3675,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-data" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8111c3baf730cb815b594fccefab73d52a7621e99a65c6298f98e9248db7a4" dependencies = [ "bytes", "serde_json", @@ -3644,7 +3687,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-subdag" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4e3831d8473ea7f5239f69a417c6bfc7d7a7531c544957b1ea94d9a7c75cc7" dependencies = [ "indexmap", "rayon", @@ -3659,7 +3703,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c2f87d46761bf5408f08f81c9a55adc09f84b58121344d892363efd3f246c9" dependencies = [ "bytes", "serde_json", @@ -3672,7 +3717,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission-id" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c7159701d1dc29c891bcfff338471fb1c331923a85338650c499a42dff52dd" dependencies = [ "snarkvm-console", "snarkvm-ledger-puzzle", @@ -3681,7 +3727,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "270240b6d6f04754b6d5fd22db59448b14a80fff11d92ffb897edaa169f58f08" dependencies = [ "aleo-std", "anyhow", @@ -3701,7 +3748,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle-epoch" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3192db98219ba7abc3a11542c882a481efc3061973c38983aa67416e5d011a0" dependencies = [ "aleo-std", "anyhow", @@ -3723,7 +3771,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-query" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61045a320a7fb64e43ecf3aa588277f0d7a9e5803c55d5e1b4d9bb6dea953fb2" dependencies = [ "anyhow", "async-trait", @@ -3740,7 +3789,8 @@ dependencies = [ [[package]] name = "snarkvm-ledger-store" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8dd8b8f01f14ef8683ec7ac8eaa23a18d78f7f7f93bc697c82df1eecdbc6a4b" dependencies = [ "aleo-std-storage", "anyhow", @@ -3767,7 +3817,8 @@ dependencies = [ [[package]] name = "snarkvm-parameters" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3199f958582fccc99b949b8f8ba9c5da993f54d5281a62620fca7c25686e1465" dependencies = [ "aleo-std", "anyhow", @@ -3789,7 +3840,8 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7224e637c7c9816bee7d3b2b844b558810fc716267d06fec1c08b9fda2696750" dependencies = [ "aleo-std", "anyhow", @@ -3824,7 +3876,8 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-error" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "846083cbef396e56e9df9fdfe6cb5382c1cc2404cc83b498a1cf2d7c2fd2e860" dependencies = [ "anyhow", "snarkvm-circuit-environment", @@ -3836,7 +3889,8 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-process" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55f65479f0c1ab873f6e941b08cc027a0f92b40c6815cb116c793d7910bd7b1" dependencies = [ "aleo-std", "colored", @@ -3862,7 +3916,8 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-program" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d568a98d96a400b4da9057a53c3f6f557c16d4533181a72e0e1d0e1e29e76c11" dependencies = [ "enum-iterator", "indexmap", @@ -3883,7 +3938,8 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-snark" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a0ab870d9ced282db29593e69021ccd4f11edc67580e35530daac2ac054444" dependencies = [ "bincode", "serde_json", @@ -3896,7 +3952,8 @@ dependencies = [ [[package]] name = "snarkvm-utilities" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01620a5549a87084e24478a253d98965277f4d963e14b462ad7eb57f698b6081" dependencies = [ "aleo-std", "anyhow", @@ -3919,7 +3976,8 @@ dependencies = [ [[package]] name = "snarkvm-utilities-derives" version = "4.9.0" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=544566b3951aa775cddee57c69b6ae7693965b40#544566b3951aa775cddee57c69b6ae7693965b40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e90f015f504dc18b7faecc6e2056b90178af6511d4b15e412e76826635eedb" dependencies = [ "proc-macro2", "quote 1.0.46", diff --git a/Cargo.toml b/Cargo.toml index 2938c1e..c4fded4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,13 +21,7 @@ reqwest = { version = "0.13", features = ["blocking", "json"] } self_update = { version = "0.41.0", features = ["archive-zip", "compression-zip-deflate"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -snarkvm = { git = "https://github.com/ProvableHQ/snarkVM.git", rev = "544566b3951aa775cddee57c69b6ae7693965b40", version = "4.9.0", features = [ - "rocks", - "test_consensus_heights", - "dev_skip_checks", - "test_targets", - "history", -] } +snarkvm = { version = "4.9.0", features = ["rocks", "test_consensus_heights", "dev_skip_checks", "test_targets", "history"] } tokio = { version = "1.52.3", features = ["full"] } tower-http = { version = "0.6.10", features = ["cors", "trace"] } tower_governor = "0.8" diff --git a/docs/rest-api.md b/docs/rest-api.md index b1be735..a6f5531 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -43,7 +43,7 @@ curl -X POST http://127.0.0.1:3030/testnet/transaction/broadcast \ **When to use:** every time you want to commit a transaction. In **auto mode** (default) a successful broadcast *immediately mints one block* containing the transaction — nothing else is needed. In **`--manual-block-creation` mode** the transaction is only buffered; it does not land on the ledger until you call `POST /block/create`. -Returns `200` with the transaction ID on success. In automatic mode, block preparation must accept the transaction before the devnode creates the block. The `/v2` route returns `422` if block preparation aborts the transaction. The legacy routes return `500` for this error. Other failure modes are `400` for a transaction that exceeds the byte limit, `422` for malformed JSON or failed validation, and `429` when too many verifications are active. +Returns `200` with the transaction ID on success. In automatic mode, the transaction must comply with the beacon block spend limit from consensus V16 and the beacon block synthesis limit from consensus V18. The devnode does not create a block when the transaction exceeds a limit. The `/v2` route returns `422` if block preparation aborts the transaction. The legacy routes return `500` for this error. Other failure modes are `400` for a transaction that exceeds the byte limit, `422` for malformed JSON or failed validation, and `429` when too many verifications are active. ### `POST /block/create` — mint blocks on demand @@ -63,7 +63,7 @@ curl -X POST http://127.0.0.1:3030/testnet/block/create \ - In **`--manual-block-creation` mode**: this is how buffered broadcasts actually get committed. Broadcast N transactions, then call this once to seal them into a block. Use this when a test needs several transactions in a *single* block, or precise control over block boundaries/timing. - In **auto mode**: the buffer is always empty (broadcasts self-seal), so calling this just mints *empty* blocks — handy to advance height or trigger time/height-gated logic without any transactions. -Returns the last created block as JSON. The `/v2` route returns `422` if block preparation aborts a buffered transaction. The devnode removes each aborted transaction and keeps the other buffered transactions. It does not create a block for the failed request. The legacy routes return `500` for this error. The route returns `400` if `num_blocks` is `0` or exceeds `1000`. +Returns the last created block as JSON. The beacon block spend and synthesis limits apply to all buffered transactions in transaction order. The `/v2` route returns `422` if block preparation aborts a buffered transaction. The devnode removes each aborted transaction and keeps the other buffered transactions. It does not create a block for the failed request. The legacy routes return `500` for this error. The route returns `400` if `num_blocks` is `0` or exceeds `1000`. ### `POST /snapshot` — checkpoint the ledger (online) diff --git a/src/rest/routes.rs b/src/rest/routes.rs index a82eb5a..e22d6bb 100644 --- a/src/rest/routes.rs +++ b/src/rest/routes.rs @@ -7,10 +7,14 @@ use super::*; use crate::restore::snapshots_sibling_dir; use snarkvm::{ + ledger::narwhal::BatchHeader, prelude::{ Block, ConsensusVersion, Identifier, LimitedWriter, Plaintext, Program, ToBytes, Transaction, VM, Value, }, - synthesizer::program::{FinalizeGlobalState, StackTrait}, + synthesizer::{ + process::transaction_compute_spend_in_microcredits, + program::{FinalizeGlobalState, StackTrait}, + }, }; use axum::{Json, extract::rejection::JsonRejection}; @@ -28,9 +32,195 @@ fn ledger_err(err: anyhow::Error) -> RestError { if err.to_string().contains("Missing") { RestError::not_found(err) } else { RestError::from(err) } } +/// Returns the spend and synthesis limits for a minimally dense beacon block. +fn beacon_block_limits(block_height: u32) -> anyhow::Result<(Option, Option)> { + let consensus_version = N::CONSENSUS_VERSION(block_height)?; + let max_certificates = active_consensus_value(&N::MAX_CERTIFICATES, consensus_version) + .map(u64::from) + .ok_or_else(|| anyhow!("Missing MAX_CERTIFICATES for consensus version {consensus_version}"))?; + let min_certificates = max_certificates.saturating_add(2).saturating_div(3).saturating_mul(2); + + let spend_limit = if consensus_version >= ConsensusVersion::V16 { + Some(min_certificates.saturating_mul(BatchHeader::::batch_spend_limit(block_height))) + } else { + None + }; + let synthesis_limit = if consensus_version >= ConsensusVersion::V18 { + let synthesis_per_round = 5_f64 * N::SYNTHESIS_PER_SECOND_OF_RUNTIME as f64; + let synthesis_per_certificate = synthesis_per_round / max_certificates as f64; + Some((synthesis_per_certificate * min_certificates as f64) as u64) + } else { + None + }; + + Ok((spend_limit, synthesis_limit)) +} + +/// Returns the value that applies at the given consensus version. +fn active_consensus_value(values: &[(ConsensusVersion, T)], consensus_version: ConsensusVersion) -> Option { + values.iter().rfind(|(version, _)| *version <= consensus_version).map(|(_, value)| *value) +} + +/// Removes transactions that exceed a transaction or block synthesis limit. +fn filter_preparation_limits>( + ledger: &Ledger, + block_height: u32, + transactions: &[Transaction], +) -> Result<(Vec<(Transaction, u64)>, Vec), RestError> { + let consensus_version = N::CONSENSUS_VERSION(block_height) + .map_err(|error| RestError::internal_server_error(error.context("Failed to determine consensus version")))?; + if consensus_version < ConsensusVersion::V16 { + return Ok((transactions.iter().cloned().map(|transaction| (transaction, 0)).collect(), Vec::new())); + } + + let transaction_spend_limit = + active_consensus_value(&N::TRANSACTION_SPEND_LIMIT, consensus_version).ok_or_else(|| { + RestError::internal_server_error(anyhow!("Missing transaction spend limit for {consensus_version}")) + })?; + let synthesis_limit = beacon_block_limits::(block_height) + .map_err(|error| RestError::internal_server_error(error.context("Failed to calculate beacon block limits")))? + .1; + let mut block_combined_density = 0u64; + let mut candidates = Vec::with_capacity(transactions.len()); + let mut aborted_transaction_ids = Vec::new(); + + for transaction in transactions { + let Ok(compute_spend) = + transaction_compute_spend_in_microcredits(ledger.vm().process(), transaction, consensus_version) + else { + aborted_transaction_ids.push(transaction.id()); + continue; + }; + if compute_spend > transaction_spend_limit { + aborted_transaction_ids.push(transaction.id()); + continue; + } + if let (Some(synthesis_limit), Some(deployment)) = (synthesis_limit, transaction.deployment()) { + let density = deployment.combined_density(); + if block_combined_density.saturating_add(density) > synthesis_limit { + aborted_transaction_ids.push(transaction.id()); + continue; + } + block_combined_density = block_combined_density.saturating_add(density); + } + candidates.push((transaction.clone(), compute_spend)); + } + + Ok((candidates, aborted_transaction_ids)) +} + +/// Removes transactions that exceed the cumulative block spend limit. +fn filter_block_spend_limit( + transactions: &[(Transaction, u64)], + spend_limit: Option, +) -> (Vec>, Vec) { + let mut block_spend = 0u64; + let mut candidates = Vec::with_capacity(transactions.len()); + let mut aborted_transaction_ids = Vec::new(); + + for (transaction, compute_spend) in transactions { + if spend_limit.is_some_and(|limit| block_spend.saturating_add(*compute_spend) > limit) { + aborted_transaction_ids.push(transaction.id()); + continue; + } + block_spend = block_spend.saturating_add(*compute_spend); + candidates.push(transaction.clone()); + } + + (candidates, aborted_transaction_ids) +} + +/// Adds aborted IDs that belong to the candidate transaction list. +fn extend_snarkvm_aborted_transaction_ids( + transactions: &[Transaction], + new_transaction_ids: &[N::TransactionID], + aborted_transaction_ids: &mut Vec, +) -> Result<(), RestError> { + let previous_len = aborted_transaction_ids.len(); + for transaction_id in new_transaction_ids { + if transactions.iter().any(|transaction| transaction.id() == *transaction_id) + && !aborted_transaction_ids.contains(transaction_id) + { + aborted_transaction_ids.push(*transaction_id); + } + } + if aborted_transaction_ids.len() == previous_len { + return Err(RestError::internal_server_error(anyhow!( + "Block preparation returned an unknown aborted transaction" + ))); + } + Ok(()) +} + +/// Prepares a beacon block and enforces the limits that snarkVM 4.9.0 skips for beacon blocks. +fn prepare_beacon_block_with_limits, R: rand::Rng + rand::CryptoRng>( + ledger: &Ledger, + private_key: &PrivateKey, + transactions: Vec>, + rng: &mut R, +) -> Result<(Block, Vec), RestError> { + let block_height = ledger.latest_height().saturating_add(1); + let (spend_limit, _) = beacon_block_limits::(block_height) + .map_err(|error| RestError::internal_server_error(error.context("Failed to calculate beacon block limits")))?; + let mut snarkvm_aborted_transaction_ids = Vec::new(); + + loop { + let active_transactions = transactions + .iter() + .filter(|transaction| !snarkvm_aborted_transaction_ids.contains(&transaction.id())) + .cloned() + .collect::>(); + let (preparation_candidates, preparation_aborted_transaction_ids) = + filter_preparation_limits(ledger, block_height, &active_transactions)?; + let candidate_transactions = + preparation_candidates.iter().map(|(transaction, _)| transaction.clone()).collect::>(); + let prepared_block = ledger + .prepare_advance_to_next_beacon_block(private_key, vec![], vec![], candidate_transactions, rng) + .map_err(|error| RestError::internal_server_error(anyhow!("Failed to prepare block: {error}")))?; + + if !prepared_block.aborted_transaction_ids().is_empty() { + extend_snarkvm_aborted_transaction_ids( + &transactions, + prepared_block.aborted_transaction_ids(), + &mut snarkvm_aborted_transaction_ids, + )?; + continue; + } + + let (spend_candidates, spend_aborted_transaction_ids) = + filter_block_spend_limit(&preparation_candidates, spend_limit); + let final_block = if spend_aborted_transaction_ids.is_empty() { + prepared_block + } else { + ledger + .prepare_advance_to_next_beacon_block(private_key, vec![], vec![], spend_candidates, rng) + .map_err(|error| RestError::internal_server_error(anyhow!("Failed to prepare block: {error}")))? + }; + + if !final_block.aborted_transaction_ids().is_empty() { + extend_snarkvm_aborted_transaction_ids( + &transactions, + final_block.aborted_transaction_ids(), + &mut snarkvm_aborted_transaction_ids, + )?; + continue; + } + + let aborted_transaction_ids = transactions + .iter() + .filter(|transaction| { + snarkvm_aborted_transaction_ids.contains(&transaction.id()) + || preparation_aborted_transaction_ids.contains(&transaction.id()) + || spend_aborted_transaction_ids.contains(&transaction.id()) + }) + .map(Transaction::id) + .collect(); + return Ok((final_block, aborted_transaction_ids)); + } +} + /// Returns an error if block preparation aborted one or more transactions. -fn ensure_no_aborted_transactions(block: &Block) -> Result<(), RestError> { - let aborted_transaction_ids = block.aborted_transaction_ids(); +fn ensure_no_aborted_transactions(aborted_transaction_ids: &[T]) -> Result<(), RestError> { if aborted_transaction_ids.is_empty() { return Ok(()); } @@ -562,11 +752,9 @@ impl> Rest { // from both preparing a block at the same height and racing to advance the ledger. tokio::task::spawn_blocking(move || -> Result<(), RestError> { let _guard = rest.block_creation_lock.lock(); - let new_block = rest - .ledger - .prepare_advance_to_next_beacon_block(&rest.private_key, vec![], vec![], vec![tx], &mut rand::rng()) - .map_err(|e| RestError::internal_server_error(anyhow!("Failed to prepare block: {e}")))?; - ensure_no_aborted_transactions(&new_block)?; + let (new_block, aborted_transaction_ids) = + prepare_beacon_block_with_limits(&rest.ledger, &rest.private_key, vec![tx], &mut rand::rng())?; + ensure_no_aborted_transactions(&aborted_transaction_ids)?; rest.ledger .advance_to_next_block(&new_block) .map_err(|e| RestError::internal_server_error(anyhow!("Failed to advance block: {e}"))) @@ -705,13 +893,9 @@ impl> Rest { // Prepare the new block. Note that transactions in the buffer are added to the first block. // If there are no transactions left in the buffer, create an empty block. - let new_block = rest - .ledger - .prepare_advance_to_next_beacon_block(&rest.private_key, vec![], vec![], txs, &mut rand::rng()) - .map_err(|e| RestError::internal_server_error(anyhow!("Failed to prepare block: {}", e)))?; - - if let Err(error) = ensure_no_aborted_transactions(&new_block) { - let aborted_transaction_ids = new_block.aborted_transaction_ids(); + let (new_block, aborted_transaction_ids) = + prepare_beacon_block_with_limits(&rest.ledger, &rest.private_key, txs, &mut rand::rng())?; + if let Err(error) = ensure_no_aborted_transactions(&aborted_transaction_ids) { rest.buffer.lock().retain(|tx| !aborted_transaction_ids.contains(&tx.id())); return Err(error); } @@ -840,7 +1024,7 @@ mod tests { use aleo_std_storage::StorageMode; use axum::response::IntoResponse; use snarkvm::{ - ledger::{narwhal::Subdag, store::helpers::memory::ConsensusMemory}, + ledger::store::helpers::memory::ConsensusMemory, prelude::{ Address, Certificate, Deployment, Fee, FromBytes, Ledger, PrivateKey, ProgramOwner, TestnetV0, VerifyingKey, deployment_cost, @@ -910,6 +1094,31 @@ mod tests { } } + #[test] + fn test_beacon_block_limits_match_v18_minimum_subdag() { + let v15_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V15).unwrap(); + let v16_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V16).unwrap(); + let v18_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V18).unwrap(); + assert_eq!(beacon_block_limits::(v15_height).unwrap(), (None, None)); + + let (spend_limit, synthesis_limit) = beacon_block_limits::(v16_height).unwrap(); + assert!(spend_limit.is_some()); + assert_eq!(synthesis_limit, None); + + let max_certificates = TestnetV0::MAX_CERTIFICATES.last().unwrap().1 as u64; + let min_certificates = max_certificates.saturating_add(2).saturating_div(3).saturating_mul(2); + let expected_spend_limit = + min_certificates.saturating_mul(BatchHeader::::batch_spend_limit(v18_height)); + let expected_synthesis_limit = ((5_f64 * TestnetV0::SYNTHESIS_PER_SECOND_OF_RUNTIME as f64 + / max_certificates as f64) + * min_certificates as f64) as u64; + + assert_eq!( + beacon_block_limits::(v18_height).unwrap(), + (Some(expected_spend_limit), Some(expected_synthesis_limit)) + ); + } + #[test] fn test_aborted_deployments_fail_block_requests() { let genesis = Block::from_bytes_le(include_bytes!(concat!( @@ -929,38 +1138,95 @@ mod tests { ledger.advance_to_next_block(&block).unwrap(); } - let synthesis_limit = Subdag::::min_synthesis_limit(v18_height).unwrap(); - let deployment_density = synthesis_limit / 2 + 1; + let synthesis_limit = beacon_block_limits::(v18_height).unwrap().1.unwrap(); + let deployment_density = synthesis_limit.saturating_mul(3).saturating_div(5); + let remaining_density = synthesis_limit.saturating_sub(deployment_density); let first_key = PrivateKey::from_str(FUNDED_ACCOUNTS[1].1).unwrap(); let second_key = PrivateKey::from_str(FUNDED_ACCOUNTS[2].1).unwrap(); + let third_key = PrivateKey::from_str(FUNDED_ACCOUNTS[3].1).unwrap(); let first = placeholder_deployment(&ledger, &first_key, "limit_first", deployment_density, &mut rng); let second = placeholder_deployment(&ledger, &second_key, "limit_second", deployment_density, &mut rng); + let third = placeholder_deployment(&ledger, &third_key, "limit_third", remaining_density, &mut rng); let first_id = first.id(); let second_id = second.id(); + let third_id = third.id(); let block = ledger .prepare_advance_to_next_beacon_block( &beacon_key, vec![], vec![], - vec![first.clone(), second.clone()], + vec![first.clone(), second.clone(), third.clone()], &mut rng, ) .unwrap(); assert_eq!(block.height(), v18_height); - assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_accepted(), 3); assert_eq!(block.transactions().num_rejected(), 0); - assert_eq!(block.aborted_transaction_ids().as_slice(), &[second_id]); + assert!(block.aborted_transaction_ids().is_empty()); assert!(block.transactions().get(&first_id).is_some()); + assert!(block.transactions().get(&second_id).is_some()); + assert!(block.transactions().get(&third_id).is_some()); + + let (spend_candidates, spend_aborted_transaction_ids) = + filter_block_spend_limit(&[(first.clone(), 60), (second.clone(), 60), (third.clone(), 40)], Some(100)); + assert_eq!(spend_aborted_transaction_ids, vec![second_id]); + assert_eq!(spend_candidates.iter().map(Transaction::id).collect::>(), vec![first_id, third_id]); + + let (limited_block, aborted_transaction_ids) = prepare_beacon_block_with_limits( + &ledger, + &beacon_key, + vec![first.clone(), second.clone(), third.clone()], + &mut rng, + ) + .unwrap(); + assert_eq!(aborted_transaction_ids, vec![second_id]); + assert!(limited_block.aborted_transaction_ids().is_empty()); + assert!(limited_block.transactions().get(&first_id).is_some()); + assert!(limited_block.transactions().get(&second_id).is_none()); + assert!(limited_block.transactions().get(&third_id).is_some()); + + let shared_key = PrivateKey::from_str(FUNDED_ACCOUNTS[4].1).unwrap(); + let same_payer_overflow = + placeholder_deployment(&ledger, &shared_key, "limit_shared_overflow", deployment_density, &mut rng); + let same_payer_valid = + placeholder_deployment(&ledger, &shared_key, "limit_shared_valid", remaining_density, &mut rng); + let same_payer_overflow_id = same_payer_overflow.id(); + let same_payer_valid_id = same_payer_valid.id(); + let raw_same_payer_block = ledger + .prepare_advance_to_next_beacon_block( + &beacon_key, + vec![], + vec![], + vec![first.clone(), same_payer_overflow.clone(), same_payer_valid.clone()], + &mut rng, + ) + .unwrap(); + assert_eq!(raw_same_payer_block.aborted_transaction_ids(), &[same_payer_valid_id]); + assert!(raw_same_payer_block.transactions().get(&same_payer_overflow_id).is_some()); + + let (limited_same_payer_block, aborted_transaction_ids) = prepare_beacon_block_with_limits( + &ledger, + &beacon_key, + vec![first.clone(), same_payer_overflow, same_payer_valid], + &mut rng, + ) + .unwrap(); + assert_eq!(aborted_transaction_ids, vec![same_payer_overflow_id]); + assert!(limited_same_payer_block.aborted_transaction_ids().is_empty()); + assert!(limited_same_payer_block.transactions().get(&first_id).is_some()); + assert!(limited_same_payer_block.transactions().get(&same_payer_overflow_id).is_none()); + assert!(limited_same_payer_block.transactions().get(&same_payer_valid_id).is_some()); let oversized = placeholder_deployment(&ledger, &first_key, "limit_oversized", synthesis_limit.saturating_add(1), &mut rng); + let oversized_id = oversized.id(); let initial_height = ledger.latest_height(); let rest = test_rest(&ledger, beacon_key, false, vec![]); let runtime = tokio::runtime::Runtime::new().unwrap(); let response = runtime.block_on(async { match Rest::transaction_broadcast( - State(rest), + State(rest.clone()), Query(CheckTransaction { check_transaction: Some(false) }), Ok(Json(oversized)), ) @@ -973,8 +1239,11 @@ mod tests { assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); assert_eq!(ledger.latest_height(), initial_height); + assert!(rest.buffer.lock().is_empty()); + let response_body = runtime.block_on(axum::body::to_bytes(response.into_body(), usize::MAX)).unwrap(); + assert!(String::from_utf8(response_body.to_vec()).unwrap().contains(&oversized_id.to_string())); - let rest = test_rest(&ledger, beacon_key, true, vec![first, second]); + let rest = test_rest(&ledger, beacon_key, true, vec![first, second, third]); let response = runtime.block_on(async { match Rest::create_block(State(rest.clone()), Json(CreateBlockRequest { num_blocks: Some(1) })).await { Ok(_) => panic!("block creation accepted an aborted deployment"), @@ -984,12 +1253,14 @@ mod tests { assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); assert_eq!(ledger.latest_height(), initial_height); - assert_eq!(rest.buffer.lock().iter().map(Transaction::id).collect::>(), vec![first_id]); + assert_eq!(rest.buffer.lock().iter().map(Transaction::id).collect::>(), vec![first_id, third_id]); let _ = runtime .block_on(Rest::create_block(State(rest.clone()), Json(CreateBlockRequest { num_blocks: Some(1) }))) .expect("valid buffered deployment should create a block"); assert_eq!(ledger.latest_height(), v18_height); assert!(rest.buffer.lock().is_empty()); + assert!(ledger.latest_block().transactions().get(&first_id).is_some()); + assert!(ledger.latest_block().transactions().get(&third_id).is_some()); } } diff --git a/src/start.rs b/src/start.rs index 4d9b07e..7f3b1dd 100644 --- a/src/start.rs +++ b/src/start.rs @@ -181,10 +181,7 @@ Please either: #[cfg(test)] mod tests { use super::*; - use snarkvm::{ - ledger::{authority::Authority, narwhal::Subdag}, - prelude::{ConsensusVersion, Field, Network}, - }; + use snarkvm::prelude::{ConsensusVersion, Network}; const VALID_PRIVATE_KEY: &str = "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH"; const INVALID_PRIVATE_KEY: &str = "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWa"; @@ -207,17 +204,10 @@ mod tests { } #[test] - fn test_beacon_authority_enforces_block_limits() { - let private_key = resolve_private_key(&Some(VALID_PRIVATE_KEY.to_string())).unwrap(); - let mut rng = rand::rng(); - let authority = Authority::::new_beacon(&private_key, Field::from_u64(0), &mut rng).unwrap(); - let v16_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V16).unwrap(); - let v18_height = TestnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V18).unwrap(); - - assert_eq!(authority.spend_limit(v16_height), Subdag::::min_spend_limit(v16_height)); - assert!(authority.spend_limit(v16_height).is_some()); - assert_eq!(authority.synthesis_limit(v16_height), None); - assert_eq!(authority.synthesis_limit(v18_height), Subdag::::min_synthesis_limit(v18_height)); - assert!(authority.synthesis_limit(v18_height).is_some()); + fn test_latest_test_consensus_version_is_v18() { + let &(version, height) = TEST_CONSENSUS_VERSION_HEIGHTS.last().unwrap(); + + assert_eq!((version, height), (ConsensusVersion::V18, 21)); + assert_eq!(TestnetV0::CONSENSUS_VERSION(height).unwrap(), ConsensusVersion::V18); } } From c428f2da235224c8fade30bad429c626c8ee86ce Mon Sep 17 00:00:00 2001 From: Mohammad Fawaz Date: Tue, 4 Aug 2026 12:14:43 -0400 Subject: [PATCH 4/5] test beacon spend with deployment costs --- src/rest/routes.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/rest/routes.rs b/src/rest/routes.rs index e22d6bb..8923176 100644 --- a/src/rest/routes.rs +++ b/src/rest/routes.rs @@ -1168,10 +1168,18 @@ mod tests { assert!(block.transactions().get(&second_id).is_some()); assert!(block.transactions().get(&third_id).is_some()); + let consensus_version = TestnetV0::CONSENSUS_VERSION(v18_height).unwrap(); + let deployment_spend = + transaction_compute_spend_in_microcredits(ledger.vm().process(), &first, consensus_version).unwrap(); + let spend_limit = beacon_block_limits::(v18_height).unwrap().0.unwrap(); + assert!(deployment_spend > 0 && deployment_spend <= spend_limit); + let deployments_within_spend_limit = spend_limit / deployment_spend; + let spend_candidates = + (0..=deployments_within_spend_limit).map(|_| (first.clone(), deployment_spend)).collect::>(); let (spend_candidates, spend_aborted_transaction_ids) = - filter_block_spend_limit(&[(first.clone(), 60), (second.clone(), 60), (third.clone(), 40)], Some(100)); - assert_eq!(spend_aborted_transaction_ids, vec![second_id]); - assert_eq!(spend_candidates.iter().map(Transaction::id).collect::>(), vec![first_id, third_id]); + filter_block_spend_limit(&spend_candidates, Some(spend_limit)); + assert_eq!(spend_candidates.len(), usize::try_from(deployments_within_spend_limit).unwrap()); + assert_eq!(spend_aborted_transaction_ids, vec![first_id]); let (limited_block, aborted_transaction_ids) = prepare_beacon_block_with_limits( &ledger, From 9c5807fb1ad83bf93c8a44d066c11dbea9688400 Mon Sep 17 00:00:00 2001 From: Mohammad Fawaz Date: Tue, 4 Aug 2026 13:31:19 -0400 Subject: [PATCH 5/5] fix spend-limit preparation ordering --- src/rest/routes.rs | 107 +++++++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 38 deletions(-) diff --git a/src/rest/routes.rs b/src/rest/routes.rs index 8923176..531554f 100644 --- a/src/rest/routes.rs +++ b/src/rest/routes.rs @@ -65,6 +65,7 @@ fn active_consensus_value(values: &[(ConsensusVersion, T)], consensus_v fn filter_preparation_limits>( ledger: &Ledger, block_height: u32, + synthesis_limit: Option, transactions: &[Transaction], ) -> Result<(Vec<(Transaction, u64)>, Vec), RestError> { let consensus_version = N::CONSENSUS_VERSION(block_height) @@ -77,9 +78,6 @@ fn filter_preparation_limits>( active_consensus_value(&N::TRANSACTION_SPEND_LIMIT, consensus_version).ok_or_else(|| { RestError::internal_server_error(anyhow!("Missing transaction spend limit for {consensus_version}")) })?; - let synthesis_limit = beacon_block_limits::(block_height) - .map_err(|error| RestError::internal_server_error(error.context("Failed to calculate beacon block limits")))? - .1; let mut block_combined_density = 0u64; let mut candidates = Vec::with_capacity(transactions.len()); let mut aborted_transaction_ids = Vec::new(); @@ -160,8 +158,22 @@ fn prepare_beacon_block_with_limits, R: rand: rng: &mut R, ) -> Result<(Block, Vec), RestError> { let block_height = ledger.latest_height().saturating_add(1); - let (spend_limit, _) = beacon_block_limits::(block_height) + let (spend_limit, synthesis_limit) = beacon_block_limits::(block_height) .map_err(|error| RestError::internal_server_error(error.context("Failed to calculate beacon block limits")))?; + + prepare_beacon_block_with_limit_values(ledger, private_key, transactions, spend_limit, synthesis_limit, rng) +} + +/// Prepares a beacon block with explicit block limits. +fn prepare_beacon_block_with_limit_values, R: rand::Rng + rand::CryptoRng>( + ledger: &Ledger, + private_key: &PrivateKey, + transactions: Vec>, + spend_limit: Option, + synthesis_limit: Option, + rng: &mut R, +) -> Result<(Block, Vec), RestError> { + let block_height = ledger.latest_height().saturating_add(1); let mut snarkvm_aborted_transaction_ids = Vec::new(); loop { @@ -171,9 +183,9 @@ fn prepare_beacon_block_with_limits, R: rand: .cloned() .collect::>(); let (preparation_candidates, preparation_aborted_transaction_ids) = - filter_preparation_limits(ledger, block_height, &active_transactions)?; - let candidate_transactions = - preparation_candidates.iter().map(|(transaction, _)| transaction.clone()).collect::>(); + filter_preparation_limits(ledger, block_height, synthesis_limit, &active_transactions)?; + let (candidate_transactions, spend_aborted_transaction_ids) = + filter_block_spend_limit(&preparation_candidates, spend_limit); let prepared_block = ledger .prepare_advance_to_next_beacon_block(private_key, vec![], vec![], candidate_transactions, rng) .map_err(|error| RestError::internal_server_error(anyhow!("Failed to prepare block: {error}")))?; @@ -187,25 +199,6 @@ fn prepare_beacon_block_with_limits, R: rand: continue; } - let (spend_candidates, spend_aborted_transaction_ids) = - filter_block_spend_limit(&preparation_candidates, spend_limit); - let final_block = if spend_aborted_transaction_ids.is_empty() { - prepared_block - } else { - ledger - .prepare_advance_to_next_beacon_block(private_key, vec![], vec![], spend_candidates, rng) - .map_err(|error| RestError::internal_server_error(anyhow!("Failed to prepare block: {error}")))? - }; - - if !final_block.aborted_transaction_ids().is_empty() { - extend_snarkvm_aborted_transaction_ids( - &transactions, - final_block.aborted_transaction_ids(), - &mut snarkvm_aborted_transaction_ids, - )?; - continue; - } - let aborted_transaction_ids = transactions .iter() .filter(|transaction| { @@ -215,7 +208,7 @@ fn prepare_beacon_block_with_limits, R: rand: }) .map(Transaction::id) .collect(); - return Ok((final_block, aborted_transaction_ids)); + return Ok((prepared_block, aborted_transaction_ids)); } } @@ -1038,11 +1031,29 @@ mod tests { program_name: &str, density: u64, rng: &mut (impl rand::Rng + rand::CryptoRng), + ) -> Transaction { + placeholder_deployment_with_constructor( + ledger, + private_key, + program_name, + density, + " assert.eq true true;\n", + rng, + ) + } + + fn placeholder_deployment_with_constructor( + ledger: &Ledger>, + private_key: &PrivateKey, + program_name: &str, + density: u64, + constructor: &str, + rng: &mut (impl rand::Rng + rand::CryptoRng), ) -> Transaction { const PLACEHOLDER_CERTIFICATE: &str = "certificate1qyqsqqqqqqqqqqxvwszp09v860w62s2l4g6eqf0kzppyax5we36957ywqm2dplzwvvlqg0kwlnmhzfatnax7uaqt7yqqqw0sc4u"; let program = Program::from_str(&format!( - "program {program_name}.aleo;\n\nfunction run:\n assert.eq true true;\n\nconstructor:\n assert.eq true true;\n" + "program {program_name}.aleo;\n\nfunction run:\n assert.eq true true;\n\nconstructor:\n{constructor}" )) .unwrap(); let function_name = *program.functions().keys().next().unwrap(); @@ -1065,8 +1076,12 @@ mod tests { let deployment_id = deployment.to_deployment_id().unwrap(); let owner = ProgramOwner::new(private_key, deployment_id, rng).unwrap(); - let consensus_version = TestnetV0::CONSENSUS_VERSION(ledger.latest_height() + 1).unwrap(); - let (base_fee, _) = deployment_cost(ledger.vm().process(), &deployment, consensus_version).unwrap(); + let current_consensus_version = TestnetV0::CONSENSUS_VERSION(ledger.latest_height()).unwrap(); + let next_consensus_version = TestnetV0::CONSENSUS_VERSION(ledger.latest_height() + 1).unwrap(); + let (current_base_fee, _) = + deployment_cost(ledger.vm().process(), &deployment, current_consensus_version).unwrap(); + let (next_base_fee, _) = deployment_cost(ledger.vm().process(), &deployment, next_consensus_version).unwrap(); + let base_fee = current_base_fee.max(next_base_fee); let authorization = ledger.vm().authorize_fee_public(private_key, base_fee, 0, deployment_id, rng).unwrap(); let fee_transition = authorization.transitions().into_values().next().unwrap(); let fee = Fee::from(fee_transition, ledger.latest_state_root(), None).unwrap(); @@ -1195,34 +1210,50 @@ mod tests { assert!(limited_block.transactions().get(&third_id).is_some()); let shared_key = PrivateKey::from_str(FUNDED_ACCOUNTS[4].1).unwrap(); - let same_payer_overflow = - placeholder_deployment(&ledger, &shared_key, "limit_shared_overflow", deployment_density, &mut rng); - let same_payer_valid = - placeholder_deployment(&ledger, &shared_key, "limit_shared_valid", remaining_density, &mut rng); + let same_payer_overflow = placeholder_deployment_with_constructor( + &ledger, + &shared_key, + "limit_shared_overflow", + 1, + " inv 2field into r0;\n", + &mut rng, + ); + let same_payer_valid = placeholder_deployment(&ledger, &shared_key, "limit_shared_valid", 1, &mut rng); let same_payer_overflow_id = same_payer_overflow.id(); let same_payer_valid_id = same_payer_valid.id(); + let same_payer_overflow_spend = + transaction_compute_spend_in_microcredits(ledger.vm().process(), &same_payer_overflow, consensus_version) + .unwrap(); + let same_payer_valid_spend = + transaction_compute_spend_in_microcredits(ledger.vm().process(), &same_payer_valid, consensus_version) + .unwrap(); + assert!(same_payer_overflow_spend > same_payer_valid_spend); + + // Without spend filtering, snarkVM accepts the first deployment and aborts the second deployment because both + // use the same public fee payer. let raw_same_payer_block = ledger .prepare_advance_to_next_beacon_block( &beacon_key, vec![], vec![], - vec![first.clone(), same_payer_overflow.clone(), same_payer_valid.clone()], + vec![same_payer_overflow.clone(), same_payer_valid.clone()], &mut rng, ) .unwrap(); assert_eq!(raw_same_payer_block.aborted_transaction_ids(), &[same_payer_valid_id]); assert!(raw_same_payer_block.transactions().get(&same_payer_overflow_id).is_some()); - let (limited_same_payer_block, aborted_transaction_ids) = prepare_beacon_block_with_limits( + let (limited_same_payer_block, aborted_transaction_ids) = prepare_beacon_block_with_limit_values( &ledger, &beacon_key, - vec![first.clone(), same_payer_overflow, same_payer_valid], + vec![same_payer_overflow, same_payer_valid], + Some(same_payer_valid_spend), + Some(synthesis_limit), &mut rng, ) .unwrap(); assert_eq!(aborted_transaction_ids, vec![same_payer_overflow_id]); assert!(limited_same_payer_block.aborted_transaction_ids().is_empty()); - assert!(limited_same_payer_block.transactions().get(&first_id).is_some()); assert!(limited_same_payer_block.transactions().get(&same_payer_overflow_id).is_none()); assert!(limited_same_payer_block.transactions().get(&same_payer_valid_id).is_some());