diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp index fd655a026f37..892ec941bd39 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp @@ -98,6 +98,8 @@ enum class OpCode : uint8_t { // Gadgets KECCAK, POSEIDON2, + SHA256, + PEDERSEN, // Conversions TORADIXLE, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp index caa72df38347..f5e8bf5a97e2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp @@ -83,7 +83,7 @@ const size_t CONTRACT_INSTANCE_LENGTH = 5; const size_t CONTRACT_STORAGE_READ_LENGTH = 2; const size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; const size_t ETH_ADDRESS_LENGTH = 1; -const size_t FUNCTION_DATA_LENGTH = 2; +const size_t FUNCTION_DATA_LENGTH = 3; const size_t FUNCTION_LEAF_PREIMAGE_LENGTH = 5; const size_t GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; const size_t APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 209e5a0e0660..f607abad860c 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -6,20 +6,56 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. +## 0.X.X + +### [Aztec.nr] View functions and interface navigation + +It is now possible to explicitly state a function doesn't perform any state alterations (including storage, logs, nullifiers and/or messages from L2 to L1) with the `#[aztec(view)]` attribute, similarly to solidity's `view` function modifier. + +```diff + #[aztec(public)] ++ #[aztec(view)] + fn get_price(asset_id: Field) -> Asset { + storage.assets.at(asset_id).read() + } +``` + +View functions only generate a `StaticCallInterface` that doesn't include `.call` or `.enqueue` methods. Also, the denomination `static` has been completely removed from the interfaces, in favor of the more familiar `view` + +```diff ++ let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; +- let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; +``` + +```diff +#[aztec(private)] +fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { ++ StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); +- StaticChild::at(target_contract).pub_get_value(value).static_enqueue(&mut context); +} +``` + +Additionally, the Noir LSP will now honor "go to definitions" requests for contract interfaces (Ctrl+click), taking the user to the original function implementation. + +### [Aztec.js] Simulate changes + +* `.simulate()` now tracks closer the process performed by `.send().wait()`, specifically going through the account contract entrypoint instead of directly calling the intended function. +* `wallet.viewTx(...)` has been renamed to `wallet.simulateUnconstrained(...)` to better clarify what it does. + ## 0.41.0 ### [Aztec.nr] Keys: Token note now stores an owner master nullifying public key hash instead of an owner address i.e. -struct TokenNote \{ +```diff +struct TokenNote { amount: U128, - ```diff - - owner: AztecAddress, - + npk_m_hash: Field, - ``` +- owner: AztecAddress, ++ npk_m_hash: Field, randomness: Field, -\} +} +``` Computing the nullifier similarly changes to use this master nullifying public key hash. diff --git a/docs/static/img/sandbox_unconstrained_function.svg b/docs/static/img/sandbox_unconstrained_function.svg index 8b42518887d7..948a9ac042e0 100644 --- a/docs/static/img/sandbox_unconstrained_function.svg +++ b/docs/static/img/sandbox_unconstrained_function.svg @@ -1307,7 +1307,7 @@ id="path53" d="M 2.8498858,-9.2967961e-4 -0.00199662,-7.4962595 H 1.2202387 l 1.5983078,4.4532922 c 0.3760724,1.0506006 0.5954479,1.7170264 0.6581267,2.0071176 h 0.062679 c 0.039174,-0.2273688 0.1958711,-0.7213079 0.4700905,-1.473977 0.2663846,-0.7683497 0.8618326,-2.430494 1.786344,-4.9864328 h 1.222235 L 4.1661393,-9.2967961e-4 Z m 6.5107536,0 H 8.2010828 V -7.4962595 H 9.3606394 Z M 8.1070647,-9.5033771 c 0,-0.2665703 0.062679,-0.4547376 0.1880362,-0.5645019 0.1410272,-0.125445 0.3133937,-0.188167 0.5014299,-0.188167 0.1645317,0 0.3133937,0.06272 0.4387512,0.188167 0.1410271,0.1097643 0.2193755,0.2979316 0.2193755,0.5645019 0,0.2508897 -0.078348,0.439057 -0.2193755,0.5645018 -0.1253575,0.1254449 -0.2742195,0.1881673 -0.4387512,0.1881673 -0.1880362,0 -0.3604027,-0.062722 -0.5014299,-0.1881673 C 8.1697435,-9.0643201 8.1070647,-9.2524874 8.1070647,-9.5033771 Z m 6.8006423,9.62789227 c -1.112547,0 -1.990049,-0.32929273 -2.632506,-1.0035588 C 11.648413,-1.5454694 11.33502,-2.4784655 11.33502,-3.6701916 c 0,-1.2074067 0.289889,-2.1717639 0.877502,-2.8852315 0.603283,-0.7056273 1.410271,-1.0662813 2.413131,-1.0662813 0.940181,0 1.676656,0.3136122 2.225095,0.9408364 0.540604,0.6115437 0.814824,1.4112546 0.814824,2.4148134 v 0.7213079 h -5.139656 c 0.01567,0.8781139 0.235045,1.55238 0.658126,2.0071176 0.415247,0.4625779 1.010695,0.68994668 1.786344,0.68994668 0.791319,0 1.582638,-0.16464638 2.381792,-0.50177938 v 1.00355878 C 16.952601,-0.17341635 16.576529,-0.0636521 16.223961,-9.2967961e-4 15.863558,0.07747335 15.424807,0.12451517 14.907707,0.12451517 Z M 14.625653,-6.680868 c -0.611117,0 -1.089043,0.2038479 -1.441611,0.5958631 -0.360402,0.3998554 -0.564108,0.9408363 -0.626787,1.630783 h 3.917421 c 0,-0.7056273 -0.172367,-1.2544485 -0.50143,-1.630783 C 15.659852,-6.4770201 15.205431,-6.680868 14.625653,-6.680868 Z M 25.743294,-9.2967961e-4 24.364362,-4.3914995 c -0.08618,-0.2665703 -0.250715,-0.8781139 -0.50143,-1.8189503 h -0.03134 c -0.188036,0.7997109 -0.360402,1.4034143 -0.501429,1.8189503 L 21.919891,-9.2967961e-4 H 20.603638 L 18.566579,-7.4962595 h 1.190896 c 0.477925,1.8816728 0.846163,3.3164482 1.096877,4.2964861 0.250715,0.9878782 0.391743,1.654304 0.438752,2.0071176 h 0.06268 c 0.03918,-0.2665703 0.109688,-0.6037033 0.219376,-1.0035588 0.125357,-0.415536 0.22721,-0.7526691 0.313394,-1.0035588 l 1.378932,-4.2964861 h 1.222235 l 1.347593,4.2964861 c 0.250715,0.799711 0.415247,1.4582964 0.50143,1.9757564 h 0.06268 c 0.01567,-0.1646463 0.07051,-0.415536 0.156696,-0.7526691 0.07835,-0.3292927 0.548439,-2.171764 1.410272,-5.5195734 h 1.190896 L 27.09089,-9.2967961e-4 Z m 8.007208,0 H 32.590946 V -8.9702365 h -3.165277 v -1.0035588 h 7.490109 v 1.0035588 H 33.750502 Z M 40.049715,-3.8269976 37.448548,-7.4962595 h 1.284914 l 1.97438,2.8852316 1.97438,-2.8852316 h 1.284914 l -2.601167,3.6692619 2.726525,3.82606792039 H 42.807579 L 40.707842,-3.0429673 38.608104,-9.2967961e-4 H 37.32319 Z m 4.896776,0 c 0,-1.2074067 0.172367,-2.3364104 0.53277,-3.387011 0.352567,-1.0427603 0.861832,-1.9600758 1.535629,-2.7597867 h 1.096877 c -0.650291,0.8781139 -1.143887,1.8424712 -1.47295,2.8852316 -0.336898,1.0506006 -0.50143,2.1247221 -0.50143,3.2302049 0,1.113323 0.164532,2.1874445 0.50143,3.23020487 0.329063,1.01923941 0.822659,1.97575643 1.47295,2.85387033 H 47.01489 C 46.341093,1.4495264 45.831828,0.54789154 45.479261,-0.47134787 45.118858,-1.5141082 44.946491,-2.6352715 44.946491,-3.8269976 Z m 4.606887,3.10476003 c 0,-0.31361213 0.06268,-0.54098093 0.188037,-0.68994673 0.141027,-0.1646463 0.352567,-0.2508897 0.626787,-0.2508897 0.266384,0 0.477925,0.086243 0.626787,0.2508897 0.141027,0.1489658 0.219376,0.3763346 0.219376,0.68994673 0,0.29793152 -0.08618,0.52530031 -0.250715,0.68994668 -0.148862,0.14112545 -0.344733,0.21952849 -0.595448,0.21952849 -0.235045,0 -0.430916,-0.0627224 -0.595448,-0.18816727961 C 49.623892,-0.14205514 49.553378,-0.38510453 49.553378,-0.72223757 Z m 3.729385,0 c 0,-0.31361213 0.06268,-0.54098093 0.188036,-0.68994673 0.141027,-0.1646463 0.352568,-0.2508897 0.626788,-0.2508897 0.266384,0 0.477925,0.086243 0.626787,0.2508897 0.141027,0.1489658 0.219376,0.3763346 0.219376,0.68994673 0,0.29793152 -0.08618,0.52530031 -0.250715,0.68994668 -0.148862,0.14112545 -0.344733,0.21952849 -0.595448,0.21952849 -0.235046,0 -0.430917,-0.0627224 -0.595448,-0.18816727961 C 53.353277,-0.14205514 53.282763,-0.38510453 53.282763,-0.72223757 Z m 3.72155,0 c 0,-0.31361213 0.06268,-0.54098093 0.188036,-0.68994673 0.141027,-0.1646463 0.352568,-0.2508897 0.626787,-0.2508897 0.266385,0 0.477926,0.086243 0.626788,0.2508897 0.141027,0.1489658 0.219375,0.3763346 0.219375,0.68994673 0,0.29793152 -0.08618,0.52530031 -0.250715,0.68994668 -0.148862,0.14112545 -0.344733,0.21952849 -0.595448,0.21952849 -0.235045,0 -0.430916,-0.0627224 -0.595447,-0.18816727961 C 57.074827,-0.14205514 57.004313,-0.38510453 57.004313,-0.72223757 Z m 6.267873,-3.10476003 c 0,1.1917261 -0.180201,2.3128894 -0.532769,3.35564973 C 62.402519,0.54789154 61.901089,1.4495264 61.235128,2.2257164 H 60.13825 c 0.626787,-0.8624333 1.104712,-1.81111001 1.441611,-2.85387033 0.329063,-1.04276037 0.501429,-2.11688187 0.501429,-3.23020487 0,-1.1054828 -0.172366,-2.1796043 -0.501429,-3.2302049 -0.313394,-1.0427604 -0.806989,-2.0071177 -1.472951,-2.8852316 h 1.128218 c 0.665961,0.7997109 1.167391,1.7248667 1.504289,2.7911479 0.352568,1.0506006 0.532769,2.1639237 0.532769,3.3556498 z m 6.557763,3.82606792039 H 68.670392 V -7.4962595 h 1.159557 z M 68.576374,-9.5033771 c 0,-0.2665703 0.06268,-0.4547376 0.188037,-0.5645019 0.141027,-0.125445 0.313393,-0.188167 0.501429,-0.188167 0.164532,0 0.313394,0.06272 0.438752,0.188167 0.141027,0.1097643 0.219375,0.2979316 0.219375,0.5645019 0,0.2508897 -0.07835,0.439057 -0.219375,0.5645018 -0.125358,0.1254449 -0.27422,0.1881673 -0.438752,0.1881673 -0.188036,0 -0.360402,-0.062722 -0.501429,-0.1881673 -0.125358,-0.1254448 -0.188037,-0.3136121 -0.188037,-0.5645018 z m 8.492969,7.4639686 c 0,0.6899467 -0.266385,1.22308729 -0.783484,1.59942184 -0.524935,0.37633456 -1.253575,0.56450183 -2.193756,0.56450183 -1.00286,0 -1.778509,-0.15680606 -2.319113,-0.47041819 V -1.380823 c 0.352568,0.1881672 0.736475,0.337133 1.159556,0.43905694 0.415247,0.10976424 0.814824,0.15680606 1.190896,0.15680606 0.579779,0 1.0342,-0.0940836 1.347593,-0.2822509 0.329064,-0.2038479 0.50143,-0.5017794 0.50143,-0.878114 0,-0.2900912 -0.125357,-0.5409809 -0.376072,-0.7526691 -0.250715,-0.2038479 -0.752145,-0.4468973 -1.50429,-0.7213079 -0.689466,-0.2665703 -1.183061,-0.5017794 -1.47295,-0.6899466 -0.297724,-0.1881673 -0.5171,-0.4076958 -0.658127,-0.6585855 -0.148862,-0.2508897 -0.219375,-0.5409809 -0.219375,-0.878114 0,-0.6037033 0.250714,-1.0819618 0.752144,-1.4426157 0.50143,-0.3528137 1.175227,-0.5331407 2.037059,-0.5331407 0.814824,0 1.606143,0.1724867 2.381792,0.5017794 l -0.407412,0.9094752 C 75.75309,-6.5240619 75.071458,-6.680868 74.468175,-6.680868 c -0.548438,0 -0.95585,0.086243 -1.222235,0.2508897 -0.274219,0.1724867 -0.407412,0.4076958 -0.407412,0.7213079 0,0.1881673 0.03918,0.360654 0.125358,0.5017794 0.101853,0.1489658 0.266384,0.2822509 0.50143,0.4076958 0.22721,0.1254448 0.665961,0.3057718 1.316253,0.5331406 0.893172,0.337133 1.50429,0.6742661 1.817683,1.0035588 0.313394,0.3136121 0.470091,0.7213079 0.470091,1.2230873 z m 8.461629,2.16392367 c -1.089043,0 -1.935206,-0.32145243 -2.538489,-0.97219759 -0.587613,-0.66642578 -0.877502,-1.61510248 -0.877502,-2.85387038 0,-1.2544485 0.297724,-2.2109655 0.908842,-2.8852315 0.603283,-0.6899467 1.45728,-1.0349201 2.569828,-1.0349201 0.376072,0 0.736475,0.047042 1.096878,0.1254449 0.352568,0.062722 0.634622,0.1489658 0.846163,0.2508897 l -0.344733,0.9721976 c -0.250715,-0.101924 -0.53277,-0.1881673 -0.846163,-0.2508897 -0.297724,-0.062722 -0.548439,-0.094084 -0.752145,-0.094084 -1.527794,0 -2.287774,0.9721976 -2.287774,2.9165928 0,0.9251558 0.172367,1.6307831 0.532769,2.1325625 0.376073,0.4860988 0.924512,0.72130788 1.660987,0.72130788 0.626787,0 1.261409,-0.13328516 1.911701,-0.40769578 v 1.00355882 c -0.50143,0.25088970039 -1.128217,0.37633455 -1.880362,0.37633485 z M 93.82807,-9.2967961e-4 93.577355,-1.0672109 h -0.03134 c -0.376072,0.46257788 -0.752144,0.77619 -1.128217,0.94083637 -0.376072,0.16464637 -0.846163,0.2508897 -1.410271,0.2508897 -0.736475,0 -1.308419,-0.18816727 -1.723666,-0.56450183 -0.423081,-0.37633455 -0.626787,-0.91731544 -0.626787,-1.63078304 0,-1.5053382 1.198731,-2.2972088 3.604027,-2.3834522 l 1.284914,-0.031361 v -0.4704182 c 0,-0.5801824 -0.125357,-1.0113991 -0.376072,-1.2858097 -0.250715,-0.2900912 -0.658127,-0.439057 -1.222235,-0.439057 -0.626788,0 -1.339758,0.2038479 -2.131077,0.5958631 l -0.344733,-0.878114 c 0.376072,-0.2038479 0.783484,-0.3606539 1.222235,-0.4704182 0.438751,-0.1254448 0.877502,-0.1881673 1.316253,-0.1881673 0.893172,0 1.551299,0.2038479 1.974381,0.5958631 0.438751,0.3998554 0.658126,1.03492 0.658126,1.913034 V -9.2967961e-4 Z M 91.258242,-0.78496 c 0.705135,0 1.261409,-0.19600758 1.660986,-0.595863 0.391742,-0.3920152 0.595448,-0.9408364 0.595448,-1.6307831 v -0.6585855 l -1.128217,0.031361 c -0.901007,0.047042 -1.559134,0.1881673 -1.97438,0.439057 -0.399577,0.2352091 -0.595448,0.6115437 -0.595448,1.1290037 0,0.4233764 0.125357,0.7448288 0.376072,0.9721976 0.250715,0.21168816 0.603283,0.3136121 1.065539,0.3136123 z m 6.878991,0.78403032039 H 96.977676 V -10.632381 h 1.159557 z m 3.541347,0 h -1.15956 V -10.632381 h 1.15956 z M 107.22565,0.12451517 c -1.11255,0 -1.99005,-0.32929273 -2.63251,-1.0035588 -0.62678,-0.66642577 -0.94018,-1.59942187 -0.94018,-2.79114797 0,-1.2074067 0.28989,-2.1717639 0.8775,-2.8852315 0.60329,-0.7056273 1.41028,-1.0662813 2.41314,-1.0662813 0.94018,0 1.67665,0.3136122 2.22509,0.9408364 0.5406,0.6115437 0.81482,1.4112546 0.81482,2.4148134 v 0.7213079 h -5.13965 c 0.0157,0.8781139 0.23504,1.55238 0.65812,2.0071176 0.41525,0.4625779 1.0107,0.68994668 1.78635,0.68994668 0.79132,0 1.58264,-0.16464638 2.38179,-0.50177938 v 1.00355878 c -0.39958,0.17248667 -0.77565,0.28225092 -1.12822,0.34497334039 C 108.1815,0.07747335 107.74275,0.12451517 107.22565,0.12451517 Z M 106.9436,-6.680868 c -0.61112,0 -1.08905,0.2038479 -1.44162,0.5958631 -0.3604,0.3998554 -0.5641,0.9408363 -0.62678,1.630783 h 3.91742 c 0,-0.7056273 -0.17237,-1.2544485 -0.50143,-1.630783 -0.3134,-0.3920152 -0.76782,-0.5958631 -1.34759,-0.5958631 z m 10.0756,5.6763795 h -0.0627 c -0.52493,0.75266912 -1.30842,1.12900367 -2.35045,1.12900367 -0.98719,0 -1.74717,-0.32929273 -2.28777,-1.0035588 -0.54844,-0.66642577 -0.81483,-1.61510247 -0.81483,-2.85387037 0,-1.2309276 0.26639,-2.1796043 0.81483,-2.8538703 0.5406,-0.6899467 1.30058,-1.0349201 2.28777,-1.0349201 1.01853,0 1.80201,0.3684943 2.35045,1.0976425 h 0.094 l -0.0627,-0.5331406 -0.0313,-0.5331406 v -3.0420379 h 1.15956 V -9.2967961e-4 h -0.94018 z m -2.25643,0.18816729 c 0.76781,0 1.32409,-0.20384789 1.66098,-0.62722429 0.35257,-0.415536 0.53277,-1.0976424 0.53277,-2.0384788 V -3.732914 c 0,-1.0427603 -0.1802,-1.7954294 -0.53277,-2.2580073 -0.3604,-0.4547376 -0.92451,-0.6899467 -1.69232,-0.6899467 -0.6738,0 -1.18306,0.2665703 -1.53563,0.7840303 -0.3369,0.5253003 -0.50143,1.2544485 -0.50143,2.1952849 0,0.9408364 0.16453,1.6621443 0.50143,2.1639237 0.35257,0.4860988 0.8775,0.72130789 1.56697,0.72130789 z m 15.84988,-2.94795399 c 0,1.2387679 -0.31339,2.1952849 -0.94018,2.88523157 -0.61112,0.67426607 -1.45728,1.0035588 -2.53849,1.0035588 -0.67379,0 -1.26924,-0.15680606 -1.78634,-0.47041819 -0.52494,-0.31361213 -0.93235,-0.76050938 -1.22224,-1.34853218 -0.27422,-0.5801824 -0.40741,-1.2701291 -0.40741,-2.06984 0,-1.2074067 0.29773,-2.1482431 0.90884,-2.8225091 0.62679,-0.6899467 1.48079,-1.0349201 2.56983,-1.0349201 1.04204,0 1.86469,0.360654 2.47581,1.0662813 0.62679,0.6899466 0.94018,1.6229427 0.94018,2.7911479 z m -5.70376,0 c 0,0.9643573 0.18803,1.6935055 0.56411,2.1952849 0.37607,0.5017794 0.94018,0.75266909 1.69232,0.75266909 0.72864,0 1.28492,-0.25088969 1.66099,-0.75266909 0.39174,-0.5017794 0.59545,-1.2309276 0.59545,-2.1952849 0,-0.9408364 -0.20371,-1.6464637 -0.59545,-2.1325625 -0.37607,-0.5017794 -0.94018,-0.7526691 -1.69233,-0.7526691 -0.73647,0 -1.28491,0.2430494 -1.66098,0.7213079 -0.37608,0.4860988 -0.56411,1.2074067 -0.56411,2.1639237 z m 12.8178,3.76334552039 V -4.8305564 c 0,-0.6272243 -0.14886,-1.0819619 -0.43875,-1.3798934 -0.27422,-0.2900912 -0.70514,-0.439057 -1.28492,-0.439057 -0.77565,0 -1.34759,0.2116882 -1.72366,0.6272243 -0.3604,0.4233764 -0.53277,1.1211633 -0.53277,2.1012012 v 3.92015162039 h -1.15956 V -7.4962595 h 0.94018 l 0.18804,1.03492 h 0.0627 c 0.22721,-0.3763345 0.54844,-0.6585855 0.97152,-0.8467527 0.41525,-0.2038479 0.8775,-0.3136122 1.37893,-0.3136122 0.91668,0 1.59831,0.2195285 2.03706,0.6585855 0.45442,0.439057 0.68947,1.1290037 0.68947,2.06984 V -9.2967961e-4 Z M 147.26169,-0.78496 c 0.18804,0 0.37607,-0.00784 0.56411,-0.0313612 0.18804,-0.0392015 0.32906,-0.078403 0.43875,-0.12544485 v 0.87811396 c -0.10969,0.0627224204 -0.28205,0.10192394 -0.53277,0.12544485 -0.23504,0.03920151 -0.45442,0.06272242 -0.65812,0.06272242 -1.44162,0 -2.16242,-0.76050941 -2.16242,-2.28936858 v -4.4532922 h -1.06554 v -0.5331406 l 1.06554,-0.4704182 0.47009,-1.5994218 h 0.65813 v 1.7248667 h 2.19375 v 0.8781139 h -2.19375 v 4.421931 c 0,0.439057 0.10185,0.7840303 0.31339,1.0349201 0.22721,0.25088966 0.53277,0.37633451 0.90884,0.3763345 z m 7.63114,0.78403032039 V -4.8305564 c 0,-0.6272243 -0.14886,-1.0819619 -0.43875,-1.3798934 -0.27422,-0.2900912 -0.70514,-0.439057 -1.28492,-0.439057 -0.79915,0 -1.3711,0.2195285 -1.72366,0.6585855 -0.36041,0.4233764 -0.53277,1.113323 -0.53277,2.06984 v 3.92015162039 h -1.15956 V -10.632381 h 1.15956 v 3.2302051 c 0,0.3763346 -0.0235,0.6899467 -0.0627,0.9408364 h 0.0627 c 0.22721,-0.3528136 0.5406,-0.6350645 0.94018,-0.8467527 0.41525,-0.2038479 0.89317,-0.3136122 1.44161,-0.3136122 0.89317,0 1.5748,0.2195285 2.03706,0.6585855 0.45442,0.439057 0.68946,1.1290037 0.68946,2.06984 V -9.2967961e-4 Z M 161.51327,0.12451517 c -1.11255,0 -1.99005,-0.32929273 -2.63251,-1.0035588 -0.62679,-0.66642577 -0.94018,-1.59942187 -0.94018,-2.79114797 0,-1.2074067 0.28989,-2.1717639 0.8775,-2.8852315 0.60329,-0.7056273 1.41027,-1.0662813 2.41313,-1.0662813 0.94019,0 1.67666,0.3136122 2.2251,0.9408364 0.5406,0.6115437 0.81482,1.4112546 0.81482,2.4148134 v 0.7213079 h -5.13965 c 0.0157,0.8781139 0.23504,1.55238 0.65812,2.0071176 0.41525,0.4625779 1.0107,0.68994668 1.78635,0.68994668 0.79132,0 1.58264,-0.16464638 2.38179,-0.50177938 v 1.00355878 c -0.39958,0.17248667 -0.77565,0.28225092 -1.12822,0.34497334039 C 162.46912,0.07747335 162.03037,0.12451517 161.51327,0.12451517 Z M 161.23121,-6.680868 c -0.61111,0 -1.08904,0.2038479 -1.44161,0.5958631 -0.3604,0.3998554 -0.5641,0.9408363 -0.62678,1.630783 h 3.91742 c 0,-0.7056273 -0.17237,-1.2544485 -0.50143,-1.630783 -0.3134,-0.3920152 -0.76782,-0.5958631 -1.3476,-0.5958631 z m 15.12908,-0.4076957 c 0,1.0270797 -0.34473,1.81111 -1.03419,2.3520909 -0.68947,0.5488212 -1.67666,0.8153915 -2.94591,0.8153915 h -1.19089 v 3.92015162039 h -1.15956 V -9.9737953 h 2.60117 c 2.48364,0 3.72938,0.9643573 3.72938,2.8852316 z m -5.17099,2.1639236 h 1.0342 c 1.04203,0 1.79418,-0.1646463 2.25643,-0.5017794 0.45442,-0.3292927 0.68947,-0.8624333 0.68947,-1.5994218 0,-0.6429049 -0.21938,-1.1290037 -0.65813,-1.4426158 -0.43875,-0.3292927 -1.12038,-0.5017794 -2.03706,-0.5017794 h -1.28491 z m 13.91468,4.92371042039 h -1.31626 L 181.09254,-4.3914995 178.36601,-9.2967961e-4 h -1.22223 L 180.46575,-5.206891 l -3.1026,-4.7669043 h 1.28492 l 2.47581,3.9515128 2.50715,-3.9515128 h 1.25357 l -3.1026,4.7041819 z m 7.01218,0 h -5.57841 V -9.9737953 h 5.57841 v 1.0035588 h -4.41885 v 3.2302049 h 4.1368 v 1.03492 h -4.1368 v 3.6692619 h 4.41885 z M 193.98085,-0.72223757 c 0,-0.31361213 0.0627,-0.54098093 0.18804,-0.68994673 0.14103,-0.1646463 0.35257,-0.2508897 0.62679,-0.2508897 0.26638,0 0.47792,0.086243 0.62678,0.2508897 0.14103,0.1489658 0.21938,0.3763346 0.21938,0.68994673 0,0.29793152 -0.0862,0.52530031 -0.25071,0.68994668 -0.14887,0.14112545 -0.34474,0.21952849 -0.59545,0.21952849 -0.23505,0 -0.43092,-0.0627224 -0.59545,-0.18816727961 C 194.05137,-0.14205514 193.98085,-0.38510453 193.98085,-0.72223757 Z m 0,0" style="fill:#f24726;fill-opacity:1;fill-rule:nonzero;stroke:none" - aria-label=" viewTx(...) is called on the PXE." + aria-label=" simulateUnconstrained(...) is called on the PXE." transform="matrix(0.4985742,0,0,0.49822691,416.05959,194.41453)" clip-path="url(#clipPath54)" /> for FunctionCall { fn serialize(self) -> [Field; FUNCTION_CALL_SIZE] { - [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field] + [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field, self.is_static as Field] } } @@ -34,6 +35,7 @@ impl FunctionCall { bytes[i + 64] = target_address_bytes[i]; } bytes[96] = self.is_public as u8; + bytes[97] = self.is_static as u8; bytes } } diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index c7d79f2e24b6..70992b0cea72 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -5,11 +5,15 @@ mod private_context; mod public_context; mod avm_context; mod interface; +mod call_interfaces; mod gas; -use interface::{ - ContextInterface, PrivateCallInterface, PublicCallInterface, PrivateVoidCallInterface, - PublicVoidCallInterface, AvmCallInterface, AvmVoidCallInterface +use interface::ContextInterface; +use call_interfaces::{ + PrivateCallInterface, PrivateStaticCallInterface, PublicCallInterface, PublicStaticCallInterface, + PrivateVoidCallInterface, PrivateStaticVoidCallInterface, PublicVoidCallInterface, + PublicStaticVoidCallInterface, AvmCallInterface, AvmStaticCallInterface, AvmVoidCallInterface, + AvmStaticVoidCallInterface }; use private_context::PrivateContext; use private_context::PackedReturns; diff --git a/noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr b/noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr new file mode 100644 index 000000000000..a04465f60bfc --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr @@ -0,0 +1,407 @@ +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, traits::Deserialize}; + +use crate::context::private_context::PrivateContext; +use crate::context::public_context::PublicContext; +use crate::context::avm_context::AvmContext; +use crate::context::gas::GasOpts; +use crate::context::public_context::FunctionReturns; + +use crate::hash::hash_args; +use crate::oracle::arguments; + +struct PrivateCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateCallInterface { + pub fn call(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ); + let unpacked: T = returns.unpack_into(); + unpacked + } + + pub fn view(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.unpack_into() + } + + pub fn delegate_call(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); + returns.unpack_into() + } +} + +struct PrivateVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateVoidCallInterface { + pub fn call(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ).assert_empty(); + } + + pub fn view(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } + + pub fn delegate_call(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); + } +} + +struct PrivateStaticCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateStaticCallInterface { + pub fn view(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.unpack_into() + } +} + +struct PrivateStaticVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateStaticVoidCallInterface { + pub fn view(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } +} + +struct PublicCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PublicCallInterface { + pub fn call(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ); + returns.deserialize_into() + } + + pub fn view(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.deserialize_into() + } + + pub fn delegate_call(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); + returns.deserialize_into() + } + + pub fn enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) + } +} + +struct PublicVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field +} + +impl PublicVoidCallInterface { + pub fn call(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ).assert_empty() + } + + pub fn view(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } + + pub fn delegate_call(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); + } + + pub fn enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) + } +} + +struct PublicStaticCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PublicStaticCallInterface { + pub fn view(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.deserialize_into() + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } +} + +struct PublicStaticVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field +} + +impl PublicStaticVoidCallInterface { + pub fn view(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } +} + +struct AvmCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn call(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.deserialize_into() + } + + pub fn view(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.deserialize_into() + } + + pub fn delegate_call(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); + returns.deserialize_into() + } + + pub fn enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ true + ) + } +} + +struct AvmVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmVoidCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn call(self, context: &mut AvmContext) { + let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.assert_empty() + } + + pub fn view(self, context: &mut AvmContext) { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.assert_empty() + } + + pub fn delegate_call(self, context: &mut AvmContext) { + let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); + returns.assert_empty() + } + + pub fn enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ true + ) + } +} + +struct AvmStaticCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmStaticCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn view(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.deserialize_into() + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } +} + +struct AvmStaticVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmStaticVoidCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn view(self, context: &mut AvmContext) { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.assert_empty() + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } +} diff --git a/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr b/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr index 0000b903f6d7..7361af69643e 100644 --- a/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr +++ b/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr @@ -3,6 +3,7 @@ use dep::protocol_types::traits::Empty; struct AvmContextInputs { selector: Field, args_hash: Field, + is_static_call: bool } impl Empty for AvmContextInputs { @@ -10,6 +11,7 @@ impl Empty for AvmContextInputs { AvmContextInputs { selector: 0, args_hash: 0, + is_static_call: false } } } diff --git a/noir-projects/aztec-nr/aztec/src/context/interface.nr b/noir-projects/aztec-nr/aztec/src/context/interface.nr index 0ceb66a05a8e..37bf13318d03 100644 --- a/noir-projects/aztec-nr/aztec/src/context/interface.nr +++ b/noir-projects/aztec-nr/aztec/src/context/interface.nr @@ -1,9 +1,5 @@ -use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, traits::Deserialize}; +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; -use crate::oracle::arguments; -use crate::context::private_context::PrivateContext; -use crate::context::public_context::PublicContext; -use crate::context::avm_context::AvmContext; use crate::context::gas::GasOpts; use crate::context::public_context::FunctionReturns; @@ -54,280 +50,3 @@ trait PublicContextInterface { ) -> FunctionReturns; fn nullifier_exists(self, unsiloed_nullifier: Field, address: AztecAddress) -> bool; } - -struct PrivateCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field, -} - -impl PrivateCallInterface { - pub fn call(self, context: &mut PrivateContext) -> T where T: Deserialize { - let returns = context.call_private_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ); - let unpacked: T = returns.unpack_into(); - unpacked - } - - pub fn static_call(self, context: &mut PrivateContext) -> T where T: Deserialize { - let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); - returns.unpack_into() - } - - pub fn delegate_call(self, context: &mut PrivateContext) -> T where T: Deserialize { - let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); - returns.unpack_into() - } -} - -struct PrivateVoidCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field, -} - -impl PrivateVoidCallInterface { - pub fn call(self, context: &mut PrivateContext) { - context.call_private_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ).assert_empty(); - } - - pub fn static_call(self, context: &mut PrivateContext) { - context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); - } - - pub fn delegate_call(self, context: &mut PrivateContext) { - context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); - } -} - -struct PublicCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field, -} - -impl PublicCallInterface { - pub fn call(self, context: &mut PublicContext) -> T where T: Deserialize { - let returns = context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ); - returns.deserialize_into() - } - - pub fn static_call(self, context: &mut PublicContext) -> T where T: Deserialize { - let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); - returns.deserialize_into() - } - - pub fn delegate_call(self, context: &mut PublicContext) -> T where T: Deserialize { - let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); - returns.deserialize_into() - } - - pub fn enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) - } -} - -struct PublicVoidCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field -} - -impl PublicVoidCallInterface { - pub fn call(self, context: &mut PublicContext) { - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ).assert_empty() - } - - pub fn static_call(self, context: &mut PublicContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); - } - - pub fn delegate_call(self, context: &mut PublicContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); - } - - pub fn enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) - } -} - -struct AvmCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args: [Field], - gas_opts: GasOpts, -} - -impl AvmCallInterface { - pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { - self.gas_opts = gas_opts; - self - } - - pub fn call(self, context: &mut AvmContext) -> T where T: Deserialize { - let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.deserialize_into() - } - - pub fn static_call(self, context: &mut AvmContext) -> T where T: Deserialize { - let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.deserialize_into() - } - - pub fn delegate_call(self, context: &mut AvmContext) -> T where T: Deserialize { - let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); - returns.deserialize_into() - } - - pub fn enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ true, - /*delegate=*/ false - ) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ true - ) - } -} - -struct AvmVoidCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args: [Field], - gas_opts: GasOpts, -} - -impl AvmVoidCallInterface { - pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { - self.gas_opts = gas_opts; - self - } - - pub fn call(self, context: &mut AvmContext) { - let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.assert_empty() - } - - pub fn static_call(self, context: &mut AvmContext) { - let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.assert_empty() - } - - pub fn delegate_call(self, context: &mut AvmContext) { - let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); - returns.assert_empty() - } - - pub fn enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ true, - /*delegate=*/ false - ) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ true - ) - } -} diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 9722d8aecbfa..645ea474ad24 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -440,7 +440,7 @@ impl PrivateContext { assert(args_hash == item.public_inputs.args_hash); - // Assert that the call context of the enqueued call generated by the oracle matches our request. + // Assert that the call context of the call generated by the oracle matches our request. assert(item.public_inputs.call_context.is_delegate_call == is_delegate_call); assert(item.public_inputs.call_context.is_static_call == is_static_call); diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 38a37c0083be..12fbe2958744 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -41,4 +41,6 @@ members = [ "contracts/uniswap_contract", "contracts/reader_contract", "contracts/multi_call_entrypoint_contract", + "contracts/static_child_contract", + "contracts/static_parent_contract" ] diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr index 8d6e9711a4dc..4b0d7e4af7b4 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr @@ -3,12 +3,11 @@ use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, use dep::authwit::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; +global DAPP_MAX_CALLS: u64 = 1; // FUNCTION_CALL_SIZE * DAPP_MAX_CALLS + 1 -global DAPP_PAYLOAD_SIZE: u64 = 5; +global DAPP_PAYLOAD_SIZE: u64 = 6; // FUNCTION_CALL_SIZE_IN_BYTES * DAPP_MAX_CALLS + 32 -global DAPP_PAYLOAD_SIZE_IN_BYTES: u64 = 129; - -global DAPP_MAX_CALLS: u64 = 1; +global DAPP_PAYLOAD_SIZE_IN_BYTES: u64 = 130; // Note: If you change the following struct you have to update default_entrypoint.ts // docs:start:app-payload-struct @@ -55,7 +54,8 @@ impl DAppPayload { // Executes all private and public calls // docs:start:entrypoint-execute-calls fn execute_calls(self, context: &mut PrivateContext, target_address: AztecAddress) { - for call in self.function_calls { + for i in 0..DAPP_MAX_CALLS { + let call = self.function_calls[i]; // whitelist the calls that the user can do only go to the expected Dapp contract assert(call.target_address == target_address); if call.is_public { @@ -63,7 +63,7 @@ impl DAppPayload { call.target_address, call.function_selector, call.args_hash, - false, + call.is_static, false ); } else { @@ -71,7 +71,7 @@ impl DAppPayload { call.target_address, call.function_selector, call.args_hash, - false, + call.is_static, false ); } diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 25bcda79fc01..a232484e17dd 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -56,7 +56,7 @@ contract AppSubscription { context.end_setup(); - AppSubscription::at(context.this_address()).assert_not_expired(note.expiry_block_number).static_enqueue(&mut context); + AppSubscription::at(context.this_address()).assert_not_expired(note.expiry_block_number).enqueue_view(&mut context); payload.execute_calls(&mut context, storage.target_address.read_private()); } @@ -81,12 +81,14 @@ contract AppSubscription { #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn assert_not_expired(expiry_block_number: Field) { assert((context.block_number()) as u64 < expiry_block_number as u64); } #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn assert_block_number(expiry_block_number: Field) { assert( (context.block_number() + SUBSCRIPTION_DURATION_IN_BLOCKS) as u64 @@ -111,7 +113,7 @@ contract AppSubscription { ).call(&mut context); // Assert that the given expiry_block_number < current_block_number + SUBSCRIPTION_DURATION_IN_BLOCKS. - AppSubscription::at(context.this_address()).assert_block_number(expiry_block_number).static_enqueue(&mut context); + AppSubscription::at(context.this_address()).assert_block_number(expiry_block_number).enqueue_view(&mut context); let subscriber_npk_m_hash = get_npk_m_hash(&mut context, subscriber_address); let subscriber_ivpk_m = get_ivpk_m(&mut context, subscriber_address); @@ -124,7 +126,7 @@ contract AppSubscription { } // Compiler bug workaround. You can't call an unconstrained function in another module, unless its from an - // unconstained function in your module. + // unconstrained function in your module. unconstrained fn is_initialized(subscriber_address: AztecAddress) -> pub bool { storage.subscriptions.at(subscriber_address).is_initialized() } diff --git a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr index a21791aaee41..a62fc79b5ece 100644 --- a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr @@ -58,13 +58,13 @@ contract AvmNestedCallsTest { // Indirectly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { - AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).static_call(&mut context) + AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).view(&mut context) } // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. #[aztec(public-vm)] fn nested_static_call_to_set_storage() { - AvmNestedCallsTest::at(context.this_address()).set_storage_single(20).static_call(&mut context); + AvmNestedCallsTest::at(context.this_address()).set_storage_single(20).view(&mut context); } #[aztec(public-vm)] diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 90747ecab5c0..36873f06d8b9 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -377,7 +377,7 @@ contract AvmTest { */ #[aztec(private)] fn enqueue_public_from_private() { - AvmTest::at(context.this_address()).set_opcode_u8().static_enqueue(&mut context); + AvmTest::at(context.this_address()).set_opcode_u8().enqueue_view(&mut context); AvmTest::at(context.this_address()).set_read_storage_single(5).enqueue(&mut context); } } diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 9eef23a50bd5..88bc4a0c54b3 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -60,6 +60,7 @@ contract Crowdfunding { // docs:start:deadline-header #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn _check_deadline() { // docs:end:deadline-header let deadline = storage.deadline.read(); @@ -72,7 +73,7 @@ contract Crowdfunding { #[aztec(private)] fn donate(amount: u64) { // 1) Check that the deadline has not passed - Crowdfunding::at(context.this_address())._check_deadline().static_enqueue(&mut context); + Crowdfunding::at(context.this_address())._check_deadline().enqueue_view(&mut context); // docs:end:call-check-deadline // docs:start:do-transfer diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index d2ed49d84ece..7723b789a262 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -117,7 +117,7 @@ contract DocsExample { // and returns the response. // Used to test that we can retrieve values through calls and // correctly return them in the simulation - let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_private().static_call(&mut context); + let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_private().view(&mut context); leader.points += 1; leader } @@ -128,12 +128,13 @@ contract DocsExample { // and returns the response. // Used to test that we can retrieve values through calls and // correctly return them in the simulation - let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_public().static_call(&mut context); + let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_public().view(&mut context); leader.points += 1; leader } #[aztec(public)] + #[aztec(view)] fn get_shared_immutable_constrained_public() -> pub Leader { storage.shared_immutable.read_public() } @@ -145,6 +146,7 @@ contract DocsExample { } #[aztec(private)] + #[aztec(view)] fn get_shared_immutable_constrained_private() -> pub Leader { storage.shared_immutable.read_private() } diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index c640a5238295..1817bc8947dc 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -151,7 +151,7 @@ contract Lending { #[aztec(internal)] fn _withdraw(owner: AztecAddress, recipient: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); - let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; + let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; let coll_loc = storage.collateral.at(owner); let collateral: Field = coll_loc.read(); @@ -199,7 +199,7 @@ contract Lending { #[aztec(internal)] fn _borrow(owner: AztecAddress, to: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); - let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; + let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; // Fetch collateral and static_debt, compute health of current position let collateral = U128::from_integer(storage.collateral.at(owner).read()); diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index c4afaacf7538..6aab33130b7c 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -18,6 +18,7 @@ contract PriceFeed { } #[aztec(public)] + #[aztec(view)] fn get_price(asset_id: Field) -> Asset { storage.assets.at(asset_id).read() } diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml new file mode 100644 index 000000000000..6c3ec004fe8b --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "static_child_contract" +type = "contract" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +value_note = { path = "../../../aztec-nr/value-note" } diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr new file mode 100644 index 000000000000..f6f7b7e79c71 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr @@ -0,0 +1,142 @@ +// A contract used along with `StaticParent` contract to test static calls. +contract StaticChild { + use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; + + use dep::aztec::{ + context::{PublicContext, Context, gas::GasOpts}, + protocol_types::{abis::{call_context::CallContext}}, + note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, + keys::getters::{get_npk_m_hash, get_ivpk_m} + }; + use dep::value_note::value_note::ValueNote; + + #[aztec(storage)] + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, + } + + // Returns base_value + chain_id + version + block_number + timestamp statically + #[aztec(public)] + #[aztec(view)] + fn pub_get_value(base_value: Field) -> Field { + let return_value = base_value + + context.chain_id() + + context.version() + + context.block_number() + + context.timestamp() as Field; + + return_value + } + + // Sets `current_value` to `new_value` + #[aztec(public)] + fn pub_set_value(new_value: Field) -> Field { + storage.current_value.write(new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // View function that attempts to modify state. Should always fail regardless how it's called. + #[aztec(private)] + #[aztec(view)] + fn private_illegal_set_value(new_value: Field, owner: AztecAddress) -> Field { + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let owner_ivpk_m = get_ivpk_m(&mut context, owner); + let mut note = ValueNote::new(new_value, owner_npk_m_hash); + storage.a_private_value.insert(&mut note, true, owner_ivpk_m); + new_value + } + + // Modify a note + #[aztec(private)] + fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let owner_ivpk_m = get_ivpk_m(&mut context, owner); + let mut note = ValueNote::new(new_value, owner_npk_m_hash); + storage.a_private_value.insert(&mut note, true, owner_ivpk_m); + new_value + } + + // Retrieve note value statically + #[aztec(private)] + #[aztec(view)] + fn private_get_value(amount: Field, owner: AztecAddress) -> Field { + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let mut options = NoteGetterOptions::new(); + options = options.select(ValueNote::properties().value, amount, Option::none()).select( + ValueNote::properties().npk_m_hash, + owner_npk_m_hash, + Option::none() + ).set_limit(1); + let notes = storage.a_private_value.get_notes(options); + notes[0].unwrap_unchecked().value + } + + // Increments `current_value` by `new_value` + #[aztec(public)] + fn pub_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // View function that attempts to modify state. Should always fail regardless how it's called. + #[aztec(public)] + #[aztec(view)] + fn pub_illegal_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // AVM + + // Returns base_value + chain_id + version + block_number + timestamp statically + #[aztec(public-vm)] + #[aztec(view)] + fn avm_get_value(base_value: Field) -> Field { + let return_value = base_value + + context.chain_id() + + context.version() + + context.block_number() + + context.timestamp() as Field; + + return_value + } + + // Sets `current_value` to `new_value` + #[aztec(public-vm)] + fn avm_set_value(new_value: Field) -> Field { + storage.current_value.write(new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // Increments `current_value` by `new_value` + #[aztec(public-vm)] + fn avm_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // View function that attempts to modify state. Should always fail regardless how it's called. + #[aztec(public-vm)] + #[aztec(view)] + fn avm_illegal_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } +} diff --git a/noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml new file mode 100644 index 000000000000..31ad33000b72 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "static_parent_contract" +type = "contract" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +static_child_contract = { path = "../static_child_contract"} \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr new file mode 100644 index 000000000000..e03529b57d05 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr @@ -0,0 +1,196 @@ + +// A contract used along with `StaticChild` contract to test static calls. +contract StaticParent { + use dep::aztec::prelude::{AztecAddress, FunctionSelector, Deserialize}; + use dep::aztec::context::gas::GasOpts; + use dep::static_child_contract::StaticChild; + + // Public function to directly call another public function to the target_contract using the selector and value provided + #[aztec(public)] + fn public_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + arg: Field + ) -> Field { + context.call_public_function( + target_contract, + target_selector, + [arg].as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Private function to directly call another private function to the target_contract using the selector and args provided + #[aztec(private)] + fn private_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 2] + ) -> Field { + context.call_private_function(target_contract, target_selector, args).unpack_into() + } + + // Private function to enqueue a call to a public function of another contract, passing the target arguments provided + #[aztec(private)] + fn enqueue_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + context.call_public_function(target_contract, target_selector, args); + } + + // Private function to statically call another private function to the target_contract using the selector and values provided + #[aztec(private)] + fn private_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 2] + ) -> Field { + context.static_call_private_function(target_contract, target_selector, args).unpack_into() + } + + // Same as above but using a specific function from the interface + #[aztec(private)] + fn private_get_value_from_child( + target_contract: AztecAddress, + value: Field, + owner: AztecAddress + ) -> Field { + StaticChild::at(target_contract).private_get_value(value, owner).view(&mut context) + } + + // Private function to set a static context and verify correct propagation for nested private calls + #[aztec(private)] + fn private_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 2] + ) -> Field { + StaticParent::at(context.this_address()).private_call(target_contract, target_selector, args).view(&mut context) + } + + // Public function to statically call another public function to the target_contract using the selector and value provided + #[aztec(public)] + fn public_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + context.static_call_public_function( + target_contract, + target_selector, + args.as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Same as above but using a specific function from the interface + #[aztec(public)] + fn public_get_value_from_child(target_contract: AztecAddress, value: Field) -> Field { + StaticChild::at(target_contract).pub_get_value(value).view(&mut context) + } + + // Public function to set a static context and verify correct propagation for nested public calls + #[aztec(public)] + fn public_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).public_call(target_contract, target_selector, args[0]).view(&mut context) + } + + // Private function to enqueue a static call to a public function of another contract, passing the target arguments provided + #[aztec(private)] + fn enqueue_static_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + context.static_call_public_function(target_contract, target_selector, args); + } + + // Same as above but using a specific function from the interface + #[aztec(private)] + fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { + StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); + } + + // Private function to set a static context and verify correct propagation of nested enqueuing of public calls + #[aztec(private)] + fn enqueue_static_nested_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).public_call(target_contract, target_selector, args[0]).enqueue_view(&mut context) + } + + // AVM + + #[aztec(public-vm)] + fn avm_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + arg: Field + ) -> Field { + context.call_public_function( + target_contract, + target_selector, + [arg].as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Public function to statically call another public function to the target_contract using the selector and value provided + #[aztec(public-vm)] + fn avm_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + context.static_call_public_function( + target_contract, + target_selector, + args.as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Same as above but using a specific function from the interface + #[aztec(public-vm)] + fn avm_get_value_from_child(target_contract: AztecAddress, value: Field) -> Field { + StaticChild::at(target_contract).avm_get_value(value).view(&mut context) + } + + // Public function to set a static context and verify correct propagation for nested public calls + #[aztec(public-vm)] + fn avm_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).avm_call(target_contract, target_selector, args[0]).view(&mut context) + } + + // Same as above but using a specific function from the interface + #[aztec(private)] + fn enqueue_avm_get_value_from_child(target_contract: AztecAddress, value: Field) { + StaticChild::at(target_contract).avm_get_value(value).enqueue_view(&mut context); + } + + // Private function to set a static context and verify correct propagation of nested enqueuing of public calls + #[aztec(private)] + fn enqueue_static_nested_call_to_avm_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).avm_call(target_contract, target_selector, args[0]).enqueue_view(&mut context) + } +} diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index afacb2205685..0ccd4b5a74b4 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -57,7 +57,7 @@ contract Uniswap { assert_current_call_valid_authwit_public(&mut context, sender); } - let input_asset = TokenBridge::at(input_asset_bridge).get_token().static_call(&mut context); + let input_asset = TokenBridge::at(input_asset_bridge).get_token().view(&mut context); // Transfer funds to this contract Token::at(input_asset).transfer_public( @@ -71,8 +71,8 @@ contract Uniswap { Uniswap::at(context.this_address())._approve_bridge_and_exit_input_asset_to_L1(input_asset, input_asset_bridge, input_amount).call(&mut context); // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. - let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address_public().static_call(&mut context); - let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address_public().static_call(&mut context); + let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address_public().view(&mut context); + let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address_public().view(&mut context); // ensure portal exists - else funds might be lost assert( !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0" @@ -114,7 +114,7 @@ contract Uniswap { ) { // Assert that user provided token address is same as expected by token bridge. // we can't directly use `input_asset_bridge.token` because that is a public method and public can't return data to private - Uniswap::at(context.this_address())._assert_token_is_same(input_asset, input_asset_bridge).static_enqueue(&mut context); + Uniswap::at(context.this_address())._assert_token_is_same(input_asset, input_asset_bridge).enqueue_view(&mut context); // Transfer funds to this contract Token::at(input_asset).unshield( @@ -129,8 +129,8 @@ contract Uniswap { // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. - let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address().static_call(&mut context); - let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address().static_call(&mut context); + let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address().view(&mut context); + let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address().view(&mut context); // ensure portal exists - else funds might be lost assert( !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0" @@ -218,9 +218,10 @@ contract Uniswap { // docs:start:assert_token_is_same #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn _assert_token_is_same(token: AztecAddress, token_bridge: AztecAddress) { assert( - token.eq(TokenBridge::at(token_bridge).get_token().static_call(&mut context)), "input_asset address is not the same as seen in the bridge contract" + token.eq(TokenBridge::at(token_bridge).get_token().view(&mut context)), "input_asset address is not the same as seen in the bridge contract" ); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr index 2a4148182ca4..f123bb616a66 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr @@ -7,12 +7,14 @@ use crate::{ struct FunctionData { selector : FunctionSelector, is_private : bool, + is_static : bool, } impl Eq for FunctionData { fn eq(self, other: Self) -> bool { self.selector.eq(other.selector) & - self.is_private == other.is_private + (self.is_private == other.is_private) & + (self.is_static == other.is_static) } } @@ -24,6 +26,7 @@ impl Serialize for FunctionData { [ self.selector.to_field(), self.is_private as Field, + self.is_static as Field ] } } @@ -33,6 +36,7 @@ impl Deserialize for FunctionData { Self { selector: FunctionSelector::from_field(serialized[0]), is_private: serialized[1] as bool, + is_static: serialized[2] as bool } } } @@ -48,8 +52,10 @@ impl Empty for FunctionData { FunctionData { selector: FunctionSelector::empty(), is_private: false, + is_static: false } } + } #[test] @@ -66,6 +72,6 @@ fn empty_hash() { let hash = data.hash(); // Value from function_data.test.ts "computes empty function data hash" test - let test_data_empty_hash = 0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed; + let test_data_empty_hash = 0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 18278e5b3d22..2913e5353634 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -85,6 +85,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x1eaa8a277851ba8de6f7630ec75a2324e03a00a6ee99f24dd834faa422bdee4f; + let test_data_empty_hash = 0x29d77b0175116357d39252de002a2944652f87ccb4404f9346bff6d44f020f7f; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr index 7757259ed7fc..f8aefb791ede 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr @@ -58,7 +58,7 @@ mod tests { #[test] fn compute_call_stack_item_request_hash() { let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false }; + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false, is_static: false }; let mut public_inputs = PublicCircuitPublicInputs::empty(); public_inputs.new_note_hashes[0] = NoteHash { @@ -69,14 +69,14 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test - let test_data_call_stack_item_request_hash = 0x1fe90f27924bcd761257c1b4570f5937b6dabcb4b6047ff668a770dea8e13533; + let test_data_call_stack_item_request_hash = 0x0230a99218df238d4a28664ee700e10a4fdfe98e4a2f5c678bce8c95d5fa04b1; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } #[test] fn compute_call_stack_item_hash() { let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false }; + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false, is_static: false }; let mut public_inputs = PublicCircuitPublicInputs::empty(); public_inputs.new_note_hashes[0] = NoteHash { @@ -87,7 +87,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test - let test_data_call_stack_item_hash = 0x2bb94c518916df51853784f16991e7691eddd452831ee1197cd29cdfb492d7b8; + let test_data_call_stack_item_hash = 0x1bda75e8d4cf46fd126d14d6e28d1dc8ff3860b49ff59edd7da8bfeee909aef3; assert_eq(call_stack_item.hash(), test_data_call_stack_item_hash); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index ef19cbe45475..7173fcc77a22 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -150,7 +150,7 @@ global CONTRACT_INSTANCE_LENGTH: u64 = 5; global CONTRACT_STORAGE_READ_LENGTH: u64 = 2; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: u64 = 2; global ETH_ADDRESS_LENGTH = 1; -global FUNCTION_DATA_LENGTH: u64 = 2; +global FUNCTION_DATA_LENGTH: u64 = 3; global FUNCTION_LEAF_PREIMAGE_LENGTH: u64 = 5; global GLOBAL_VARIABLES_LENGTH: u64 = 6 + GAS_FEES_LENGTH; global APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr index 836e673b5e14..bae6a2c40b0e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr @@ -14,6 +14,7 @@ global default_private_function = ContractFunction { data: FunctionData { selector: FunctionSelector { inner: 1010101 }, is_private: true, + is_static: false }, vk_hash: 0, acir_hash: 1111, @@ -33,6 +34,7 @@ global default_public_function = ContractFunction { data: FunctionData { selector: FunctionSelector { inner: 3030303 }, is_private: false, + is_static: false }, vk_hash: 0, acir_hash: 3333, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr index 5d804fa5d0a5..6e261adea38d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr @@ -95,10 +95,10 @@ mod tests { origin: AztecAddress::from_field(1), args_hash: 3, tx_context: TxContext { chain_id: 0, version: 0, gas_settings }, - function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_private: true } + function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_private: true, is_static: false } }; // Value from tx_request.test.ts "compute hash" test - let test_data_tx_request_hash = 0x0d982a1c7a65919b2bcacbf5660f5b861132072a8190d97c82b1591da402f5ea; + let test_data_tx_request_hash = 0x249ca45ef4045007021de437e14bf865445f63af6ab5dcc8d78d2b3aa7c58c74; assert(tx_request.hash() == test_data_tx_request_hash); } } diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 5f0326bea5ab..c3638b7760df 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -1,6 +1,7 @@ mod transforms; mod utils; +use noirc_errors::Location; use transforms::{ compute_note_hash_and_nullifier::inject_compute_note_hash_and_nullifier, contract_interface::{ @@ -66,6 +67,7 @@ fn transform( for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { if transform_module( crate_id, + &file_id, context, &mut submodule.contents, submodule.name.0.contents.as_str(), @@ -86,6 +88,7 @@ fn transform( /// Returns true if an annotated node is found, false otherwise fn transform_module( crate_id: &CrateId, + file_id: &FileId, context: &HirContext, module: &mut SortedModule, module_name: &str, @@ -134,6 +137,7 @@ fn transform_module( let mut is_initializer = false; let mut is_internal = false; let mut insert_init_check = has_initializer; + let mut is_static = false; for secondary_attribute in func.def.attributes.secondary.clone() { if is_custom_attribute(&secondary_attribute, "aztec(private)") { @@ -150,6 +154,9 @@ fn transform_module( } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { is_public_vm = true; } + if is_custom_attribute(&secondary_attribute, "aztec(view)") { + is_static = true; + } } // Apply transformations to the function based on collected attributes @@ -161,7 +168,8 @@ fn transform_module( } else { "Public" }; - stubs.push(stub_function(fn_type, func)); + let stub_src = stub_function(fn_type, func, is_static); + stubs.push((stub_src, Location { file: *file_id, span: func.name_ident().span() })); export_fn_abi(&mut module.types, func)?; transform_function( @@ -171,6 +179,7 @@ fn transform_module( is_initializer, insert_init_check, is_internal, + is_static, )?; has_transformed_module = true; } else if storage_defined && func.def.is_unconstrained { diff --git a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs index 921bad4b6127..bb63357d2510 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs @@ -1,4 +1,5 @@ -use noirc_frontend::ast::{NoirFunction, UnresolvedTypeData}; +use noirc_errors::Location; +use noirc_frontend::ast::{Ident, NoirFunction, UnresolvedTypeData}; use noirc_frontend::{ graph::CrateId, macros_api::{FileId, HirContext, HirExpression, HirLiteral, HirStatement}, @@ -39,7 +40,7 @@ use crate::utils::{ // } // // The selector placeholder has to be replaced with the actual function signature after type checking in the next macro pass -pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { +pub fn stub_function(aztec_visibility: &str, func: &NoirFunction, is_static_call: bool) -> String { let fn_name = func.name().to_string(); let fn_parameters = func .parameters() @@ -59,6 +60,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { let parameters = func.parameters(); let is_void = if matches!(fn_return_type.typ, UnresolvedTypeData::Unit) { "Void" } else { "" }; + let is_static = if is_static_call { "Static" } else { "" }; let return_type_hint = if is_void == "Void" { "".to_string() } else { @@ -101,18 +103,18 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { let fn_body = format!( "{} - dep::aztec::context::{}{}CallInterface {{ + dep::aztec::context::{}{}{}CallInterface {{ target_contract: self.target_contract, selector: {}, args_hash, }}", - args_hash, aztec_visibility, is_void, fn_selector, + args_hash, aztec_visibility, is_static, is_void, fn_selector, ); format!( - "pub fn {}(self, {}) -> dep::aztec::context::{}{}CallInterface{} {{ + "pub fn {}(self, {}) -> dep::aztec::context::{}{}{}CallInterface{} {{ {} }}", - fn_name, fn_parameters, aztec_visibility, is_void, return_type_hint, fn_body + fn_name, fn_parameters, aztec_visibility, is_static, is_void, return_type_hint, fn_body ) } else { let args = format!( @@ -123,19 +125,19 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { ); let fn_body = format!( "{} - dep::aztec::context::Avm{}CallInterface {{ + dep::aztec::context::Avm{}{}CallInterface {{ target_contract: self.target_contract, selector: {}, args: args_acc, gas_opts: dep::aztec::context::gas::GasOpts::default(), }}", - args, is_void, fn_selector, + args, is_static, is_void, fn_selector, ); format!( - "pub fn {}(self, {}) -> dep::aztec::context::Avm{}CallInterface{} {{ + "pub fn {}(self, {}) -> dep::aztec::context::Avm{}{}CallInterface{} {{ {} }}", - fn_name, fn_parameters, is_void, return_type_hint, fn_body + fn_name, fn_parameters, is_static, is_void, return_type_hint, fn_body ) } } @@ -146,7 +148,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { pub fn generate_contract_interface( module: &mut SortedModule, module_name: &str, - stubs: &[String], + stubs: &[(String, Location)], ) -> Result<(), AztecMacroError> { let contract_interface = format!( " @@ -172,7 +174,7 @@ pub fn generate_contract_interface( }} ", module_name, - stubs.join("\n"), + stubs.iter().map(|(src, _)| src.to_owned()).collect::>().join("\n"), ); let (contract_interface_ast, errors) = parse_program(&contract_interface); @@ -182,8 +184,27 @@ pub fn generate_contract_interface( } let mut contract_interface_ast = contract_interface_ast.into_sorted(); + let mut impl_with_locations = contract_interface_ast.impls.pop().unwrap(); + + impl_with_locations.methods = impl_with_locations + .methods + .iter() + .enumerate() + .map(|(i, (method, orig_span))| { + if method.name() == "at" { + (method.clone(), *orig_span) + } else { + let (_, new_location) = stubs[i]; + let mut modified_method = method.clone(); + modified_method.def.name = + Ident::new(modified_method.name().to_string(), new_location.span); + (modified_method, *orig_span) + } + }) + .collect(); + module.types.push(contract_interface_ast.types.pop().unwrap()); - module.impls.push(contract_interface_ast.impls.pop().unwrap()); + module.impls.push(impl_with_locations); module.functions.push(contract_interface_ast.functions.pop().unwrap()); Ok(()) diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 487d15ceabe8..45bce6a681a6 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -10,6 +10,7 @@ use noirc_frontend::ast::{ use noirc_frontend::{macros_api::FieldElement, parse_program}; +use crate::utils::ast_utils::member_access; use crate::{ chained_dep, chained_path, utils::{ @@ -33,6 +34,7 @@ pub fn transform_function( is_initializer: bool, insert_init_check: bool, is_internal: bool, + is_static: bool, ) -> Result<(), AztecMacroError> { let context_name = format!("{}Context", ty); let inputs_name = format!("{}ContextInputs", ty); @@ -40,6 +42,12 @@ pub fn transform_function( let is_avm = ty == "Avm"; let is_private = ty == "Private"; + // Force a static context if the function is static + if is_static { + let is_static_check = create_static_check(func.name(), is_avm); + func.def.body.statements.insert(0, is_static_check); + } + // Add check that msg sender equals this address and flag function as internal if is_internal { let is_internal_check = create_internal_check(func.name()); @@ -275,6 +283,31 @@ fn create_mark_as_initialized(ty: &str) -> Statement { ))) } +/// Forces a static context for a function, ensuring that no state modifications are allowed +/// +/// ```noir +/// assert(context.inputs.call_context.is_static_call == true, "Function can only be called statically") +/// ``` +fn create_static_check(fname: &str, is_avm: bool) -> Statement { + let is_static_call_expr = if !is_avm { + ["inputs", "call_context", "is_static_call"] + .iter() + .fold(variable("context"), |acc, member| member_access(acc, member)) + } else { + ["inputs", "is_static_call"] + .iter() + .fold(variable("context"), |acc, member| member_access(acc, member)) + }; + make_statement(StatementKind::Constrain(ConstrainStatement( + make_eq(is_static_call_expr, expression(ExpressionKind::Literal(Literal::Bool(true)))), + Some(expression(ExpressionKind::Literal(Literal::Str(format!( + "Function {} can only be called statically", + fname + ))))), + ConstrainKind::Assert, + ))) +} + /// Creates a check for internal functions ensuring that the caller is self. /// /// ```noir diff --git a/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs b/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs index ebb4854f86e3..4e05dcaf6197 100644 --- a/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs +++ b/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs @@ -1,9 +1,9 @@ use noirc_errors::{Span, Spanned}; use noirc_frontend::ast::{ BinaryOpKind, CallExpression, CastExpression, Expression, ExpressionKind, FunctionReturnType, - Ident, IndexExpression, InfixExpression, Lambda, LetStatement, MethodCallExpression, - NoirTraitImpl, Path, Pattern, PrefixExpression, Statement, StatementKind, TraitImplItem, - UnaryOp, UnresolvedType, UnresolvedTypeData, + Ident, IndexExpression, InfixExpression, Lambda, LetStatement, MemberAccessExpression, + MethodCallExpression, NoirTraitImpl, Path, Pattern, PrefixExpression, Statement, StatementKind, + TraitImplItem, UnaryOp, UnresolvedType, UnresolvedTypeData, }; use noirc_frontend::token::SecondaryAttribute; @@ -125,6 +125,13 @@ pub fn make_statement(kind: StatementKind) -> Statement { Statement { span: Span::default(), kind } } +pub fn member_access(lhs: Expression, member: &str) -> Expression { + expression(ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { + lhs, + rhs: ident(member), + }))) +} + #[macro_export] macro_rules! chained_path { ( $base:expr ) => { diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index bcdac6b8dc92..c7e7db96a483 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -20,7 +20,7 @@ describe('Contract Class', () => { const mockTxRequest = { type: 'TxRequest' } as any as TxExecutionRequest; const mockTxHash = { type: 'TxHash' } as any as TxHash; const mockTxReceipt = { type: 'TxReceipt' } as any as TxReceipt; - const mockViewResultValue = 1; + const mockUnconstrainedResultValue = 1; const l1Addresses: L1ContractAddresses = { availabilityOracleAddress: EthAddress.random(), rollupAddress: EthAddress.random(), @@ -45,6 +45,7 @@ describe('Contract Class', () => { isInitializer: false, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, debugSymbols: '', parameters: [ { @@ -68,6 +69,7 @@ describe('Contract Class', () => { { name: 'baz', isInitializer: false, + isStatic: false, functionType: FunctionType.OPEN, isInternal: false, parameters: [], @@ -78,6 +80,7 @@ describe('Contract Class', () => { { name: 'qux', isInitializer: false, + isStatic: false, functionType: FunctionType.UNCONSTRAINED, isInternal: false, parameters: [ @@ -118,7 +121,7 @@ describe('Contract Class', () => { wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest); wallet.getContractInstance.mockResolvedValue(contractInstance); wallet.sendTx.mockResolvedValue(mockTxHash); - wallet.viewTx.mockResolvedValue(mockViewResultValue as any as DecodedReturn); + wallet.simulateUnconstrained.mockResolvedValue(mockUnconstrainedResultValue as any as DecodedReturn); wallet.getTxReceipt.mockResolvedValue(mockTxReceipt); wallet.getNodeInfo.mockResolvedValue(mockNodeInfo); wallet.proveTx.mockResolvedValue(mockTx); @@ -145,9 +148,9 @@ describe('Contract Class', () => { const result = await fooContract.methods.qux(123n).simulate({ from: account.address, }); - expect(wallet.viewTx).toHaveBeenCalledTimes(1); - expect(wallet.viewTx).toHaveBeenCalledWith('qux', [123n], contractAddress, account.address); - expect(result).toBe(mockViewResultValue); + expect(wallet.simulateUnconstrained).toHaveBeenCalledTimes(1); + expect(wallet.simulateUnconstrained).toHaveBeenCalledWith('qux', [123n], contractAddress, account.address); + expect(result).toBe(mockUnconstrainedResultValue); }); it('should not call create on an unconstrained function', async () => { diff --git a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts index 393445868919..6ebf682cdc1b 100644 --- a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts +++ b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts @@ -1,5 +1,5 @@ -import { type FunctionCall, PackedValues, TxExecutionRequest } from '@aztec/circuit-types'; -import { type AztecAddress, FunctionData, GasSettings, TxContext } from '@aztec/circuits.js'; +import type { FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; +import { type AztecAddress, FunctionData, type GasSettings } from '@aztec/circuits.js'; import { type FunctionAbi, FunctionType, decodeReturnValues, encodeArguments } from '@aztec/foundation/abi'; import { type Wallet } from '../account/wallet.js'; @@ -70,42 +70,29 @@ export class ContractFunctionInteraction extends BaseContractInteraction { * Differs from prove in a few important ways: * 1. It returns the values of the function execution * 2. It supports `unconstrained`, `private` and `public` functions - * 3. For `private` execution it: - * 3.a SKIPS the entrypoint and starts directly at the function - * 4. For `public` execution it: - * 4.a Removes the `txRequest` value after ended simulation - * 4.b Ignores the `from` in the options * * @param options - An optional object containing additional configuration for the transaction. * @returns The result of the transaction as returned by the contract function. */ public async simulate(options: SimulateMethodOptions = {}): Promise { if (this.functionDao.functionType == FunctionType.UNCONSTRAINED) { - return this.wallet.viewTx(this.functionDao.name, this.args, this.contractAddress, options.from); + return this.wallet.simulateUnconstrained(this.functionDao.name, this.args, this.contractAddress, options?.from); } - if (this.functionDao.functionType == FunctionType.SECRET) { - const nodeInfo = await this.wallet.getNodeInfo(); - const packedArgs = PackedValues.fromValues(encodeArguments(this.functionDao, this.args)); - const gasSettings = options.gasSettings ?? GasSettings.simulation(); + const txRequest = await this.create(); + // const from = + // this.functionDao.functionType == FunctionType.SECRET ? options.from ?? this.wallet.getAddress() : undefined; - const txRequest = TxExecutionRequest.from({ - firstCallArgsHash: packedArgs.hash, - origin: this.contractAddress, - functionData: FunctionData.fromAbi(this.functionDao), - txContext: new TxContext(nodeInfo.chainId, nodeInfo.protocolVersion, gasSettings), - argsOfCalls: [packedArgs], - authWitnesses: [], - }); - const simulatedTx = await this.wallet.simulateTx(txRequest, true, options.from ?? this.wallet.getAddress()); - const flattened = simulatedTx.privateReturnValues; - return flattened ? decodeReturnValues(this.functionDao, flattened) : []; - } else { - const txRequest = await this.create(); - const simulatedTx = await this.wallet.simulateTx(txRequest, true); - this.txRequest = undefined; - const flattened = simulatedTx.publicOutput?.publicReturnValues; - return flattened ? decodeReturnValues(this.functionDao, flattened) : []; - } + const simulatedTx = await this.wallet.simulateTx(txRequest, true, options?.from); + + // As account entrypoints are private, for private functions we retrieve the return values from the first nested call + // since we're interested in the first set of values AFTER the account entrypoint + // For public functions we retrieve the first values directly from the public output. + const rawReturnValues = + this.functionDao.functionType == FunctionType.SECRET + ? simulatedTx.privateReturnValues?.nested?.[0].values + : simulatedTx.publicOutput?.publicReturnValues?.values; + + return rawReturnValues ? decodeReturnValues(this.functionDao, rawReturnValues) : []; } } diff --git a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts b/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts index 167dfac25013..bf36456c1bbb 100644 --- a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts +++ b/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts @@ -39,6 +39,7 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { isInitializer: false, functionType: 'secret', isInternal: false, + isStatic: false, parameters: [ { name: 'app_payload', @@ -73,6 +74,7 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, diff --git a/yarn-project/aztec.js/src/entrypoint/payload.ts b/yarn-project/aztec.js/src/entrypoint/payload.ts index c4bfb965aaab..7c3ec2f764d8 100644 --- a/yarn-project/aztec.js/src/entrypoint/payload.ts +++ b/yarn-project/aztec.js/src/entrypoint/payload.ts @@ -33,6 +33,8 @@ type EncodedFunctionCall = { target_address: Fr; /** Whether the function is public or private */ is_public: boolean; + /** Whether the function can alter state */ + is_static: boolean; }; /* eslint-enable camelcase */ @@ -54,6 +56,7 @@ export class EntrypointPayload { function_selector: call.functionData.selector.toField(), target_address: call.to.toField(), is_public: !call.functionData.isPrivate, + is_static: call.functionData.isStatic, })); /* eslint-enable camelcase */ @@ -96,6 +99,7 @@ export class EntrypointPayload { call.function_selector, call.target_address, new Fr(call.is_public), + new Fr(call.is_static), ]), this.#nonce, ]; diff --git a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts index af5a9ac3b312..92a4779c6f06 100644 --- a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts @@ -54,7 +54,11 @@ export class NativeFeePaymentMethod implements FeePaymentMethod { return Promise.resolve([ { to: this.#gasTokenAddress, - functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false), + functionData: new FunctionData( + FunctionSelector.fromSignature('pay_fee(Field)'), + /*isPrivate=*/ false, + /*isStatic=*/ false, + ), args: [gasSettings.getFeeLimit()], }, ]); diff --git a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts index f3298ed09ef8..f0a96413e31f 100644 --- a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts @@ -65,7 +65,11 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { this.wallet.getVersion(), { args: [this.wallet.getCompleteAddress().address, this.paymentContract, maxFee, nonce], - functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), + functionData: new FunctionData( + FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), + /*isPrivate=*/ true, + /*isStatic=*/ false, + ), to: this.asset, }, ); @@ -78,7 +82,8 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_private(Field,(Field),Field,Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [maxFee, this.asset, secretHashForRebate, nonce], }, diff --git a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts index 33b2430ebeeb..5b8782107dfa 100644 --- a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts @@ -60,7 +60,8 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), to: this.asset, }, @@ -72,7 +73,8 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [maxFee, this.asset, nonce], }, diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index 803d07010eba..e793504eb7db 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -206,6 +206,7 @@ export class AccountWallet extends BaseWallet { isInitializer: false, functionType: FunctionType.OPEN, isInternal: true, + isStatic: false, parameters: [ { name: 'message_hash', @@ -223,6 +224,7 @@ export class AccountWallet extends BaseWallet { isInitializer: false, functionType: FunctionType.SECRET, isInternal: true, + isStatic: false, parameters: [ { name: 'message_hash', @@ -240,6 +242,7 @@ export class AccountWallet extends BaseWallet { isInitializer: false, functionType: FunctionType.UNCONSTRAINED, isInternal: false, + isStatic: false, parameters: [ { name: 'myself', diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index e94c99203590..d8a87d37098f 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -130,8 +130,13 @@ export abstract class BaseWallet implements Wallet { getBlock(number: number): Promise { return this.pxe.getBlock(number); } - viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress | undefined): Promise { - return this.pxe.viewTx(functionName, args, to, from); + simulateUnconstrained( + functionName: string, + args: any[], + to: AztecAddress, + from?: AztecAddress | undefined, + ): Promise { + return this.pxe.simulateUnconstrained(functionName, args, to, from); } getUnencryptedLogs(filter: LogFilter): Promise { return this.pxe.getUnencryptedLogs(filter); diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 0ad069a0ceb7..784c5d7ebbfc 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -232,7 +232,7 @@ export interface PXE { getBlock(number: number): Promise; /** - * Simulate the execution of a view (read-only) function on a deployed contract without actually modifying state. + * Simulate the execution of an unconstrained function on a deployed contract without actually modifying state. * This is useful to inspect contract state, for example fetching a variable value or calling a getter function. * The function takes function name and arguments as parameters, along with the contract address * and optionally the sender's address. @@ -243,7 +243,7 @@ export interface PXE { * @param from - (Optional) The msg sender to set for the call. * @returns The result of the view function call, structured based on the function ABI. */ - viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; + simulateUnconstrained(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; /** * Gets unencrypted logs based on the provided filter. diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 2e21eac53b9e..0fc51c62cdb0 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -27,7 +27,7 @@ import { type ContractInstanceWithAddress, SerializableContractInstance } from ' import { EncryptedL2Log } from './logs/encrypted_l2_log.js'; import { EncryptedFunctionL2Logs, EncryptedTxL2Logs, Note, UnencryptedTxL2Logs } from './logs/index.js'; import { ExtendedNote } from './notes/index.js'; -import { type ProcessReturnValues, PublicSimulationOutput, SimulatedTx, Tx, TxHash } from './tx/index.js'; +import { NestedProcessReturnValues, PublicSimulationOutput, SimulatedTx, Tx, TxHash } from './tx/index.js'; /** * Testing utility to create empty logs composed from a single empty log. @@ -145,7 +145,7 @@ export const mockTxForRollup = (seed = 1, { hasLogs = false }: { hasLogs?: boole export const mockSimulatedTx = (seed = 1, hasLogs = true) => { const tx = mockTx(seed, { hasLogs }); - const dec: ProcessReturnValues = [new Fr(1n), new Fr(2n), new Fr(3n), new Fr(4n)]; + const dec = new NestedProcessReturnValues([new Fr(1n), new Fr(2n), new Fr(3n), new Fr(4n)]); const output = new PublicSimulationOutput( tx.encryptedLogs, tx.unencryptedLogs, diff --git a/yarn-project/circuit-types/src/tx/public_simulation_output.ts b/yarn-project/circuit-types/src/tx/public_simulation_output.ts index 244438146801..d28daa3dc4b2 100644 --- a/yarn-project/circuit-types/src/tx/public_simulation_output.ts +++ b/yarn-project/circuit-types/src/tx/public_simulation_output.ts @@ -8,6 +8,31 @@ import { type PublicKernelType } from './processed_tx.js'; /** Return values of simulating a circuit. */ export type ProcessReturnValues = Fr[] | undefined; +/** Return values of simulating complete callstack. */ +export class NestedProcessReturnValues { + values: ProcessReturnValues; + nested: NestedProcessReturnValues[]; + + constructor(values: ProcessReturnValues, nested?: NestedProcessReturnValues[]) { + this.values = values; + this.nested = nested ?? []; + } + + toJSON(): any { + return { + values: this.values?.map(fr => fr.toString()), + nested: this.nested.map(n => n.toJSON()), + }; + } + + static fromJSON(json: any): NestedProcessReturnValues { + return new NestedProcessReturnValues( + json.values?.map(Fr.fromString), + json.nested?.map((n: any) => NestedProcessReturnValues.fromJSON(n)), + ); + } +} + /** * Outputs of processing the public component of a transaction. */ @@ -18,7 +43,7 @@ export class PublicSimulationOutput { public revertReason: SimulationError | undefined, public constants: CombinedConstantData, public end: CombinedAccumulatedData, - public publicReturnValues: ProcessReturnValues, + public publicReturnValues: NestedProcessReturnValues, public gasUsed: Partial>, ) {} @@ -29,7 +54,7 @@ export class PublicSimulationOutput { revertReason: this.revertReason, constants: this.constants.toBuffer().toString('hex'), end: this.end.toBuffer().toString('hex'), - publicReturnValues: this.publicReturnValues?.map(fr => fr.toString()), + publicReturnValues: this.publicReturnValues?.toJSON(), gasUsed: mapValues(this.gasUsed, gas => gas?.toJSON()), }; } @@ -41,7 +66,7 @@ export class PublicSimulationOutput { json.revertReason, CombinedConstantData.fromBuffer(Buffer.from(json.constants, 'hex')), CombinedAccumulatedData.fromBuffer(Buffer.from(json.end, 'hex')), - json.publicReturnValues?.map(Fr.fromString), + NestedProcessReturnValues.fromJSON(json.publicReturnValues), mapValues(json.gasUsed, gas => (gas ? Gas.fromJSON(gas) : undefined)), ); } diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.ts b/yarn-project/circuit-types/src/tx/simulated_tx.ts index e3808a1e4632..8ac2ef72a1ff 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.ts @@ -1,6 +1,4 @@ -import { Fr } from '@aztec/circuits.js'; - -import { type ProcessReturnValues, PublicSimulationOutput } from './public_simulation_output.js'; +import { NestedProcessReturnValues, PublicSimulationOutput } from './public_simulation_output.js'; import { Tx } from './tx.js'; // REFACTOR: Review what we need to expose to the user when running a simulation. @@ -12,7 +10,7 @@ import { Tx } from './tx.js'; export class SimulatedTx { constructor( public tx: Tx, - public privateReturnValues?: ProcessReturnValues, + public privateReturnValues?: NestedProcessReturnValues, public publicOutput?: PublicSimulationOutput, ) {} @@ -23,7 +21,7 @@ export class SimulatedTx { public toJSON() { return { tx: this.tx.toJSON(), - privateReturnValues: this.privateReturnValues?.map(fr => fr.toString()), + privateReturnValues: this.privateReturnValues && this.privateReturnValues.toJSON(), publicOutput: this.publicOutput && this.publicOutput.toJSON(), }; } @@ -36,7 +34,9 @@ export class SimulatedTx { public static fromJSON(obj: any) { const tx = Tx.fromJSON(obj.tx); const publicOutput = obj.publicOutput ? PublicSimulationOutput.fromJSON(obj.publicOutput) : undefined; - const privateReturnValues = obj.privateReturnValues?.map(Fr.fromString); + const privateReturnValues = obj.privateReturnValues + ? NestedProcessReturnValues.fromJSON(obj.privateReturnValues) + : undefined; return new SimulatedTx(tx, privateReturnValues, publicOutput); } diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 3be95e96e9ae..4a35f3845383 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -94,7 +94,7 @@ export const CONTRACT_INSTANCE_LENGTH = 5; export const CONTRACT_STORAGE_READ_LENGTH = 2; export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; export const ETH_ADDRESS_LENGTH = 1; -export const FUNCTION_DATA_LENGTH = 2; +export const FUNCTION_DATA_LENGTH = 3; export const FUNCTION_LEAF_PREIMAGE_LENGTH = 5; export const GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; export const APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index e81eaebfc49e..4bb4b19a1fbd 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -36,6 +36,7 @@ describe('ContractAddress', () => { functionType: FunctionType.SECRET, isInitializer: false, isInternal: false, + isStatic: false, name: 'fun', parameters: [{ name: 'param1', type: { kind: 'boolean' }, visibility: ABIParameterVisibility.SECRET }], returnTypes: [], diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap index db45ccb85d26..8287356b029b 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FunctionData computes empty function data hash 1`] = `Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>`; +exports[`FunctionData computes empty function data hash 1`] = `Fr<0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap index be2f85234d33..169f798b7ea3 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x1eaa8a277851ba8de6f7630ec75a2324e03a00a6ee99f24dd834faa422bdee4f>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x29d77b0175116357d39252de002a2944652f87ccb4404f9346bff6d44f020f7f>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0cb30e5fa0e822ff93dc0bc3752c4b277e4629dfd8c31651aca53541873a5505>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x00c30fa28e1ab0d35bd0eaa591f469b7f9b92bc37aa5696eaf447b88ad331339>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index 20348f214d3f..5cf1ed0ff490 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x2bb94c518916df51853784f16991e7691eddd452831ee1197cd29cdfb492d7b8"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x1bda75e8d4cf46fd126d14d6e28d1dc8ff3860b49ff59edd7da8bfeee909aef3"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x1fe90f27924bcd761257c1b4570f5937b6dabcb4b6047ff668a770dea8e13533"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x0230a99218df238d4a28664ee700e10a4fdfe98e4a2f5c678bce8c95d5fa04b1"`; -exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x13e55a4c1fb75d2a348ab0abe47aba86992a0cebf5fe2b24243af0246d27d2b5>`; +exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x2328377f64bffa61d6a773e688b4b217b1dca488b8f905d94effe3fbc968111c>`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x0e54342ea9a248adda86b676c762fab4ed8e64f91c28da0f577162870685e5ab>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x20506d5ffb519b1e5763fdfe3c3f84cd6292585bacd024eccca04e31b17b4cfc>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap index fbadc0a1a84b..bffda2922e49 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TxRequest compute hash 1`] = `"0x0d982a1c7a65919b2bcacbf5660f5b861132072a8190d97c82b1591da402f5ea"`; +exports[`TxRequest compute hash 1`] = `"0x249ca45ef4045007021de437e14bf865445f63af6ab5dcc8d78d2b3aa7c58c74"`; diff --git a/yarn-project/circuits.js/src/structs/function_data.test.ts b/yarn-project/circuits.js/src/structs/function_data.test.ts index c39c0a030d37..58abf6a4bcc3 100644 --- a/yarn-project/circuits.js/src/structs/function_data.test.ts +++ b/yarn-project/circuits.js/src/structs/function_data.test.ts @@ -9,7 +9,7 @@ describe('FunctionData', () => { beforeAll(() => { setupCustomSnapshotSerializers(expect); - functionData = new FunctionData(new FunctionSelector(123), true); + functionData = new FunctionData(new FunctionSelector(123), /*isPrivate=*/ true, /*isStatic=*/ false); }); it(`serializes to buffer and deserializes it back`, () => { diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 66be3fd069be..d33a8b2ea8d3 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -13,12 +13,15 @@ export class FunctionData { public selector: FunctionSelector, /** Indicates whether the function is private or public. */ public isPrivate: boolean, + /** Indicates whether the function can alter state or not. */ + public isStatic: boolean, ) {} static fromAbi(abi: FunctionAbi | ContractFunctionDao): FunctionData { return new FunctionData( FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), abi.functionType === FunctionType.SECRET, + abi.isStatic, ); } @@ -27,11 +30,11 @@ export class FunctionData { * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.selector, this.isPrivate); + return serializeToBuffer(this.selector, this.isPrivate, this.isStatic); } toFields(): Fr[] { - const fields = [this.selector.toField(), new Fr(this.isPrivate)]; + const fields = [this.selector.toField(), new Fr(this.isPrivate), new Fr(this.isStatic)]; if (fields.length !== FUNCTION_DATA_LENGTH) { throw new Error( `Invalid number of fields for FunctionData. Expected ${FUNCTION_DATA_LENGTH}, got ${fields.length}`, @@ -56,8 +59,10 @@ export class FunctionData { public static empty(args?: { /** Indicates whether the function is private or public. */ isPrivate?: boolean; + /** Indicates whether the function can alter state or not. */ + isStatic?: boolean; }): FunctionData { - return new FunctionData(FunctionSelector.empty(), args?.isPrivate ?? false); + return new FunctionData(FunctionSelector.empty(), args?.isPrivate ?? false, args?.isStatic ?? false); } /** @@ -67,7 +72,11 @@ export class FunctionData { */ static fromBuffer(buffer: Buffer | BufferReader): FunctionData { const reader = BufferReader.asReader(buffer); - return new FunctionData(reader.readObject(FunctionSelector), reader.readBoolean()); + return new FunctionData( + reader.readObject(FunctionSelector), + /*isPrivate=*/ reader.readBoolean(), + /*isStatic=*/ reader.readBoolean(), + ); } static fromFields(fields: Fr[] | FieldReader): FunctionData { @@ -75,8 +84,9 @@ export class FunctionData { const selector = FunctionSelector.fromFields(reader); const isPrivate = reader.readBoolean(); + const isStatic = reader.readBoolean(); - return new FunctionData(selector, isPrivate); + return new FunctionData(selector, isPrivate, isStatic); } hash(): Fr { diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts index df7c6192b6b5..18719981e9ee 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts @@ -32,7 +32,7 @@ describe('PublicCallStackItem', () => { const callStack = PublicCallStackItem.empty(); callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false); + callStack.functionData = new FunctionData(new FunctionSelector(2), /*isPrivate=*/ false, /*isStatic=*/ false); callStack.isExecutionRequest = true; callStack.publicInputs.newNoteHashes[0] = new NoteHash(new Fr(1), 0); @@ -51,7 +51,7 @@ describe('PublicCallStackItem', () => { const callStack = PublicCallStackItem.empty(); callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false); + callStack.functionData = new FunctionData(new FunctionSelector(2), /*isPrivate=*/ false, /*isStatic=*/ false); callStack.publicInputs.newNoteHashes[0] = new NoteHash(new Fr(1), 0); const hash = callStack.hash(); diff --git a/yarn-project/circuits.js/src/structs/tx_request.test.ts b/yarn-project/circuits.js/src/structs/tx_request.test.ts index f4a44c77fc34..8a62b32b1b9d 100644 --- a/yarn-project/circuits.js/src/structs/tx_request.test.ts +++ b/yarn-project/circuits.js/src/structs/tx_request.test.ts @@ -37,7 +37,7 @@ describe('TxRequest', () => { const gasSettings = new GasSettings(new Gas(2, 2), new Gas(1, 1), new GasFees(3, 3), new Fr(10)); const txRequest = TxRequest.from({ origin: AztecAddress.fromBigInt(1n), - functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), true), + functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), /*isPrivate=*/ true, /*isStatic=*/ false), argsHash: new Fr(3), txContext: new TxContext(Fr.ZERO, Fr.ZERO, gasSettings), }); diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 7eb335efb0b6..7037eabcb359 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -508,7 +508,7 @@ export function makePublicCallRequest(seed = 1): PublicCallRequest { return new PublicCallRequest( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), false), + new FunctionData(makeSelector(seed + 0x1), /*isPrivate=*/ false, /*isStatic=*/ false), childCallContext, parentCallContext, makeTuple(ARGS_LENGTH, fr, seed + 0x10), @@ -637,7 +637,7 @@ export function makePublicCallStackItem(seed = 1, full = false): PublicCallStack const callStackItem = new PublicCallStackItem( makeAztecAddress(seed), // in the public kernel, function can't be a constructor or private - new FunctionData(makeSelector(seed + 0x1), false), + new FunctionData(makeSelector(seed + 0x1), /*isPrivate=*/ false, /*isStatic=*/ false), makePublicCircuitPublicInputs(seed + 0x10, undefined, full), false, ); @@ -723,7 +723,7 @@ export function makePublicKernelInputsWithTweak( export function makeTxRequest(seed = 1): TxRequest { return TxRequest.from({ origin: makeAztecAddress(seed), - functionData: new FunctionData(makeSelector(seed + 0x100), true), + functionData: new FunctionData(makeSelector(seed + 0x100), /*isPrivate=*/ true, /*isStatic=*/ false), argsHash: fr(seed + 0x200), txContext: makeTxContext(seed + 0x400), }); @@ -759,7 +759,7 @@ export function makePrivateCallData(seed = 1): PrivateCallData { export function makePrivateCallStackItem(seed = 1): PrivateCallStackItem { return new PrivateCallStackItem( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), true), + new FunctionData(makeSelector(seed + 0x1), /*isPrivate=*/ true, /*isStatic=*/ false), makePrivateCircuitPublicInputs(seed + 0x10), ); } diff --git a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts index dfde4f8662bf..35405f8b8f50 100644 --- a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts @@ -229,7 +229,8 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), to: this.asset, }, @@ -243,7 +244,8 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [tooMuchFee, this.asset, nonce], }, @@ -264,7 +266,8 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), to: this.asset, }, @@ -280,7 +283,8 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [maxFee, this.asset, nonce], }, @@ -289,7 +293,8 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { to: this.asset, functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), args: [this.wallet.getAddress(), this.paymentContract, new Fr(1), Fr.random()], }, diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index a1c10487adf9..d74e08d5a9c5 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -1,18 +1,19 @@ import { type Wallet } from '@aztec/aztec.js'; -import { ChildContract, ParentContract } from '@aztec/noir-contracts.js'; +import { StaticChildContract, StaticParentContract } from '@aztec/noir-contracts.js'; +import { STATIC_CALL_STATE_MODIFICATION_ERROR, STATIC_CONTEXT_ASSERTION_ERROR } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; describe('e2e_static_calls', () => { let wallet: Wallet; - let parentContract: ParentContract; - let childContract: ChildContract; + let parentContract: StaticParentContract; + let childContract: StaticChildContract; let teardown: () => Promise; beforeAll(async () => { ({ teardown, wallet } = await setup()); - parentContract = await ParentContract.deploy(wallet).send().deployed(); - childContract = await ChildContract.deploy(wallet).send().deployed(); + parentContract = await StaticParentContract.deploy(wallet).send().deployed(); + childContract = await StaticChildContract.deploy(wallet).send().deployed(); // We create a note in the set, such that later reads doesn't fail due to get_notes returning 0 notes await childContract.methods.private_set_value(42n, wallet.getCompleteAddress().address).send().wait(); @@ -20,8 +21,31 @@ describe('e2e_static_calls', () => { afterAll(() => teardown()); + describe('direct view calls to child', () => { + it('performs legal private static calls', async () => { + await childContract.methods.private_get_value(42n, wallet.getCompleteAddress().address).send().wait(); + }); + + it('fails when performing non-static calls to poorly written static private functions', async () => { + await expect( + childContract.methods.private_illegal_set_value(42n, wallet.getCompleteAddress().address).send().wait(), + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('performs legal public static calls', async () => { + await childContract.methods.pub_get_value(42n).send().wait(); + }); + + it('fails when performing non-static calls to poorly written static public functions', async () => { + await expect(childContract.methods.pub_illegal_inc_value(42n).send().wait()).rejects.toThrow( + STATIC_CALL_STATE_MODIFICATION_ERROR, + ); + }); + }); + describe('parent calls child', () => { it('performs legal private to private static calls', async () => { + // Using low level calls await parentContract.methods .private_static_call(childContract.address, childContract.methods.private_get_value.selector, [ 42n, @@ -29,6 +53,12 @@ describe('e2e_static_calls', () => { ]) .send() .wait(); + + // Using the contract interface + await parentContract.methods + .private_get_value_from_child(childContract.address, 42n, wallet.getCompleteAddress().address) + .send() + .wait(); }); it('performs legal (nested) private to private static calls', async () => { @@ -42,10 +72,14 @@ describe('e2e_static_calls', () => { }); it('performs legal public to public static calls', async () => { + // Using low level calls await parentContract.methods .public_static_call(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); + + // Using contract interface + await parentContract.methods.public_get_value_from_child(childContract.address, 42n).send().wait(); }); it('performs legal (nested) public to public static calls', async () => { @@ -56,10 +90,14 @@ describe('e2e_static_calls', () => { }); it('performs legal enqueued public static calls', async () => { + // Using low level calls await parentContract.methods .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); + + // Using contract interface + await parentContract.methods.enqueue_public_get_value_from_child(childContract.address, 42).send().wait(); }); it('performs legal (nested) enqueued public static calls', async () => { @@ -82,7 +120,19 @@ describe('e2e_static_calls', () => { ]) .send() .wait(), - ).rejects.toThrow('Static call cannot create new notes, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing non-static calls to poorly written private static functions', async () => { + await expect( + parentContract.methods + .private_call(childContract.address, childContract.methods.private_illegal_set_value.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CONTEXT_ASSERTION_ERROR); }); it('fails when performing illegal (nested) private to private static calls', async () => { @@ -94,7 +144,7 @@ describe('e2e_static_calls', () => { ]) .send() .wait(), - ).rejects.toThrow('Static call cannot create new notes, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal public to public static calls', async () => { @@ -103,7 +153,7 @@ describe('e2e_static_calls', () => { .public_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal (nested) public to public static calls', async () => { @@ -112,7 +162,7 @@ describe('e2e_static_calls', () => { .public_nested_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal enqueued public static calls', async () => { @@ -123,7 +173,7 @@ describe('e2e_static_calls', () => { ]) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal (nested) enqueued public static calls', async () => { @@ -136,7 +186,115 @@ describe('e2e_static_calls', () => { ) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing non-static enqueue calls to poorly written public static functions', async () => { + await expect( + parentContract.methods + .enqueue_call(childContract.address, childContract.methods.pub_illegal_inc_value.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CONTEXT_ASSERTION_ERROR); + }); + }); + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/5818): clean up the following tests and either remove the "public" version above or rename these to be the new public. + // There should be 1:1 correspondence between the two sets of tests. + describe('avm', () => { + describe('direct view calls to child', () => { + it('performs legal public static calls', async () => { + await childContract.methods.avm_get_value(42n).send().wait(); + }); + + it('fails when performing non-static calls to poorly written static public functions', async () => { + await expect(childContract.methods.avm_illegal_inc_value(42n).send().wait()).rejects.toThrow( + STATIC_CALL_STATE_MODIFICATION_ERROR, + ); + }); + }); + + describe('parent calls child', () => { + it('performs legal public to public static calls', async () => { + // Using low level calls + await parentContract.methods + .avm_static_call(childContract.address, childContract.methods.avm_get_value.selector, [42n]) + .send() + .wait(); + + // Using contract interface + await parentContract.methods.public_get_value_from_child(childContract.address, 42n).send().wait(); + }); + + it('performs legal enqueued public static calls', async () => { + // Using low level calls + await parentContract.methods + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.avm_get_value.selector, [ + 42n, + ]) + .send() + .wait(); + + // Using contract interface + await parentContract.methods.enqueue_avm_get_value_from_child(childContract.address, 42).send().wait(); + }); + + it('performs legal (nested) public to public static calls', async () => { + await parentContract.methods + .avm_nested_static_call(childContract.address, childContract.methods.avm_get_value.selector, [42n]) + .send() + .wait(); + }); + + it('performs legal (nested) enqueued public static calls', async () => { + await parentContract.methods + .enqueue_static_nested_call_to_avm_function( + childContract.address, + childContract.methods.avm_get_value.selector, + [42n], + ) + .send() + .wait(); + }); + + it('fails when performing illegal enqueued public static calls', async () => { + await expect( + parentContract.methods + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.avm_set_value.selector, [ + 42n, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing illegal (nested) enqueued public static calls', async () => { + await expect( + parentContract.methods + .enqueue_static_nested_call_to_avm_function( + childContract.address, + childContract.methods.avm_set_value.selector, + [42n], + ) + .send() + .wait(), + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing non-static enqueue calls to poorly written public static functions', async () => { + await expect( + parentContract.methods + .enqueue_call(childContract.address, childContract.methods.avm_illegal_inc_value.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CONTEXT_ASSERTION_ERROR); + }); }); }); }); diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index ec11d1ae340a..25e9922b5cb8 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -10,3 +10,6 @@ export const BITSIZE_TOO_BIG_ERROR = "'self.__assert_max_bit_size(bit_size)'"; export const DUPLICATE_NULLIFIER_ERROR = /dropped|duplicate nullifier|reverted/; export const NO_L1_TO_L2_MSG_ERROR = /No non-nullified L1 to L2 message found for message hash|Tried to consume nonexistent L1-to-L2 message/; +export const STATIC_CALL_STATE_MODIFICATION_ERROR = + /Static call cannot update the state, emit L2->L1 messages or generate logs.*/; +export const STATIC_CONTEXT_ASSERTION_ERROR = /Assertion failed: Function .* can only be called statically.*/; diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index b750f3232f0b..87e9a8f1023f 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -48,6 +48,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { isInitializer: false, functionType: 'secret', isInternal: false, + isStatic: false, parameters: [ { name: 'app_payload', @@ -82,6 +83,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, @@ -124,6 +126,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index b80307dfc3ac..2aca62739c7a 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -61,6 +61,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { isInitializer: false, functionType: 'secret', isInternal: false, + isStatic: false, parameters: [ { name: 'payload', @@ -95,6 +96,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index ff1be9bcdd75..da33e70473b5 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -165,6 +165,10 @@ export interface FunctionAbi { * Whether the function is internal. */ isInternal: boolean; + /** + * Whether the function can alter state or not + */ + isStatic: boolean; /** * Function parameters. */ diff --git a/yarn-project/foundation/src/abi/encoder.test.ts b/yarn-project/foundation/src/abi/encoder.test.ts index f78e1325dfd9..a38b963e9d03 100644 --- a/yarn-project/foundation/src/abi/encoder.test.ts +++ b/yarn-project/foundation/src/abi/encoder.test.ts @@ -11,6 +11,7 @@ describe('abi/encoder', () => { functionType: FunctionType.SECRET, isInternal: false, isInitializer: true, + isStatic: false, parameters: [ { name: 'owner', @@ -33,6 +34,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -57,6 +59,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -82,6 +85,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -117,6 +121,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'contract_class', @@ -148,6 +153,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -170,6 +176,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'isOwner', @@ -195,6 +202,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts index f03c01e18763..5ba1e2b0b2aa 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts @@ -47,7 +47,7 @@ describe('Noir<>Circuits.js type conversion test suite', () => { expect(mapFunctionSelectorFromNoir(mapFunctionSelectorToNoir(functionSelector))).toEqual(functionSelector); }); - const functionData = new FunctionData(functionSelector, true); + const functionData = new FunctionData(functionSelector, /*isPrivate=*/ true, /*isStatic=*/ false); it('should map function data', () => { expect(mapFunctionDataFromNoir(mapFunctionDataToNoir(functionData))).toEqual(functionData); diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index b2ccda0887fc..360c3f19bd3d 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -406,6 +406,7 @@ export function mapFunctionDataToNoir(functionData: FunctionData): FunctionDataN return { selector: mapFunctionSelectorToNoir(functionData.selector), is_private: functionData.isPrivate, + is_static: functionData.isStatic, }; } @@ -415,7 +416,11 @@ export function mapFunctionDataToNoir(functionData: FunctionData): FunctionDataN * @returns The function data. */ export function mapFunctionDataFromNoir(functionData: FunctionDataNoir): FunctionData { - return new FunctionData(mapFunctionSelectorFromNoir(functionData.selector), functionData.is_private); + return new FunctionData( + mapFunctionSelectorFromNoir(functionData.selector), + functionData.is_private, + functionData.is_static, + ); } /** diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 91c007958419..c94dd96973ac 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -45,6 +45,7 @@ import { Timer } from '@aztec/foundation/timer'; import { type AcirSimulator, type ExecutionResult, + accumulateReturnValues, collectEnqueuedPublicFunctionCalls, collectPublicTeardownFunctionCall, collectSortedEncryptedLogs, @@ -465,7 +466,7 @@ export class PXEService implements PXE { return txHash; } - public async viewTx( + public async simulateUnconstrained( functionName: string, args: any[], to: AztecAddress, @@ -681,7 +682,8 @@ export class PXEService implements PXE { enqueuedPublicFunctions, teardownPublicFunction, ); - return new SimulatedTx(tx, executionResult.returnValues); + + return new SimulatedTx(tx, accumulateReturnValues(executionResult)); } /** diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index f367253bdeb3..6d7422be7b4f 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -143,7 +143,7 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => ); }); - // Note: Not testing a successful run of `proveTx`, `sendTx`, `getTxReceipt` and `viewTx` here as it requires + // Note: Not testing a successful run of `proveTx`, `sendTx`, `getTxReceipt` and `simulateUnconstrained` here as it requires // a larger setup and it's sufficiently tested in the e2e tests. it('throws when getting public storage for non-existent contract', async () => { diff --git a/yarn-project/simulator/src/avm/avm_execution_environment.ts b/yarn-project/simulator/src/avm/avm_execution_environment.ts index e57f94eecda0..411b9d60ff49 100644 --- a/yarn-project/simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/simulator/src/avm/avm_execution_environment.ts @@ -1,15 +1,15 @@ import { FunctionSelector, type GasSettings, type GlobalVariables, type Header } from '@aztec/circuits.js'; import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { type Fr } from '@aztec/foundation/fields'; +import { Fr } from '@aztec/foundation/fields'; export class AvmContextInputs { - static readonly SIZE = 2; + static readonly SIZE = 3; - constructor(private selector: Fr, private argsHash: Fr) {} + constructor(private selector: Fr, private argsHash: Fr, private isStaticCall: boolean) {} public toFields(): Fr[] { - return [this.selector, this.argsHash]; + return [this.selector, this.argsHash, new Fr(this.isStaticCall)]; } } @@ -41,7 +41,11 @@ export class AvmExecutionEnvironment { ) { // We encode some extra inputs (AvmContextInputs) in calldata. // This will have to go once we move away from one proof per call. - const inputs = new AvmContextInputs(temporaryFunctionSelector.toField(), computeVarArgsHash(calldata)); + const inputs = new AvmContextInputs( + temporaryFunctionSelector.toField(), + computeVarArgsHash(calldata), + isStaticCall, + ); this.calldata = [...inputs.toFields(), ...calldata]; } diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 8c06e9b1b768..148cddf078eb 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -439,7 +439,7 @@ export class ClientExecutionContext extends ViewDataOracle { childExecutionResult.callStackItem.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) || childExecutionResult.callStackItem.publicInputs.unencryptedLogsHashes.some(item => !item.isEmpty()) ) { - throw new Error(`Static call cannot create new notes, emit L2->L1 messages or generate logs`); + throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`); } } @@ -450,7 +450,7 @@ export class ClientExecutionContext extends ViewDataOracle { * @param argsHash - The packed arguments to pass to the function. * @param sideEffectCounter - The side effect counter at the start of the call. * @param isStaticCall - Whether the call is a static call. - * @param isStaticCall - Whether the call is a delegate call. + * @param isDelegateCall - Whether the call is a delegate call. * @returns The execution result. */ override async callPrivateFunction( diff --git a/yarn-project/simulator/src/client/simulator.ts b/yarn-project/simulator/src/client/simulator.ts index 1c3c8490f84d..90ea5d3deee0 100644 --- a/yarn-project/simulator/src/client/simulator.ts +++ b/yarn-project/simulator/src/client/simulator.ts @@ -88,7 +88,7 @@ export class AcirSimulator { contractAddress, FunctionSelector.fromNameAndParameters(entryPointArtifact.name, entryPointArtifact.parameters), false, - false, + entryPointArtifact.isStatic, startSideEffectCounter, ); const context = new ClientExecutionContext( diff --git a/yarn-project/simulator/src/client/unconstrained_execution.test.ts b/yarn-project/simulator/src/client/unconstrained_execution.test.ts index 9077aa0489eb..5a901e8aedaf 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.test.ts @@ -63,7 +63,7 @@ describe('Unconstrained Execution test suite', () => { const execRequest: FunctionCall = { to: contractAddress, - functionData: new FunctionData(FunctionSelector.empty(), true), + functionData: new FunctionData(FunctionSelector.empty(), /*isPrivate=*/ true, /*isStatic=*/ false), args: encodeArguments(artifact, [owner]), }; diff --git a/yarn-project/simulator/src/common/index.ts b/yarn-project/simulator/src/common/index.ts index 9e61c2e99e57..b10327ec983b 100644 --- a/yarn-project/simulator/src/common/index.ts +++ b/yarn-project/simulator/src/common/index.ts @@ -1,3 +1,4 @@ export * from './packed_values_cache.js'; export * from './errors.js'; export * from './side_effect_counter.js'; +export * from './return_values.js'; diff --git a/yarn-project/simulator/src/common/return_values.ts b/yarn-project/simulator/src/common/return_values.ts new file mode 100644 index 000000000000..1878c8c673d2 --- /dev/null +++ b/yarn-project/simulator/src/common/return_values.ts @@ -0,0 +1,18 @@ +import { NestedProcessReturnValues } from '@aztec/circuit-types'; + +import type { ExecutionResult } from '../client/execution_result.js'; +import type { PublicExecutionResult } from '../public/execution.js'; + +/** + * Recursively accummulate the return values of a call result and its nested executions, + * so they can be retrieved in order. + * @param executionResult + * @returns + */ +export function accumulateReturnValues( + executionResult: PublicExecutionResult | ExecutionResult, +): NestedProcessReturnValues { + const acc = new NestedProcessReturnValues(executionResult.returnValues); + acc.nested = executionResult.nestedExecutions.map(nestedExecution => accumulateReturnValues(nestedExecution)); + return acc; +} diff --git a/yarn-project/simulator/src/mocks/fixtures.ts b/yarn-project/simulator/src/mocks/fixtures.ts index da4763a3ca0c..3b2ca84d697d 100644 --- a/yarn-project/simulator/src/mocks/fixtures.ts +++ b/yarn-project/simulator/src/mocks/fixtures.ts @@ -133,7 +133,7 @@ export const makeFunctionCall = ( to = makeAztecAddress(30), selector = makeSelector(5), args = new Array(ARGS_LENGTH).fill(Fr.ZERO), -) => ({ to, functionData: new FunctionData(selector, false), args }); +) => ({ to, functionData: new FunctionData(selector, /*isPrivate=*/ false, /*isStatic=*/ false), args }); export function addKernelPublicCallStack( kernelOutput: PrivateKernelTailCircuitPublicInputs, diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index f9c0dd25afff..2d066f8345f2 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -1,6 +1,6 @@ import { MerkleTreeId, - type ProcessReturnValues, + type NestedProcessReturnValues, type PublicKernelRequest, PublicKernelType, type SimulationError, @@ -57,6 +57,7 @@ import { type PublicExecution, type PublicExecutionResult, type PublicExecutor, + accumulateReturnValues, collectPublicDataReads, collectPublicDataUpdateRequests, isPublicExecutionResult, @@ -140,7 +141,7 @@ export abstract class AbstractPhaseManager { * revert reason, if any */ revertReason: SimulationError | undefined; - returnValues: ProcessReturnValues; + returnValues: NestedProcessReturnValues[]; /** Gas used during the execution this particular phase. */ gasUsed: Gas | undefined; }>; @@ -227,7 +228,7 @@ export abstract class AbstractPhaseManager { Proof, UnencryptedFunctionL2Logs[], SimulationError | undefined, - ProcessReturnValues, + NestedProcessReturnValues[], Gas, ] > { @@ -238,7 +239,7 @@ export abstract class AbstractPhaseManager { const enqueuedCalls = this.extractEnqueuedPublicCalls(tx); if (!enqueuedCalls || !enqueuedCalls.length) { - return [[], kernelOutput, kernelProof, [], undefined, undefined, Gas.empty()]; + return [[], kernelOutput, kernelProof, [], undefined, [], Gas.empty()]; } const newUnencryptedFunctionLogs: UnencryptedFunctionL2Logs[] = []; @@ -250,9 +251,10 @@ export abstract class AbstractPhaseManager { // separate public callstacks to be proven by separate public kernel sequences // and submitted separately to the base rollup? - let returns: ProcessReturnValues = undefined; let gasUsed = Gas.empty(); + const enqueuedCallResults = []; + for (const enqueuedCall of enqueuedCalls) { const executionStack: (PublicExecution | PublicExecutionResult)[] = [enqueuedCall]; @@ -334,13 +336,14 @@ export abstract class AbstractPhaseManager { }`, ); // TODO(@spalladino): Check gasUsed is correct. The AVM should take care of setting gasLeft to zero upon a revert. - return [[], kernelOutput, kernelProof, [], result.revertReason, undefined, gasUsed]; + return [[], kernelOutput, kernelProof, [], result.revertReason, [], gasUsed]; } if (!enqueuedExecutionResult) { enqueuedExecutionResult = result; - returns = result.returnValues; } + + enqueuedCallResults.push(accumulateReturnValues(enqueuedExecutionResult)); } // HACK(#1622): Manually patches the ordering of public state actions // TODO(#757): Enforce proper ordering of public state actions @@ -350,7 +353,15 @@ export abstract class AbstractPhaseManager { // TODO(#3675): This should be done in a public kernel circuit removeRedundantPublicDataWrites(kernelOutput, this.phase); - return [publicKernelInputs, kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined, returns, gasUsed]; + return [ + publicKernelInputs, + kernelOutput, + kernelProof, + newUnencryptedFunctionLogs, + undefined, + enqueuedCallResults, + gasUsed, + ]; } /** Returns all pending private and public nullifiers. */ diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index fb3d199d30ce..2923b7dd0b57 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -184,7 +184,7 @@ describe('ACIR public execution simulator', () => { beforeEach(() => { transferArtifact = TokenContractArtifact.functions.find(f => f.name === 'transfer_public')!; - functionData = new FunctionData(FunctionSelector.empty(), false); + functionData = new FunctionData(FunctionSelector.empty(), /*isPrivate=*/ false, /*isStatic=*/ false); sender = AztecAddress.random(); args = encodeArguments(transferArtifact, [sender, recipient, 140n, 0n]); @@ -265,7 +265,7 @@ describe('ACIR public execution simulator', () => { parentEntryPointFn.name, parentEntryPointFn.parameters, ); - functionData = new FunctionData(parentEntryPointFnSelector, false); + functionData = new FunctionData(parentEntryPointFnSelector, /*isPrivate=*/ false, /*isStatic=*/ false); childContractAddress = AztecAddress.random(); callContext = makeCallContext(parentContractAddress); }, 10000); @@ -354,7 +354,7 @@ describe('ACIR public execution simulator', () => { beforeEach(async () => { contractAddress = AztecAddress.random(); await mockInitializationNullifierCallback(contractAddress); - functionData = new FunctionData(FunctionSelector.empty(), false); + functionData = new FunctionData(FunctionSelector.empty(), /*isPrivate=*/ false, /*isStatic=*/ false); amount = new Fr(1); params = [amount, new Fr(1)]; }); diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index e8c6fefcda83..144c00ee509d 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -212,7 +212,7 @@ export class PublicExecutionContext extends TypedOracle { `Public function call: addr=${targetContractAddress} selector=${functionSelector} args=${args.join(',')}`, ); - const functionData = new FunctionData(functionSelector, /*isPrivate=*/ false); + const functionData = new FunctionData(functionSelector, /*isPrivate=*/ false, /*isStatic=*/ false); const callContext = CallContext.from({ msgSender: isDelegateCall ? this.execution.callContext.msgSender : this.execution.contractAddress, storageContractAddress: isDelegateCall ? this.execution.contractAddress : targetContractAddress, diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index 360ed52b8891..e17b20f17ed2 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -1,7 +1,7 @@ import { type BlockProver, type FailedTx, - type ProcessReturnValues, + NestedProcessReturnValues, type ProcessedTx, type PublicKernelRequest, type SimulationError, @@ -96,12 +96,12 @@ export class PublicProcessor { maxTransactions = txs.length, blockProver?: BlockProver, txValidator?: TxValidator, - ): Promise<[ProcessedTx[], FailedTx[], ProcessReturnValues[]]> { + ): Promise<[ProcessedTx[], FailedTx[], NestedProcessReturnValues[]]> { // The processor modifies the tx objects in place, so we need to clone them. txs = txs.map(tx => Tx.clone(tx)); const result: ProcessedTx[] = []; const failed: FailedTx[] = []; - const returns: ProcessReturnValues[] = []; + const returns: NestedProcessReturnValues[] = []; for (const tx of txs) { // only process up to the limit of the block @@ -129,7 +129,7 @@ export class PublicProcessor { await blockProver.addNewTx(processedTx); } result.push(processedTx); - returns.push(returnValues); + returns.push(returnValues?.[0] ?? new NestedProcessReturnValues([])); } catch (err: any) { const errorMessage = err instanceof Error ? err.message : 'Unknown error'; this.log.warn(`Failed to process tx ${tx.getTxHash()}: ${errorMessage}`); @@ -138,7 +138,7 @@ export class PublicProcessor { tx, error: err instanceof Error ? err : new Error(errorMessage), }); - returns.push([]); + returns.push(new NestedProcessReturnValues([])); } } @@ -154,8 +154,8 @@ export class PublicProcessor { return makeEmptyProcessedTx(this.historicalHeader.clone(), chainId, version); } - private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, ProcessReturnValues | undefined]> { - let returnValues: ProcessReturnValues = undefined; + private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> { + let returnValues: NestedProcessReturnValues[] = []; const publicRequests: PublicKernelRequest[] = []; let phase: AbstractPhaseManager | undefined = PhaseManagerFactory.phaseFromTx( tx, diff --git a/yarn-project/simulator/src/public/setup_phase_manager.ts b/yarn-project/simulator/src/public/setup_phase_manager.ts index 33581b36f5b0..0573f57ca4da 100644 --- a/yarn-project/simulator/src/public/setup_phase_manager.ts +++ b/yarn-project/simulator/src/public/setup_phase_manager.ts @@ -67,7 +67,7 @@ export class SetupPhaseManager extends AbstractPhaseManager { publicKernelOutput, publicKernelProof, revertReason, - returnValues: undefined, + returnValues: [], gasUsed, }; } diff --git a/yarn-project/simulator/src/public/tail_phase_manager.ts b/yarn-project/simulator/src/public/tail_phase_manager.ts index be324885e6f3..f3c406357930 100644 --- a/yarn-project/simulator/src/public/tail_phase_manager.ts +++ b/yarn-project/simulator/src/public/tail_phase_manager.ts @@ -70,7 +70,7 @@ export class TailPhaseManager extends AbstractPhaseManager { finalKernelOutput, publicKernelProof: makeEmptyProof(), revertReason: undefined, - returnValues: undefined, + returnValues: [], gasUsed: undefined, }; } diff --git a/yarn-project/simulator/src/public/teardown_phase_manager.ts b/yarn-project/simulator/src/public/teardown_phase_manager.ts index 55b1b7656303..7a40812a46ca 100644 --- a/yarn-project/simulator/src/public/teardown_phase_manager.ts +++ b/yarn-project/simulator/src/public/teardown_phase_manager.ts @@ -71,7 +71,7 @@ export class TeardownPhaseManager extends AbstractPhaseManager { publicKernelOutput, publicKernelProof, revertReason, - returnValues: undefined, + returnValues: [], gasUsed, }; } diff --git a/yarn-project/simulator/src/public/transitional_adaptors.ts b/yarn-project/simulator/src/public/transitional_adaptors.ts index 74e6d0047887..0f2248e348c8 100644 --- a/yarn-project/simulator/src/public/transitional_adaptors.ts +++ b/yarn-project/simulator/src/public/transitional_adaptors.ts @@ -65,7 +65,11 @@ export function createPublicExecution( isStaticCall: avmEnvironment.isStaticCall, sideEffectCounter: startSideEffectCounter, }); - const functionData = new FunctionData(avmEnvironment.temporaryFunctionSelector, /*isPrivate=*/ false); + const functionData = new FunctionData( + avmEnvironment.temporaryFunctionSelector, + /*isPrivate=*/ false, + /*isStatic=*/ false, + ); const execution: PublicExecution = { contractAddress: avmEnvironment.address, callContext, diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 0998899167ec..9758e85650d5 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -20,6 +20,7 @@ import { AZTEC_PRIVATE_ATTRIBUTE, AZTEC_PUBLIC_ATTRIBUTE, AZTEC_PUBLIC_VM_ATTRIBUTE, + AZTEC_VIEW_ATTRIBUTE, type NoirCompiledContract, } from '../noir/index.js'; import { mockVerificationKey } from './mocked_keys.js'; @@ -138,6 +139,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No } const functionType = getFunctionType(fn); const isInternal = fn.custom_attributes.includes(AZTEC_INTERNAL_ATTRIBUTE); + const isStatic = fn.custom_attributes.includes(AZTEC_VIEW_ATTRIBUTE); // If the function is not unconstrained, the first item is inputs or CallContext which we should omit let parameters = fn.abi.parameters.map(generateFunctionParameter); @@ -170,6 +172,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No name: fn.name, functionType, isInternal, + isStatic, isInitializer: fn.custom_attributes.includes(AZTEC_INITIALIZER_ATTRIBUTE), parameters, returnTypes, diff --git a/yarn-project/types/src/noir/index.ts b/yarn-project/types/src/noir/index.ts index 56a449d8ef03..f268071eae0a 100644 --- a/yarn-project/types/src/noir/index.ts +++ b/yarn-project/types/src/noir/index.ts @@ -12,6 +12,7 @@ export const AZTEC_PUBLIC_ATTRIBUTE = 'aztec(public)'; export const AZTEC_PUBLIC_VM_ATTRIBUTE = 'aztec(public-vm)'; export const AZTEC_INTERNAL_ATTRIBUTE = 'aztec(internal)'; export const AZTEC_INITIALIZER_ATTRIBUTE = 'aztec(initializer)'; +export const AZTEC_VIEW_ATTRIBUTE = 'aztec(view)'; /** The witness indices of the parameters. */ type ParamWitnessIndices = { /** Start */ start: number; /** End */ end: number };