From c2747cbb21ff4a8d2298736f0e20bb31841b085f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 24 Aug 2023 19:52:20 +0200 Subject: [PATCH] feat: `FunctionSelector` type (#1518) Fixes #1424 --- .../cpp/src/aztec3/circuits/abis/.test.cpp | 10 +- .../src/aztec3/circuits/abis/c_bind.test.cpp | 12 +- .../aztec3/circuits/abis/function_data.hpp | 12 +- .../circuits/abis/function_leaf_preimage.hpp | 14 +- .../circuits/abis/function_selector.hpp | 59 +++++++ .../cpp/src/aztec3/circuits/apps/.test.cpp | 5 +- .../cpp/src/aztec3/circuits/apps/contract.tpp | 6 +- .../apps/function_execution_context.hpp | 5 +- .../circuits/apps/test_apps/escrow/.test.cpp | 5 +- .../.test.cpp | 5 +- circuits/cpp/src/aztec3/circuits/hash.hpp | 4 +- ...ative_private_kernel_circuit_init.test.cpp | 4 +- .../kernel/private/testing_harness.cpp | 5 +- .../aztec3/circuits/kernel/public/.test.cpp | 14 +- .../aztec3/circuits/kernel/public/common.hpp | 2 +- .../acir-simulator/src/acvm/deserialize.ts | 9 -- .../acir-simulator/src/acvm/serialize.ts | 2 +- .../acir-simulator/src/client/db_oracle.ts | 6 +- .../src/client/function_selectors.ts | 8 +- .../src/client/private_execution.test.ts | 40 +++-- .../src/client/private_execution.ts | 16 +- .../client/unconstrained_execution.test.ts | 4 +- .../src/client/unconstrained_execution.ts | 4 +- yarn-project/acir-simulator/src/public/db.ts | 10 +- .../acir-simulator/src/public/executor.ts | 17 +-- .../acir-simulator/src/public/index.test.ts | 14 +- .../archiver/src/archiver/archiver.ts | 7 +- .../src/aztec_rpc_server/aztec_rpc_server.ts | 10 +- .../src/contract_data_oracle/index.ts | 26 ++-- .../memory_contract_database.ts | 7 +- .../aztec-rpc/src/contract_tree/index.ts | 28 ++-- .../aztec-rpc/src/kernel_oracle/index.ts | 6 +- .../src/kernel_prover/kernel_prover.ts | 2 +- .../src/kernel_prover/proving_data_oracle.ts | 5 +- .../aztec-rpc/src/simulator_oracle/index.ts | 10 +- .../examples/uniswap_trade_on_l1_from_l2.ts | 2 +- .../account/entrypoint/entrypoint_payload.ts | 2 +- .../aztec.js/src/contract/contract_base.ts | 6 +- .../src/uniswap_trade_on_l1_from_l2.test.ts | 2 +- .../src/abis/__snapshots__/abis.test.ts.snap | 2 +- .../circuits.js/src/abis/abis.test.ts | 22 +-- .../circuits.js/src/cbind/circuits.gen.ts | 29 +++- yarn-project/circuits.js/src/cbind/types.ts | 1 + .../src/contract/contract_deployment_info.ts | 4 +- .../contract/contract_tree/contract_tree.ts | 4 +- .../__snapshots__/function_data.test.ts.snap | 4 +- .../function_leaf_preimage.test.ts.snap | 4 +- .../src/structs/function_data.test.ts | 4 +- .../circuits.js/src/structs/function_data.ts | 45 ++---- .../structs/function_leaf_preimage.test.ts | 3 +- .../src/structs/function_leaf_preimage.ts | 27 +--- yarn-project/circuits.js/src/structs/index.ts | 1 + .../kernel/__snapshots__/index.test.ts.snap | 144 +++++++++++++----- .../__snapshots__/base_rollup.test.ts.snap | 32 +++- .../circuits.js/src/tests/factories.ts | 7 +- .../src/types/contract_function_dao.ts | 4 +- .../src/e2e_escrow_contract.test.ts | 7 +- .../end-to-end/src/e2e_multi_transfer.test.ts | 6 +- .../src/e2e_nested_contract.test.ts | 22 +-- .../end-to-end/src/e2e_ordering.test.ts | 4 +- .../e2e_pending_commitments_contract.test.ts | 26 ++-- .../src/uniswap_trade_on_l1_from_l2.test.ts | 2 +- yarn-project/foundation/src/abi/abi_coder.ts | 39 +---- .../foundation/src/abi/function_selector.ts | 111 ++++++++++++++ yarn-project/foundation/src/abi/index.ts | 1 + .../src/contract-interface-gen/noir.ts | 12 +- .../src/sequencer/public_processor.ts | 2 +- .../src/simulator/public_executor.ts | 10 +- yarn-project/types/src/contract_dao.ts | 6 +- yarn-project/types/src/contract_data.ts | 20 +-- 70 files changed, 621 insertions(+), 389 deletions(-) create mode 100644 circuits/cpp/src/aztec3/circuits/abis/function_selector.hpp create mode 100644 yarn-project/foundation/src/abi/function_selector.ts diff --git a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp index 0bee851c6627..124d48d02607 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp @@ -51,7 +51,10 @@ TEST(abi_tests, native_read_write_call_context) TEST(abi_tests, native_read_write_function_data) { FunctionData const function_data = { - .function_selector = 11, + .function_selector = + FunctionSelector{ + .value = 11, + }, .is_private = false, .is_constructor = false, }; @@ -67,7 +70,10 @@ TEST(abi_tests, native_read_write_function_data) TEST(abi_tests, native_to_circuit_function_data) { FunctionData const native_function_data = { - .function_selector = 11, + .function_selector = + FunctionSelector{ + .value = 11, + }, .is_private = false, .is_constructor = false, }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index a4b88a03ae30..c945a51d388a 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -191,7 +191,10 @@ TEST(abi_tests, compute_function_leaf) { // Construct FunctionLeafPreimage with some randomized fields auto const preimage = FunctionLeafPreimage{ - .function_selector = engine.get_random_uint32(), + .function_selector = + FunctionSelector{ + .value = engine.get_random_uint32(), + }, .is_private = static_cast(engine.get_random_uint8() & 1), .vk_hash = NT::fr::random_element(), .acir_hash = NT::fr::random_element(), @@ -279,7 +282,12 @@ TEST(abi_tests, compute_function_tree) TEST(abi_tests, hash_constructor) { // Randomize required values - auto const func_data = FunctionData{ .function_selector = 10, .is_private = true, .is_constructor = false }; + auto const func_data = FunctionData{ .function_selector = + FunctionSelector{ + .value = 10, + }, + .is_private = true, + .is_constructor = false }; NT::fr const args_hash = NT::fr::random_element(); NT::fr const constructor_vk_hash = NT::fr::random_element(); diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp index 05b72821a3f6..6941639ab1e9 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp @@ -1,5 +1,6 @@ #pragma once +#include "aztec3/circuits/abis/function_selector.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" @@ -17,7 +18,7 @@ template struct FunctionData { using boolean = typename NCT::boolean; using fr = typename NCT::fr; - uint32 function_selector; // e.g. 1st 4-bytes of abi-encoding of function. + FunctionSelector function_selector; boolean is_internal = false; boolean is_private = false; boolean is_constructor = false; @@ -38,7 +39,7 @@ template struct FunctionData { auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; FunctionData> function_data = { - to_ct(function_selector), + function_selector.to_circuit_type(builder), to_ct(is_internal), to_ct(is_private), to_ct(is_constructor), @@ -50,10 +51,11 @@ template struct FunctionData { template FunctionData to_native_type() const { static_assert(std::is_same, NCT>::value); + auto to_native_type = [](T& e) { return e.template to_native_type(); }; auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; FunctionData function_data = { - to_nt(function_selector), + to_native_type(function_selector), to_nt(is_internal), to_nt(is_private), to_nt(is_constructor), @@ -66,7 +68,7 @@ template struct FunctionData { { static_assert(!(std::is_same::value)); - fr(function_selector).set_public(); + function_selector.set_public(); fr(is_internal).set_public(); fr(is_private).set_public(); fr(is_constructor).set_public(); @@ -76,7 +78,7 @@ template struct FunctionData { fr hash() const { std::vector const inputs = { - fr(function_selector), + fr(function_selector.value), fr(is_internal), fr(is_private), fr(is_constructor), diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp index 34b74ba5e4b7..38160b6a3b04 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp @@ -1,5 +1,6 @@ #pragma once +#include "aztec3/circuits/abis/function_selector.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" @@ -31,7 +32,7 @@ template struct FunctionLeafPreimage { using fr = typename NCT::fr; using uint32 = typename NCT::uint32; - uint32 function_selector = 0; + FunctionSelector function_selector = {}; boolean is_internal = false; boolean is_private = false; fr vk_hash = 0; @@ -54,7 +55,11 @@ template struct FunctionLeafPreimage { auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; FunctionLeafPreimage> preimage = { - to_ct(function_selector), to_ct(is_internal), to_ct(is_private), to_ct(vk_hash), to_ct(acir_hash), + function_selector.to_circuit_type(builder), + to_ct(is_internal), + to_ct(is_private), + to_ct(vk_hash), + to_ct(acir_hash), }; return preimage; @@ -63,10 +68,11 @@ template struct FunctionLeafPreimage { template FunctionLeafPreimage to_native_type() const { static_assert(std::is_same, NCT>::value); + auto to_native_type = [](T& e) { return e.template to_native_type(); }; auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; FunctionLeafPreimage preimage = { - to_nt(function_selector), to_nt(is_internal), to_nt(is_private), to_nt(vk_hash), to_nt(acir_hash), + to_native_type(function_selector), to_nt(is_internal), to_nt(is_private), to_nt(vk_hash), to_nt(acir_hash), }; return preimage; @@ -86,7 +92,7 @@ template struct FunctionLeafPreimage { fr hash() const { std::vector const inputs = { - function_selector, fr(is_internal), fr(is_private), vk_hash, acir_hash, + function_selector.value, fr(is_internal), fr(is_private), vk_hash, acir_hash, }; return NCT::compress(inputs, GeneratorIndex::FUNCTION_LEAF); } diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_selector.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_selector.hpp new file mode 100644 index 000000000000..aebd4c2400a5 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/function_selector.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/convert.hpp" +#include "aztec3/utils/types/native_types.hpp" + +#include "barretenberg/serialize/msgpack.hpp" + +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; + +template struct FunctionSelector { + using uint32 = typename NCT::uint32; + using boolean = typename NCT::boolean; + using fr = typename NCT::fr; + + uint32 value; // e.g. 1st 4-bytes of abi-encoding of function. + + MSGPACK_FIELDS(value); + + boolean operator==(FunctionSelector const& other) const { return value == other.value; }; + + template FunctionSelector> to_circuit_type(Builder& builder) const + { + static_assert((std::is_same::value)); + + // Capture the circuit builder: + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; + + FunctionSelector> function_selector = { + to_ct(value), + }; + + return function_selector; + }; + + template FunctionSelector to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; + + FunctionSelector function_selector = { + to_nt(value), + }; + + return function_selector; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + fr(value).set_public(); + } +}; + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/apps/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp index ab4ca379df42..2604e1484040 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp @@ -75,7 +75,10 @@ class state_var_tests : public ::testing::Test { uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); FunctionData const function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. + .function_selector = + FunctionSelector{ + .value = 1, // TODO: deduce this from the contract, somehow. + }, .is_private = true, .is_constructor = false, }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp index 5eb8dcd04c9c..5f1fa493ea77 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp @@ -13,6 +13,7 @@ namespace aztec3::circuits::apps { using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::FunctionData; +using aztec3::circuits::abis::FunctionSelector; template void Contract::set_functions(std::vector> const& functions) { @@ -22,7 +23,10 @@ template void Contract::set_functions(std::vector{ - .function_selector = static_cast(i), + .function_selector = + FunctionSelector{ + .value = static_cast(i), + }, .is_private = function.is_private, .is_constructor = function.is_constructor, }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp index db3a10fe60f9..2ec0bc59a6fa 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp @@ -178,7 +178,10 @@ template class FunctionExecutionContext { const FunctionData f_function_data_ct{ // Note: we MUST - .function_selector = f_encoding_ct, + .function_selector = + FunctionSelector{ + .value = f_encoding_ct, + }, .is_private = true, .is_constructor = false, }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 5e68463937ed..a001d49f1920 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -16,7 +16,10 @@ class escrow_tests : public ::testing::Test { uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); FunctionData const function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. + .function_selector = + FunctionSelector{ + .value = 1, // TODO: deduce this from the contract, somehow. + }, .is_private = true, .is_constructor = false, }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index ba7acefda62f..cf7ed49a0f5a 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -22,7 +22,10 @@ TEST(private_to_private_function_call_tests, circuit_private_to_private_function uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); const FunctionData function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. + .function_selector = + FunctionSelector{ + .value = 1, // TODO: deduce this from the contract, somehow. + }, .is_private = true, .is_constructor = false, }; diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 896dad37ab26..b7b06f864441 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -2,6 +2,7 @@ #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/function_leaf_preimage.hpp" +#include "aztec3/circuits/abis/function_selector.hpp" #include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/point.hpp" @@ -16,6 +17,7 @@ namespace aztec3::circuits { using abis::FunctionData; +using abis::FunctionSelector; using abis::Point; using aztec3::circuits::abis::ContractLeafPreimage; using aztec3::circuits::abis::FunctionLeafPreimage; @@ -303,7 +305,7 @@ void check_membership(Builder& builder, * @return NCT::fr */ template typename NCT::fr function_tree_root_from_siblings( - typename NCT::uint32 const& function_selector, + FunctionSelector const& function_selector, typename NCT::boolean const& is_internal, typename NCT::boolean const& is_private, typename NCT::fr const& vk_hash, diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp index 68d17b425315..29116c50666f 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp @@ -193,7 +193,9 @@ TEST_F(native_private_kernel_init_tests, contract_deployment_function_data_misma auto private_inputs = do_private_call_get_kernel_inputs_init(true, constructor, standard_test_args()); // Modify the function selector in function data. - private_inputs.tx_request.function_data.function_selector = numeric::random::get_engine().get_random_uint32(); + private_inputs.tx_request.function_data.function_selector = FunctionSelector{ + .value = numeric::random::get_engine().get_random_uint32(), + }; // Invoke the native private kernel circuit DummyBuilder builder = DummyBuilder("private_kernel_tests__contract_deployment_function_data_mismatch_fails"); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp index da85d34bda05..d7f931b2ccf5 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp @@ -156,7 +156,10 @@ std::pair, ContractDeploymentData> create_private_call_d const Point msg_sender_pub_key = { .x = 123456789, .y = 123456789 }; FunctionData const function_data{ - .function_selector = 1, // TODO(suyash): deduce this from the contract, somehow. + .function_selector = + FunctionSelector{ + .value = 1, // TODO: deduce this from the contract, somehow. + }, .is_private = true, .is_constructor = is_constructor, }; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp index 643c0a137c9e..fee8eb6f798e 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp @@ -107,7 +107,10 @@ PublicCallStackItem generate_call_stack_item(NT::fr contract_address, { NT::uint32 count = seed + 1; FunctionData const function_data{ - .function_selector = count, + .function_selector = + FunctionSelector{ + .value = count, + }, .is_private = false, .is_constructor = false, }; @@ -264,7 +267,10 @@ PublicKernelInputs get_kernel_inputs_with_previous_kernel(NT::boolean privat const NT::address msg_sender = NT::fr(1); FunctionData const function_data{ - .function_selector = 1, + .function_selector = + FunctionSelector{ + .value = 1, + }, .is_private = false, .is_constructor = false, }; @@ -640,7 +646,9 @@ TEST(public_kernel_tests, function_selector_must_be_valid) DummyBuilder dummyBuilder = DummyBuilder("public_kernel_tests__function_selector_must_be_valid"); PublicKernelInputs inputs = get_kernel_inputs_with_previous_kernel(true); - inputs.public_call.call_stack_item.function_data.function_selector = 0; + inputs.public_call.call_stack_item.function_data.function_selector = FunctionSelector{ + .value = 0, + }; auto public_inputs = native_public_kernel_circuit_private_previous_kernel(dummyBuilder, inputs); ASSERT_TRUE(dummyBuilder.failed()); ASSERT_EQ(dummyBuilder.get_first_failure().code, CircuitErrorCode::PUBLIC_KERNEL__FUNCTION_SIGNATURE_INVALID); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp b/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp index a661a0db0348..1363c4abfa22 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp @@ -180,7 +180,7 @@ void common_validate_inputs(DummyBuilder& builder, KernelInput const& public_ker builder.do_assert(this_call_stack_item.contract_address != 0, "Contract address must be non-zero", CircuitErrorCode::PUBLIC_KERNEL__CONTRACT_ADDRESS_INVALID); - builder.do_assert(this_call_stack_item.function_data.function_selector != 0, + builder.do_assert(this_call_stack_item.function_data.function_selector.value != 0, "Function signature must be non-zero", CircuitErrorCode::PUBLIC_KERNEL__FUNCTION_SIGNATURE_INVALID); builder.do_assert(this_call_stack_item.function_data.is_constructor == false, diff --git a/yarn-project/acir-simulator/src/acvm/deserialize.ts b/yarn-project/acir-simulator/src/acvm/deserialize.ts index 7f8c7f87f5c6..538b14e4a76b 100644 --- a/yarn-project/acir-simulator/src/acvm/deserialize.ts +++ b/yarn-project/acir-simulator/src/acvm/deserialize.ts @@ -57,15 +57,6 @@ export function frToBoolean(fr: Fr): boolean { return buf[buf.length - 1] !== 0; } -/** - * Converts a field to a function selector. - * @param fr - The field to convert. - * @returns The function selector. - */ -export function frToSelector(fr: Fr): Buffer { - return fr.toBuffer().slice(-4); -} - /** * Extracts the return fields of a given partial witness. * @param acir - The bytecode of the function. diff --git a/yarn-project/acir-simulator/src/acvm/serialize.ts b/yarn-project/acir-simulator/src/acvm/serialize.ts index f6186d33ebad..9b8e26403159 100644 --- a/yarn-project/acir-simulator/src/acvm/serialize.ts +++ b/yarn-project/acir-simulator/src/acvm/serialize.ts @@ -22,7 +22,7 @@ import { ACVMField, toACVMField } from './acvm.js'; */ export function toACVMFunctionData(functionData: FunctionData): ACVMField[] { return [ - toACVMField(functionData.functionSelector), + toACVMField(functionData.selector.toBuffer()), toACVMField(functionData.isInternal), toACVMField(functionData.isPrivate), toACVMField(functionData.isConstructor), diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index d7a78352683c..5fa48c5044fc 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -1,5 +1,5 @@ import { CompleteAddress, HistoricBlockData, PrivateKey, PublicKey } from '@aztec/circuits.js'; -import { FunctionAbi, FunctionDebugMetadata } from '@aztec/foundation/abi'; +import { FunctionAbi, FunctionDebugMetadata, FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -116,10 +116,10 @@ export interface DBOracle extends CommitmentsDB { * The function is identified by its selector, which is a unique identifier generated from the function signature. * * @param contractAddress - The contract address. - * @param functionSelector - The Buffer containing the function selector bytes. + * @param selector - The corresponding function selector. * @returns A Promise that resolves to a FunctionAbi object containing the ABI information of the target function. */ - getFunctionABI(contractAddress: AztecAddress, functionSelector: Buffer): Promise; + getFunctionABI(contractAddress: AztecAddress, selector: FunctionSelector): Promise; /** * Retrieves the portal contract address associated with the given contract address. diff --git a/yarn-project/acir-simulator/src/client/function_selectors.ts b/yarn-project/acir-simulator/src/client/function_selectors.ts index 97f988134de0..1c8e34f0a357 100644 --- a/yarn-project/acir-simulator/src/client/function_selectors.ts +++ b/yarn-project/acir-simulator/src/client/function_selectors.ts @@ -1,9 +1,5 @@ -import { FUNCTION_SELECTOR_NUM_BYTES } from '@aztec/circuits.js'; -import { computeFunctionSelector } from '@aztec/foundation/abi'; +import { FunctionSelector } from '@aztec/circuits.js'; export const computeNoteHashAndNullifierSignature = 'compute_note_hash_and_nullifier(field,field,field,array)'; -export const computeNoteHashAndNullifierSelector = computeFunctionSelector( - computeNoteHashAndNullifierSignature, - FUNCTION_SELECTOR_NUM_BYTES, -); +export const computeNoteHashAndNullifierSelector = FunctionSelector.fromSignature(computeNoteHashAndNullifierSignature); diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index 08543acddd58..02cfa0707d91 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -23,7 +23,7 @@ import { } from '@aztec/circuits.js/abis'; import { pedersenPlookupCommitInputs } from '@aztec/circuits.js/barretenberg'; import { makeContractDeploymentData } from '@aztec/circuits.js/factories'; -import { FunctionAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi'; +import { FunctionAbi, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { asyncMap } from '@aztec/foundation/async-map'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; @@ -211,7 +211,7 @@ describe('Private Execution test suite', () => { oracle.getFunctionABI.mockImplementation((_, selector) => Promise.resolve( PrivateTokenAirdropContractAbi.functions.find(f => - selector.equals(generateFunctionSelector(f.name, f.parameters)), + selector.equals(FunctionSelector.fromNameAndParameters(f.name, f.parameters)), )!, ), ); @@ -440,7 +440,9 @@ describe('Private Execution test suite', () => { oracle.getFunctionABI.mockImplementation((_, selector) => Promise.resolve( - PrivateTokenContractAbi.functions.find(f => selector.equals(generateFunctionSelector(f.name, f.parameters)))!, + PrivateTokenContractAbi.functions.find(f => + selector.equals(FunctionSelector.fromNameAndParameters(f.name, f.parameters)), + )!, ), ); }); @@ -602,15 +604,15 @@ describe('Private Execution test suite', () => { const parentAbi = getFunctionAbi(ParentContractAbi, 'entryPoint'); const parentAddress = AztecAddress.random(); const childAddress = AztecAddress.random(); - const childSelector = generateFunctionSelector(childAbi.name, childAbi.parameters); + const childSelector = FunctionSelector.fromNameAndParameters(childAbi.name, childAbi.parameters); oracle.getFunctionABI.mockImplementation(() => Promise.resolve(childAbi)); oracle.getPortalContractAddress.mockImplementation(() => Promise.resolve(EthAddress.ZERO)); logger(`Parent deployed at ${parentAddress.toShortString()}`); - logger(`Calling child function ${childSelector.toString('hex')} at ${childAddress.toShortString()}`); + logger(`Calling child function ${childSelector.toString()} at ${childAddress.toShortString()}`); - const args = [Fr.fromBuffer(childAddress.toBuffer()), Fr.fromBuffer(childSelector)]; + const args = [Fr.fromBuffer(childAddress.toBuffer()), Fr.fromBuffer(childSelector.toBuffer())]; const result = await runSimulator({ args, abi: parentAbi, origin: parentAddress }); expect(result.callStackItem.publicInputs.returnValues[0]).toEqual(new Fr(privateIncrement)); @@ -652,7 +654,10 @@ describe('Private Execution test suite', () => { const importerAddress = AztecAddress.random(); const testAddress = AztecAddress.random(); const parentAbi = ImportTestContractAbi.functions.find(f => f.name === 'main')!; - const testCodeGenSelector = generateFunctionSelector(testCodeGenAbi.name, testCodeGenAbi.parameters); + const testCodeGenSelector = FunctionSelector.fromNameAndParameters( + testCodeGenAbi.name, + testCodeGenAbi.parameters, + ); oracle.getFunctionABI.mockResolvedValue(testCodeGenAbi); oracle.getPortalContractAddress.mockResolvedValue(EthAddress.ZERO); @@ -768,13 +773,13 @@ describe('Private Execution test suite', () => { const childContractAbi = ParentContractAbi.functions[0]; const childAddress = AztecAddress.random(); const childPortalContractAddress = EthAddress.random(); - const childSelector = generateFunctionSelector(childContractAbi.name, childContractAbi.parameters); + const childSelector = FunctionSelector.fromNameAndParameters(childContractAbi.name, childContractAbi.parameters); const parentAddress = AztecAddress.random(); oracle.getPortalContractAddress.mockImplementation(() => Promise.resolve(childPortalContractAddress)); oracle.getFunctionABI.mockImplementation(() => Promise.resolve({ ...childContractAbi, isInternal })); - const args = [Fr.fromBuffer(childAddress.toBuffer()), Fr.fromBuffer(childSelector), 42n]; + const args = [Fr.fromBuffer(childAddress.toBuffer()), childSelector.toField(), 42n]; const result = await runSimulator({ origin: parentAddress, contractAddress: parentAddress, @@ -830,7 +835,7 @@ describe('Private Execution test suite', () => { oracle.getFunctionABI.mockImplementation((_, selector) => Promise.resolve( PendingCommitmentsContractAbi.functions.find(f => - selector.equals(generateFunctionSelector(f.name, f.parameters)), + selector.equals(FunctionSelector.fromNameAndParameters(f.name, f.parameters)), )!, ), ); @@ -894,18 +899,21 @@ describe('Private Execution test suite', () => { const getThenNullifyAbi = PendingCommitmentsContractAbi.functions.find(f => f.name === 'get_then_nullify_note')!; const getZeroAbi = PendingCommitmentsContractAbi.functions.find(f => f.name === 'get_note_zero_balance')!; - const insertFnSelector = generateFunctionSelector(insertAbi.name, insertAbi.parameters); - const getThenNullifyFnSelector = generateFunctionSelector(getThenNullifyAbi.name, getThenNullifyAbi.parameters); - const getZeroFnSelector = generateFunctionSelector(getZeroAbi.name, getZeroAbi.parameters); + const insertFnSelector = FunctionSelector.fromNameAndParameters(insertAbi.name, insertAbi.parameters); + const getThenNullifyFnSelector = FunctionSelector.fromNameAndParameters( + getThenNullifyAbi.name, + getThenNullifyAbi.parameters, + ); + const getZeroFnSelector = FunctionSelector.fromNameAndParameters(getZeroAbi.name, getZeroAbi.parameters); oracle.getPortalContractAddress.mockImplementation(() => Promise.resolve(EthAddress.ZERO)); const args = [ amountToTransfer, owner, - Fr.fromBuffer(insertFnSelector), - Fr.fromBuffer(getThenNullifyFnSelector), - Fr.fromBuffer(getZeroFnSelector), + insertFnSelector.toField(), + getThenNullifyFnSelector.toField(), + getZeroFnSelector.toField(), ]; const result = await runSimulator({ args: args, diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index b0dd8369caaf..93425ffb9553 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -6,14 +6,14 @@ import { PublicCallRequest, } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { decodeReturnValues } from '@aztec/foundation/abi'; +import { FunctionSelector, decodeReturnValues } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { to2Fields } from '@aztec/foundation/serialize'; import { FunctionL2Logs, NotePreimage, NoteSpendingInfo } from '@aztec/types'; -import { extractPrivateCircuitPublicInputs, frToAztecAddress, frToSelector } from '../acvm/deserialize.js'; +import { extractPrivateCircuitPublicInputs, frToAztecAddress } from '../acvm/deserialize.js'; import { ZERO_ACVM_FIELD, acvm, @@ -55,7 +55,7 @@ export class PrivateFunctionExecution { * @returns The execution result. */ public async run(): Promise { - const selector = this.functionData.functionSelectorBuffer.toString('hex'); + const selector = this.functionData.selector.toString(); this.log(`Executing external function ${this.contractAddress.toString()}:${selector}`); const acir = Buffer.from(this.abi.bytecode, 'base64'); @@ -132,7 +132,7 @@ export class PrivateFunctionExecution { const childExecutionResult = await this.callPrivateFunction( frToAztecAddress(contractAddress), - frToSelector(functionSelector), + FunctionSelector.fromField(functionSelector), fromACVMField(acvmArgsHash), this.callContext, this.curve, @@ -157,7 +157,7 @@ export class PrivateFunctionExecution { enqueuePublicFunctionCall: async ([acvmContractAddress], [acvmFunctionSelector], [acvmArgsHash]) => { const enqueuedRequest = await this.enqueuePublicFunctionCall( frToAztecAddress(fromACVMField(acvmContractAddress)), - frToSelector(fromACVMField(acvmFunctionSelector)), + FunctionSelector.fromField(fromACVMField(acvmFunctionSelector)), this.context.packedArgsCache.unpack(fromACVMField(acvmArgsHash)), this.callContext, ); @@ -280,7 +280,7 @@ export class PrivateFunctionExecution { */ private async callPrivateFunction( targetContractAddress: AztecAddress, - targetFunctionSelector: Buffer, + targetFunctionSelector: FunctionSelector, targetArgsHash: Fr, callerContext: CallContext, curve: Grumpkin, @@ -317,7 +317,7 @@ export class PrivateFunctionExecution { */ private async enqueuePublicFunctionCall( targetContractAddress: AztecAddress, - targetFunctionSelector: Buffer, + targetFunctionSelector: FunctionSelector, targetArgs: Fr[], callerContext: CallContext, ): Promise { @@ -335,7 +335,7 @@ export class PrivateFunctionExecution { // TODO($846): if enqueued public calls are associated with global // side-effect counter, that will leak info about how many other private // side-effects occurred in the TX. Ultimately the private kernel should - // just outut everything in the proper order without any counters. + // just output everything in the proper order without any counters. } /** diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts index 9c8d8815a0f2..1e4dbf694218 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts @@ -1,5 +1,5 @@ import { CompleteAddress, FunctionData, HistoricBlockData, PrivateKey } from '@aztec/circuits.js'; -import { encodeArguments } from '@aztec/foundation/abi'; +import { FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -60,7 +60,7 @@ describe('Unconstrained Execution test suite', () => { const execRequest: FunctionCall = { to: contractAddress, - functionData: new FunctionData(Buffer.alloc(4), false, true, true), + functionData: new FunctionData(FunctionSelector.empty(), false, true, true), args: encodeArguments(abi, [owner]), }; diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts index b949abef49c1..a370240baddd 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts @@ -34,9 +34,7 @@ export class UnconstrainedFunctionExecution { */ public async run(aztecNode?: AztecNode): Promise { this.log( - `Executing unconstrained function ${this.contractAddress.toShortString()}:${this.functionData.functionSelectorBuffer.toString( - 'hex', - )}`, + `Executing unconstrained function ${this.contractAddress.toShortString()}:${this.functionData.selector.toString()}`, ); const acir = Buffer.from(this.abi.bytecode, 'base64'); diff --git a/yarn-project/acir-simulator/src/public/db.ts b/yarn-project/acir-simulator/src/public/db.ts index 16f7bf412dc6..bc79cb17b76c 100644 --- a/yarn-project/acir-simulator/src/public/db.ts +++ b/yarn-project/acir-simulator/src/public/db.ts @@ -1,4 +1,4 @@ -import { EthAddress } from '@aztec/circuits.js'; +import { EthAddress, FunctionSelector } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; @@ -33,18 +33,18 @@ export interface PublicContractsDB { /** * Returns the brillig (public bytecode) of a function. * @param address - The contract address that owns this function. - * @param functionSelector - The selector for the function. + * @param selector - The selector for the function. * @returns The bytecode or undefined if not found. */ - getBytecode(address: AztecAddress, functionSelector: Buffer): Promise; + getBytecode(address: AztecAddress, selector: FunctionSelector): Promise; /** * Returns whether a function is internal or not. * @param address - The contract address that owns this function. - * @param functionSelector - The selector for the function. + * @param selector - The selector for the function. * @returns The `isInternal` flag found, undefined if not found. */ - getIsInternal(address: AztecAddress, functionSelector: Buffer): Promise; + getIsInternal(address: AztecAddress, selector: FunctionSelector): Promise; /** * Returns the portal contract address for an L2 address. diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index 86eb9c35bfd2..2b0081508a9a 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -4,6 +4,7 @@ import { EthAddress, Fr, FunctionData, + FunctionSelector, GlobalVariables, HistoricBlockData, } from '@aztec/circuits.js'; @@ -17,7 +18,6 @@ import { convertACVMFieldToBuffer, extractPublicCircuitPublicInputs, frToAztecAddress, - frToSelector, fromACVMField, toACVMField, toACVMWitness, @@ -54,12 +54,11 @@ export class PublicExecutor { * @returns The result of the run plus all nested runs. */ public async execute(execution: PublicExecution, globalVariables: GlobalVariables): Promise { - const selectorHex = execution.functionData.functionSelectorBuffer.toString('hex'); - this.log(`Executing public external function ${execution.contractAddress.toString()}:${selectorHex}`); + const selector = execution.functionData.selector; + this.log(`Executing public external function ${execution.contractAddress.toString()}:${selector}`); - const selector = execution.functionData.functionSelectorBuffer; const acir = await this.contractsDb.getBytecode(execution.contractAddress, selector); - if (!acir) throw new Error(`Bytecode not found for ${execution.contractAddress.toString()}:${selectorHex}`); + if (!acir) throw new Error(`Bytecode not found for ${execution.contractAddress.toString()}:${selector}`); const initialWitness = getInitialWitness(execution.args, execution.callContext, this.blockData, globalVariables); const storageActions = new ContractStorageActionsCollector(this.stateDb, execution.contractAddress); @@ -118,7 +117,7 @@ export class PublicExecutor { this.log(`Public function call: addr=${address} selector=${functionSelector} args=${args.join(',')}`); const childExecutionResult = await this.callPublicFunction( frToAztecAddress(fromACVMField(address)), - frToSelector(fromACVMField(functionSelector)), + FunctionSelector.fromField(fromACVMField(functionSelector)), args, execution.callContext, globalVariables, @@ -176,7 +175,7 @@ export class PublicExecutor { private async callPublicFunction( targetContractAddress: AztecAddress, - targetFunctionSelector: Buffer, + targetFunctionSelector: FunctionSelector, targetArgs: Fr[], callerContext: CallContext, globalVariables: GlobalVariables, @@ -185,9 +184,7 @@ export class PublicExecutor { const isInternal = await this.contractsDb.getIsInternal(targetContractAddress, targetFunctionSelector); if (isInternal === undefined) { throw new Error( - `ERR: ContractsDb don't contain isInternal for ${targetContractAddress.toString()}:${targetFunctionSelector.toString( - 'hex', - )}. Defaulting to false.`, + `ERR: ContractsDb don't contain isInternal for ${targetContractAddress.toString()}:${targetFunctionSelector.toString()}. Defaulting to false.`, ); } diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/acir-simulator/src/public/index.test.ts index b7926ea26e8d..c2630961cc3e 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/acir-simulator/src/public/index.test.ts @@ -7,7 +7,7 @@ import { L1_TO_L2_MSG_TREE_HEIGHT, } from '@aztec/circuits.js'; import { pedersenPlookupCommitInputs } from '@aztec/circuits.js/barretenberg'; -import { FunctionAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi'; +import { FunctionAbi, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -110,7 +110,7 @@ describe('ACIR public execution simulator', () => { beforeEach(() => { contractAddress = AztecAddress.random(); abi = PublicTokenContractAbi.functions.find(f => f.name === 'transfer')!; - functionData = new FunctionData(Buffer.alloc(4), false, false, false); + functionData = new FunctionData(FunctionSelector.empty(), false, false, false); args = encodeArguments(abi, [140, recipient]); sender = AztecAddress.random(); @@ -203,21 +203,21 @@ describe('ACIR public execution simulator', () => { async isInternal => { const parentContractAddress = AztecAddress.random(); const parentEntryPointFn = ParentContractAbi.functions.find(f => f.name === 'pubEntryPoint')!; - const parentEntryPointFnSelector = generateFunctionSelector( + const parentEntryPointFnSelector = FunctionSelector.fromNameAndParameters( parentEntryPointFn.name, parentEntryPointFn.parameters, ); const childContractAddress = AztecAddress.random(); const childValueFn = ChildContractAbi.functions.find(f => f.name === 'pubGetValue')!; - const childValueFnSelector = generateFunctionSelector(childValueFn.name, childValueFn.parameters); + const childValueFnSelector = FunctionSelector.fromNameAndParameters(childValueFn.name, childValueFn.parameters); const initialValue = 3n; const functionData = new FunctionData(parentEntryPointFnSelector, isInternal ?? false, false, false); const args = encodeArguments(parentEntryPointFn, [ childContractAddress.toField().value, - toBigInt(childValueFnSelector), + toBigInt(childValueFnSelector.toBuffer()), initialValue, ]); @@ -231,7 +231,7 @@ describe('ACIR public execution simulator', () => { }); // eslint-disable-next-line require-await - publicContracts.getBytecode.mockImplementation(async (addr: AztecAddress, selector: Buffer) => { + publicContracts.getBytecode.mockImplementation(async (addr: AztecAddress, selector: FunctionSelector) => { if (addr.equals(parentContractAddress) && selector.equals(parentEntryPointFnSelector)) { return Buffer.from(parentEntryPointFn.bytecode, 'base64'); } else if (addr.equals(childContractAddress) && selector.equals(childValueFnSelector)) { @@ -279,7 +279,7 @@ describe('ACIR public execution simulator', () => { beforeEach(async () => { contractAddress = AztecAddress.random(); - functionData = new FunctionData(Buffer.alloc(4), false, false, false); + functionData = new FunctionData(FunctionSelector.empty(), false, false, false); amount = new Fr(140); params = [amount, Fr.random()]; wasm = await CircuitsWasm.get(); diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 8d7bfed21cdc..ab4b779c8cbe 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,3 +1,4 @@ +import { FunctionSelector } from '@aztec/circuits.js'; import { createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -327,15 +328,15 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource /** * Gets the public function data for a contract. * @param contractAddress - The contract address containing the function to fetch. - * @param functionSelector - The function selector of the function to fetch. + * @param selector - The function selector of the function to fetch. * @returns The public function data (if found). */ public async getPublicFunction( contractAddress: AztecAddress, - functionSelector: Buffer, + selector: FunctionSelector, ): Promise { const contractData = await this.getContractDataAndBytecode(contractAddress); - return contractData?.getPublicFunction(functionSelector); + return contractData?.getPublicFunction(selector); } /** diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index b5aeb0053cad..2497e409a2aa 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -326,14 +326,8 @@ export class AztecRPCServer implements AztecRPC { contractDataOracle: ContractDataOracle, ) { const contractAddress = (execRequest as FunctionCall).to ?? (execRequest as TxExecutionRequest).origin; - const functionAbi = await contractDataOracle.getFunctionAbi( - contractAddress, - execRequest.functionData.functionSelectorBuffer, - ); - const debug = await contractDataOracle.getFunctionDebugMetadata( - contractAddress, - execRequest.functionData.functionSelectorBuffer, - ); + const functionAbi = await contractDataOracle.getFunctionAbi(contractAddress, execRequest.functionData.selector); + const debug = await contractDataOracle.getFunctionDebugMetadata(contractAddress, execRequest.functionData.selector); const portalContract = await contractDataOracle.getPortalContractAddress(contractAddress); return { diff --git a/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts b/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts index 3657b2a89687..ef05b49e3fb7 100644 --- a/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts @@ -1,5 +1,5 @@ import { AztecAddress, CircuitsWasm, MembershipWitness, VK_TREE_HEIGHT } from '@aztec/circuits.js'; -import { FunctionDebugMetadata, getFunctionDebugMetadata } from '@aztec/foundation/abi'; +import { FunctionDebugMetadata, FunctionSelector, getFunctionDebugMetadata } from '@aztec/foundation/abi'; import { ContractCommitmentProvider, ContractDatabase } from '@aztec/types'; import { ContractTree } from '../contract_tree/index.js'; @@ -36,12 +36,12 @@ export class ContractDataOracle { * Throws an error if the contract address or function selector are invalid or not found. * * @param contractAddress - The AztecAddress representing the contract containing the function. - * @param functionSelector - A Buffer containing the unique selector code for the desired function. + * @param selector - The function selector. * @returns The corresponding function's ABI as an object. */ - public async getFunctionAbi(contractAddress: AztecAddress, functionSelector: Buffer) { + public async getFunctionAbi(contractAddress: AztecAddress, selector: FunctionSelector) { const tree = await this.getTree(contractAddress); - return tree.getFunctionAbi(functionSelector); + return tree.getFunctionAbi(selector); } /** @@ -50,15 +50,15 @@ export class ContractDataOracle { * Returns undefined if the debug metadata for the given function is not found. * * @param contractAddress - The AztecAddress representing the contract containing the function. - * @param functionSelector - A Buffer containing the unique selector code for the desired function. + * @param selector - The function selector. * @returns The corresponding function's ABI as an object. */ public async getFunctionDebugMetadata( contractAddress: AztecAddress, - functionSelector: Buffer, + selector: FunctionSelector, ): Promise { const contract = await this.db.getContract(contractAddress); - const functionAbi = contract?.functions.find(f => f.selector.equals(functionSelector)); + const functionAbi = contract?.functions.find(f => f.selector.equals(selector)); if (!contract || !functionAbi) { return undefined; @@ -73,12 +73,12 @@ export class ContractDataOracle { * in the Aztec network. Throws an error if the contract or function cannot be found. * * @param contractAddress - The contract's address. - * @param functionSelector - A Buffer containing the function selector (first 4 bytes of the keccak256 hash of the function signature). + * @param selector - The function selector. * @returns A Promise that resolves to a Buffer containing the bytecode of the specified function. */ - public async getBytecode(contractAddress: AztecAddress, functionSelector: Buffer) { + public async getBytecode(contractAddress: AztecAddress, selector: FunctionSelector) { const tree = await this.getTree(contractAddress); - return tree.getBytecode(functionSelector); + return tree.getBytecode(selector); } /** @@ -102,12 +102,12 @@ export class ContractDataOracle { * Throws an error if the contract address or function selector is unknown. * * @param contractAddress - The contract address. - * @param functionSelector - The buffer containing the function selector. + * @param selector - The function selector. * @returns A promise that resolves with the MembershipWitness instance for the specified contract's function. */ - public async getFunctionMembershipWitness(contractAddress: AztecAddress, functionSelector: Buffer) { + public async getFunctionMembershipWitness(contractAddress: AztecAddress, selector: FunctionSelector) { const tree = await this.getTree(contractAddress); - return tree.getFunctionMembershipWitness(functionSelector); + return tree.getFunctionMembershipWitness(selector); } /** diff --git a/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts b/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts index 1f7efbb23956..e32961f8bb28 100644 --- a/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts +++ b/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts @@ -1,3 +1,4 @@ +import { FunctionSelector } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { DebugLogger } from '@aztec/foundation/log'; import { ContractDao, ContractDatabase } from '@aztec/types'; @@ -47,11 +48,11 @@ export class MemoryContractDatabase implements ContractDatabase { * then returns the corresponding bytecode. If no match is found, it returns undefined. * * @param contractAddress - The AztecAddress representing the contract address to look for. - * @param functionSelector - The Buffer containing the function selector to search for. + * @param selector - The function selector. * @returns A Promise that resolves to the bytecode of the matching function or undefined if not found. */ - public async getCode(contractAddress: AztecAddress, functionSelector: Buffer) { + public async getCode(contractAddress: AztecAddress, selector: FunctionSelector) { const contract = await this.getContract(contractAddress); - return contract?.functions.find(f => f.selector.equals(functionSelector))?.bytecode; + return contract?.functions.find(f => f.selector.equals(selector))?.bytecode; } } diff --git a/yarn-project/aztec-rpc/src/contract_tree/index.ts b/yarn-project/aztec-rpc/src/contract_tree/index.ts index acf6052ed50d..9c1d48a9e141 100644 --- a/yarn-project/aztec-rpc/src/contract_tree/index.ts +++ b/yarn-project/aztec-rpc/src/contract_tree/index.ts @@ -22,7 +22,7 @@ import { computeVarArgsHash, hashConstructor, } from '@aztec/circuits.js/abis'; -import { ContractAbi, generateFunctionSelector } from '@aztec/foundation/abi'; +import { ContractAbi, FunctionSelector } from '@aztec/foundation/abi'; import { assertLength } from '@aztec/foundation/serialize'; import { AztecNode, ContractCommitmentProvider, ContractDao, PublicKey } from '@aztec/types'; @@ -85,7 +85,7 @@ export class ContractTree { const functions = abi.functions.map(f => ({ ...f, - selector: generateFunctionSelector(f.name, f.parameters), + selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), })); const leaves = generateFunctionLeaves(functions, wasm); const root = computeFunctionTreeRoot(wasm, leaves); @@ -112,17 +112,15 @@ export class ContractTree { * The function is identified by its selector, which represents a unique identifier for the function's signature. * Throws an error if the function with the provided selector is not found in the contract. * - * @param functionSelector - The Buffer containing the unique identifier for the function's signature. + * @param selector - The function selector. * @returns The ABI object containing relevant information about the targeted function. */ - public getFunctionAbi(functionSelector: Buffer) { - const abi = this.contract.functions.find(f => f.selector.equals(functionSelector)); + public getFunctionAbi(selector: FunctionSelector) { + const abi = this.contract.functions.find(f => f.selector.equals(selector)); if (!abi) { throw new Error( - `Unknown function. Selector ${functionSelector.toString( - 'hex', - )} not found in the ABI of contract ${this.contract.address.toString()}. Expected one of: ${this.contract.functions - .map(f => f.selector.toString('hex')) + `Unknown function. Selector ${selector.toString()} not found in the ABI of contract ${this.contract.address.toString()}. Expected one of: ${this.contract.functions + .map(f => f.selector.toString()) .join(', ')}`, ); } @@ -134,11 +132,11 @@ export class ContractTree { * The function selector is a unique identifier for each function in a contract. * Throws an error if the function with the given selector is not found in the contract. * - * @param functionSelector - The Buffer representing the function selector. + * @param selector - The selector of a function to get bytecode for. * @returns The bytecode of the function as a string. */ - public getBytecode(functionSelector: Buffer) { - return this.getFunctionAbi(functionSelector).bytecode; + public getBytecode(selector: FunctionSelector) { + return this.getFunctionAbi(selector).bytecode; } /** @@ -195,14 +193,14 @@ export class ContractTree { * in the Merkle tree of constrained functions. It is required to prove the existence of the * function within the contract during execution. * - * @param functionSelector - The Buffer containing the function selector (signature). + * @param selector - The function selector. * @returns A MembershipWitness instance representing the position and authentication path of the function in the function tree. */ public getFunctionMembershipWitness( - functionSelector: Buffer, + selector: FunctionSelector, ): Promise> { const targetFunctions = this.contract.functions.filter(isConstrained); - const functionIndex = targetFunctions.findIndex(f => f.selector.equals(functionSelector)); + const functionIndex = targetFunctions.findIndex(f => f.selector.equals(selector)); if (functionIndex < 0) { return Promise.resolve(MembershipWitness.empty(FUNCTION_TREE_HEIGHT, 0n)); } diff --git a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts index a52a160f0298..85a32f3ca485 100644 --- a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts @@ -1,4 +1,4 @@ -import { AztecAddress, Fr, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT } from '@aztec/circuits.js'; +import { AztecAddress, Fr, FunctionSelector, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT } from '@aztec/circuits.js'; import { Tuple } from '@aztec/foundation/serialize'; import { AztecNode, MerkleTreeId } from '@aztec/types'; @@ -15,8 +15,8 @@ export class KernelOracle implements ProvingDataOracle { return await this.contractDataOracle.getContractMembershipWitness(contractAddress); } - public async getFunctionMembershipWitness(contractAddress: AztecAddress, functionSelector: Buffer) { - return await this.contractDataOracle.getFunctionMembershipWitness(contractAddress, functionSelector); + public async getFunctionMembershipWitness(contractAddress: AztecAddress, selector: FunctionSelector) { + return await this.contractDataOracle.getFunctionMembershipWitness(contractAddress, selector); } public async getVkMembershipWitness() { diff --git a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts index 6d758889f0de..94afeca021d8 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts @@ -186,7 +186,7 @@ export class KernelProver { const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness( contractAddress, - functionData.functionSelectorBuffer, + functionData.selector, ); // TODO(#262): Use real acir hash diff --git a/yarn-project/aztec-rpc/src/kernel_prover/proving_data_oracle.ts b/yarn-project/aztec-rpc/src/kernel_prover/proving_data_oracle.ts index 16e90f9ca1ae..8e88e557c1a6 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/proving_data_oracle.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/proving_data_oracle.ts @@ -2,6 +2,7 @@ import { CONTRACT_TREE_HEIGHT, FUNCTION_TREE_HEIGHT, Fr, + FunctionSelector, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT, VK_TREE_HEIGHT, @@ -32,12 +33,12 @@ export interface ProvingDataOracle { * Throws an error if the contract address or function selector is unknown. * * @param contractAddress - The contract address. - * @param functionSelector - The buffer containing the function selector. + * @param selector - The function selector. * @returns A promise that resolves with the MembershipWitness instance for the specified contract's function. */ getFunctionMembershipWitness( contractAddress: AztecAddress, - functionSelector: Buffer, + selector: FunctionSelector, ): Promise>; /** diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 64dcae81c92b..42a33e58c3b9 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -10,6 +10,7 @@ import { CompleteAddress, EthAddress, Fr, + FunctionSelector, HistoricBlockData, PrivateKey, PublicKey, @@ -58,9 +59,12 @@ export class SimulatorOracle implements DBOracle { })); } - async getFunctionABI(contractAddress: AztecAddress, functionSelector: Buffer): Promise { - const abi = await this.contractDataOracle.getFunctionAbi(contractAddress, functionSelector); - const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, functionSelector); + async getFunctionABI( + contractAddress: AztecAddress, + selector: FunctionSelector, + ): Promise { + const abi = await this.contractDataOracle.getFunctionAbi(contractAddress, selector); + const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, selector); return { ...abi, debug, diff --git a/yarn-project/aztec-sandbox/src/examples/uniswap_trade_on_l1_from_l2.ts b/yarn-project/aztec-sandbox/src/examples/uniswap_trade_on_l1_from_l2.ts index d7ef5a620e14..2a7907a836bb 100644 --- a/yarn-project/aztec-sandbox/src/examples/uniswap_trade_on_l1_from_l2.ts +++ b/yarn-project/aztec-sandbox/src/examples/uniswap_trade_on_l1_from_l2.ts @@ -236,7 +236,7 @@ async function main() { // 4. Send L2 to L1 message to withdraw funds and another message to swap assets. logger('Send L2 tx to withdraw WETH to uniswap portal and send message to swap assets on L1'); // recipient is the uniswap portal - const selector = Fr.fromBuffer(wethL2Contract.methods.withdraw.selector); + const selector = wethL2Contract.methods.withdraw.selector.toField(); const minimumOutputAmount = 0n; const withdrawTx = uniswapL2Contract.methods diff --git a/yarn-project/aztec.js/src/account/entrypoint/entrypoint_payload.ts b/yarn-project/aztec.js/src/account/entrypoint/entrypoint_payload.ts index 111f9ab127ec..b5ec1c719c24 100644 --- a/yarn-project/aztec.js/src/account/entrypoint/entrypoint_payload.ts +++ b/yarn-project/aztec.js/src/account/entrypoint/entrypoint_payload.ts @@ -52,7 +52,7 @@ export async function buildPayload( // eslint-disable-next-line camelcase flattened_args_hashes: packedArguments.map(args => args.hash), // eslint-disable-next-line camelcase - flattened_selectors: calls.map(call => Fr.fromBuffer(call.functionData.functionSelectorBuffer)), + flattened_selectors: calls.map(call => call.functionData.selector.toField()), // eslint-disable-next-line camelcase flattened_targets: calls.map(call => call.to.toField()), nonce, diff --git a/yarn-project/aztec.js/src/contract/contract_base.ts b/yarn-project/aztec.js/src/contract/contract_base.ts index 3c2d6653c41f..4a20050fb2a9 100644 --- a/yarn-project/aztec.js/src/contract/contract_base.ts +++ b/yarn-project/aztec.js/src/contract/contract_base.ts @@ -1,4 +1,4 @@ -import { ContractAbi, FunctionAbi, generateFunctionSelector } from '@aztec/foundation/abi'; +import { ContractAbi, FunctionAbi, FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { DeployedContract } from '@aztec/types'; @@ -14,7 +14,7 @@ export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & /** * The unique identifier for a contract function in bytecode. */ - readonly selector: Buffer; + readonly selector: FunctionSelector; }; /** @@ -51,7 +51,7 @@ export abstract class ContractBase { * @returns Selector of the function. */ get selector() { - return generateFunctionSelector(f.name, f.parameters); + return FunctionSelector.fromNameAndParameters(f.name, f.parameters); }, }); }); diff --git a/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts index 62e05bad6435..15748b722bfd 100644 --- a/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts @@ -264,7 +264,7 @@ describe('uniswap_trade_on_l1_from_l2', () => { // 4. Send L2 to L1 message to withdraw funds and another message to swap assets. logger('Send L2 tx to withdraw WETH to uniswap portal and send message to swap assets on L1'); // recipient is the uniswap portal - const selector = Fr.fromBuffer(wethL2Contract.methods.withdraw.selector); + const selector = wethL2Contract.methods.withdraw.selector.toField(); const minimumOutputAmount = 0n; const withdrawTx = uniswapL2Contract.methods diff --git a/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap b/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap index d86a59faaf18..b27325aa3910 100644 --- a/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap +++ b/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap @@ -44,7 +44,7 @@ AztecAddress { exports[`abis wasm bindings computes a function leaf 1`] = ` Fr { - "value": 3087577661303601311028613516544548769914327454147174509447606645757193921240n, + "value": 16977277925454205296890617263907769463254781689473762721237698889614686866498n, } `; diff --git a/yarn-project/circuits.js/src/abis/abis.test.ts b/yarn-project/circuits.js/src/abis/abis.test.ts index 9a1657f440ba..564777d086d7 100644 --- a/yarn-project/circuits.js/src/abis/abis.test.ts +++ b/yarn-project/circuits.js/src/abis/abis.test.ts @@ -1,6 +1,6 @@ import times from 'lodash.times'; -import { AztecAddress, Fr, FunctionData, FunctionLeafPreimage, NewContractData } from '../index.js'; +import { AztecAddress, Fr, FunctionData, FunctionLeafPreimage, FunctionSelector, NewContractData } from '../index.js'; import { makeAztecAddress, makeEthAddress, makePoint, makeTxRequest, makeVerificationKey } from '../tests/factories.js'; import { CircuitsWasm } from '../wasm/circuits_wasm.js'; import { @@ -44,34 +44,18 @@ describe('abis wasm bindings', () => { }); it('computes a function leaf', () => { - const leaf = new FunctionLeafPreimage(Buffer.from([0, 0, 0, 123]), false, true, Fr.ZERO, Fr.ZERO); + const leaf = new FunctionLeafPreimage(new FunctionSelector(7837), false, true, Fr.ZERO, Fr.ZERO); const res = computeFunctionLeaf(wasm, leaf); expect(res).toMatchSnapshot(); }); - it('compute function leaf should revert if buffer is over 4 bytes', () => { - expect(() => { - new FunctionLeafPreimage(Buffer.from([0, 0, 0, 0, 123]), false, true, Fr.ZERO, Fr.ZERO); - }).toThrow('Function selector must be 4 bytes long, got 5 bytes.'); - }); - - it('function leaf toBuffer should revert if buffer is over 4 bytes ', () => { - const initBuffer = Buffer.from([0, 0, 0, 123]); - const largerBuffer = Buffer.from([0, 0, 0, 0, 123]); - expect(() => { - const leaf = new FunctionLeafPreimage(initBuffer, false, true, Fr.ZERO, Fr.ZERO); - leaf.functionSelector = largerBuffer; - leaf.toBuffer(); - }).toThrow('Function selector must be 4 bytes long, got 5 bytes.'); - }); - it('computes function tree root', () => { const res = computeFunctionTreeRoot(wasm, [new Fr(0n), new Fr(0n), new Fr(0n), new Fr(0n)]); expect(res).toMatchSnapshot(); }); it('hashes constructor info', () => { - const functionData = new FunctionData(Buffer.alloc(4), false, true, true); + const functionData = new FunctionData(FunctionSelector.empty(), false, true, true); const argsHash = new Fr(42); const vkHash = Buffer.alloc(32); const res = hashConstructor(wasm, functionData, argsHash, vkHash); diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 825699452962..2dbf96b033e1 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -19,6 +19,7 @@ import { Fq, Fr, FunctionData, + FunctionSelector, G1AffineElement, GlobalVariables, HistoricBlockData, @@ -266,8 +267,28 @@ export function fromNewContractData(o: NewContractData): MsgpackNewContractData }; } +interface MsgpackFunctionSelector { + value: number; +} + +export function toFunctionSelector(o: MsgpackFunctionSelector): FunctionSelector { + if (o.value === undefined) { + throw new Error('Expected value in FunctionSelector deserialization'); + } + return new FunctionSelector(o.value); +} + +export function fromFunctionSelector(o: FunctionSelector): MsgpackFunctionSelector { + if (o.value === undefined) { + throw new Error('Expected value in FunctionSelector serialization'); + } + return { + value: o.value, + }; +} + interface MsgpackFunctionData { - function_selector: number; + function_selector: MsgpackFunctionSelector; is_internal: boolean; is_private: boolean; is_constructor: boolean; @@ -286,11 +307,11 @@ export function toFunctionData(o: MsgpackFunctionData): FunctionData { if (o.is_constructor === undefined) { throw new Error('Expected is_constructor in FunctionData deserialization'); } - return new FunctionData(o.function_selector, o.is_internal, o.is_private, o.is_constructor); + return new FunctionData(toFunctionSelector(o.function_selector), o.is_internal, o.is_private, o.is_constructor); } export function fromFunctionData(o: FunctionData): MsgpackFunctionData { - if (o.functionSelector === undefined) { + if (o.selector === undefined) { throw new Error('Expected functionSelector in FunctionData serialization'); } if (o.isInternal === undefined) { @@ -303,7 +324,7 @@ export function fromFunctionData(o: FunctionData): MsgpackFunctionData { throw new Error('Expected isConstructor in FunctionData serialization'); } return { - function_selector: o.functionSelector, + function_selector: fromFunctionSelector(o.selector), is_internal: o.isInternal, is_private: o.isPrivate, is_constructor: o.isConstructor, diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index b3c1443cf5f5..527c6c9b2442 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -52,6 +52,7 @@ export { Coordinate, GlobalVariables, } from '../structs/index.js'; +export { FunctionSelector } from '@aztec/foundation/abi'; /** * A pointer to a Prover object in WebAssembly memory. diff --git a/yarn-project/circuits.js/src/contract/contract_deployment_info.ts b/yarn-project/circuits.js/src/contract/contract_deployment_info.ts index 8554b6fa3147..a358e4f5f56f 100644 --- a/yarn-project/circuits.js/src/contract/contract_deployment_info.ts +++ b/yarn-project/circuits.js/src/contract/contract_deployment_info.ts @@ -5,7 +5,7 @@ import { computeVarArgsHash, hashConstructor, } from '@aztec/circuits.js/abis'; -import { ContractAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi'; +import { ContractAbi, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { CircuitsWasm, CompleteAddress, DeploymentInfo, Fr, FunctionData, PublicKey } from '../index.js'; import { generateFunctionLeaves, hashVKStr, isConstructor } from './contract_tree/contract_tree.js'; @@ -37,7 +37,7 @@ export async function getContractDeploymentInfo( const constructorVkHash = Fr.fromBuffer(vkHash); const functions = abi.functions.map(f => ({ ...f, - selector: generateFunctionSelector(f.name, f.parameters), + selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), })); const leaves = generateFunctionLeaves(functions, wasm); const functionTreeRoot = computeFunctionTreeRoot(wasm, leaves); diff --git a/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts b/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts index e3e636f5b6f9..13d88c315d00 100644 --- a/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts +++ b/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts @@ -1,6 +1,6 @@ import { CircuitsWasm, ContractFunctionDao, Fr, FunctionData, FunctionLeafPreimage } from '@aztec/circuits.js'; import { computeFunctionLeaf, hashVK } from '@aztec/circuits.js/abis'; -import { FunctionType, generateFunctionSelector } from '@aztec/foundation/abi'; +import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; /** * Computes the hash of a hex-encoded string representation of a verification key (vk). @@ -69,7 +69,7 @@ export function generateFunctionLeaves(functions: ContractFunctionDao[], wasm: C const result: Fr[] = []; for (let i = 0; i < targetFunctions.length; i++) { const f = targetFunctions[i]; - const selector = generateFunctionSelector(f.name, f.parameters); + const selector = FunctionSelector.fromNameAndParameters(f.name, f.parameters); const isInternal = f.isInternal; const isPrivate = f.functionType === FunctionType.SECRET; // All non-unconstrained functions have vks 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 980ea702e531..77561a966b3d 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,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`basic FunctionData serialization serializes a trivial FunctionData and prints it 1`] = ` -"function_selector: 123 +"function_selector: +value: 123 + is_internal: 0 is_private: 1 is_constructor: 1 diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap index 6b16bf40e3ac..0fd029b41242 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`basic FunctionLeafPreimage serialization serializes a trivial Function Leaf Preimage and prints it 1`] = ` -"function_selector: 123 +"function_selector: +value: 8972 + is_internal: 0 is_private: 1 vk_hash: 0x0 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 bd66d31438db..266f7903eb98 100644 --- a/yarn-project/circuits.js/src/structs/function_data.test.ts +++ b/yarn-project/circuits.js/src/structs/function_data.test.ts @@ -1,3 +1,5 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; + import { expectSerializeToMatchSnapshot } from '../tests/expectSerialize.js'; import { FunctionData } from './function_data.js'; @@ -5,7 +7,7 @@ describe('basic FunctionData serialization', () => { it(`serializes a trivial FunctionData and prints it`, async () => { // Test the data case: writing (mostly) sequential numbers await expectSerializeToMatchSnapshot( - new FunctionData(Buffer.from([0, 0, 0, 123]), false, true, true).toBuffer(), + new FunctionData(new FunctionSelector(123), false, true, true).toBuffer(), 'abis__test_roundtrip_serialize_function_data', ); }); diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 8411c6fcc725..9838417a13b6 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -1,22 +1,19 @@ -import { FunctionAbi, FunctionType, generateFunctionSelector } from '@aztec/foundation/abi'; -import { BufferReader, deserializeUInt32, numToUInt32BE } from '@aztec/foundation/serialize'; +import { FunctionAbi, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { BufferReader } from '@aztec/foundation/serialize'; import { ContractFunctionDao } from '../index.js'; import { serializeToBuffer } from '../utils/serialize.js'; -const FUNCTION_SELECTOR_LENGTH = 4; - /** * Function description for circuit. * @see abis/function_data.hpp */ export class FunctionData { - /** - * Function selector of the function being called. - */ - public functionSelectorBuffer: Buffer; constructor( - functionSelector: Buffer | number, + /** + * Function selector of the function being called. + */ + public selector: FunctionSelector, /** * Indicates whether the function is only callable by self or not. */ @@ -29,41 +26,23 @@ export class FunctionData { * Indicates whether the function is a constructor. */ public isConstructor: boolean, - ) { - if (functionSelector instanceof Buffer) { - if (functionSelector.byteLength !== FUNCTION_SELECTOR_LENGTH) { - throw new Error( - `Function selector must be ${FUNCTION_SELECTOR_LENGTH} bytes long, got ${functionSelector.byteLength} bytes.`, - ); - } - this.functionSelectorBuffer = functionSelector; - } else { - // create a new numeric buffer with 4 bytes - this.functionSelectorBuffer = numToUInt32BE(functionSelector); - } - } + ) {} static fromAbi(abi: FunctionAbi | ContractFunctionDao): FunctionData { return new FunctionData( - generateFunctionSelector(abi.name, abi.parameters), + FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), abi.isInternal, abi.functionType === FunctionType.SECRET, abi.name === 'constructor', ); } - // For serialization, must match function_selector name in C++ and return as number - // TODO(AD) somehow remove this cruft, probably by using a buffer selector in C++ - get functionSelector(): number { - return deserializeUInt32(this.functionSelectorBuffer).elem; - } - /** * Serialize this as a buffer. * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.functionSelectorBuffer, this.isInternal, this.isPrivate, this.isConstructor); + return serializeToBuffer(this.selector, this.isInternal, this.isPrivate, this.isConstructor); } /** @@ -71,7 +50,7 @@ export class FunctionData { * @returns True if the function selector is zero. */ isEmpty() { - return this.functionSelectorBuffer.equals(Buffer.alloc(FUNCTION_SELECTOR_LENGTH, 0)); + return this.selector.isEmpty(); } /** @@ -94,7 +73,7 @@ export class FunctionData { isConstructor?: boolean; }): FunctionData { return new FunctionData( - Buffer.alloc(FUNCTION_SELECTOR_LENGTH, 0), + FunctionSelector.empty(), args?.isInternal ?? false, args?.isPrivate ?? false, args?.isConstructor ?? false, @@ -109,7 +88,7 @@ export class FunctionData { static fromBuffer(buffer: Buffer | BufferReader): FunctionData { const reader = BufferReader.asReader(buffer); return new FunctionData( - reader.readBytes(FUNCTION_SELECTOR_LENGTH), + reader.readObject(FunctionSelector), reader.readBoolean(), reader.readBoolean(), reader.readBoolean(), diff --git a/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts b/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts index dc278841d836..ca0296167b05 100644 --- a/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts +++ b/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts @@ -1,3 +1,4 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { expectSerializeToMatchSnapshot } from '../tests/expectSerialize.js'; @@ -7,7 +8,7 @@ describe('basic FunctionLeafPreimage serialization', () => { it(`serializes a trivial Function Leaf Preimage and prints it`, async () => { // Test the data case: writing (mostly) sequential numbers await expectSerializeToMatchSnapshot( - new FunctionLeafPreimage(Buffer.from([0, 0, 0, 123]), false, true, Fr.ZERO, Fr.ZERO).toBuffer(), + new FunctionLeafPreimage(new FunctionSelector(8972), false, true, Fr.ZERO, Fr.ZERO).toBuffer(), 'abis__test_roundtrip_serialize_function_leaf_preimage', ); }); diff --git a/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts b/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts index b60fe507e21a..b9f781202f6c 100644 --- a/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts +++ b/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts @@ -1,3 +1,4 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; @@ -8,13 +9,11 @@ import { serializeToBuffer } from '../utils/serialize.js'; * @see abis/function_leaf_preimage.hpp */ export class FunctionLeafPreimage { - readonly FUNCTION_SELECTOR_LENGTH = 4; - constructor( /** - * Function selector `FUNCTION_SELECTOR_LENGTH` bytes long. + * Function selector. */ - public functionSelector: Buffer, + public functionSelector: FunctionSelector, /** * Indicates whether the function is only callable by self or not. */ @@ -31,29 +30,13 @@ export class FunctionLeafPreimage { * Hash of the ACIR of the function. */ public acirHash: Fr, - ) { - this.assertFunctionSelectorLength(functionSelector); - } - - /** - * Assert the function selector buffer length matches `FUNCTION_SELECTOR_LENGTH`. - * @param functionSelector - The buffer containing the function selector. - * @throws If the function selector buffer length does not match `FUNCTION_SELECTOR_LENGTH`. - */ - private assertFunctionSelectorLength(functionSelector: Buffer) { - if (functionSelector.byteLength !== this.FUNCTION_SELECTOR_LENGTH) { - throw new Error( - `Function selector must be ${this.FUNCTION_SELECTOR_LENGTH} bytes long, got ${functionSelector.byteLength} bytes.`, - ); - } - } + ) {} /** * Serialize this as a buffer. * @returns The buffer. */ toBuffer(): Buffer { - this.assertFunctionSelectorLength(this.functionSelector); return serializeToBuffer(this.functionSelector, this.isInternal, this.isPrivate, this.vkHash, this.acirHash); } @@ -65,7 +48,7 @@ export class FunctionLeafPreimage { static fromBuffer(buffer: Buffer | BufferReader): FunctionLeafPreimage { const reader = BufferReader.asReader(buffer); return new FunctionLeafPreimage( - reader.readBytes(4), + reader.readObject(FunctionSelector), reader.readBoolean(), reader.readBoolean(), reader.readFr(), diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 9e26cb50f128..12307c66e255 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -32,3 +32,4 @@ export * from '@aztec/foundation/eth-address'; export * from '@aztec/foundation/fields'; export * from '@aztec/foundation/aztec-address'; +export { FunctionSelector } from '@aztec/foundation/abi'; diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index ec0ef2e189ce..bae4b965ff0f 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -94,7 +94,9 @@ portal_contract_address: 0x202020202020202020202020202020202020202 function_tree_root: 0xb03 ] optionally_revealed_data: [ call_stack_item_hash: 0xc01 -function_data: function_selector: c02 +function_data: function_selector: +value: c02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -106,7 +108,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc02 -function_data: function_selector: c03 +function_data: function_selector: +value: c03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -118,7 +122,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc03 -function_data: function_selector: c04 +function_data: function_selector: +value: c04 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -130,7 +136,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc04 -function_data: function_selector: c05 +function_data: function_selector: +value: c05 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -325,7 +333,9 @@ portal_contract_address: 0x202020202020202020202020202020202020202 function_tree_root: 0xb03 ] optionally_revealed_data: [ call_stack_item_hash: 0xc01 -function_data: function_selector: c02 +function_data: function_selector: +value: c02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -337,7 +347,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc02 -function_data: function_selector: c03 +function_data: function_selector: +value: c03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -349,7 +361,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc03 -function_data: function_selector: c04 +function_data: function_selector: +value: c04 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -361,7 +375,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc04 -function_data: function_selector: c05 +function_data: function_selector: +value: c05 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -504,7 +520,9 @@ vk_path: [ 0x1000 0x1001 0x1002 ] exports[`structs/kernel serializes and prints private_kernel_inputs_init 1`] = ` "tx_request: origin: 0x1 -function_data: function_selector: 257 +function_data: function_selector: +value: 257 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -530,7 +548,9 @@ version: 0x0 private_call: call_stack_item: contract_address: 0x1001 -function_data: function_selector: 4098 +function_data: function_selector: +value: 4098 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -580,7 +600,9 @@ version: 0x2511 is_execution_request: 0 private_call_stack_preimages: [ contract_address: 0x1011 -function_data: function_selector: 1012 +function_data: function_selector: +value: 1012 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -629,7 +651,9 @@ version: 0x2521 is_execution_request: 0 contract_address: 0x1012 -function_data: function_selector: 1013 +function_data: function_selector: +value: 1013 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -678,7 +702,9 @@ version: 0x2522 is_execution_request: 0 contract_address: 0x1013 -function_data: function_selector: 1014 +function_data: function_selector: +value: 1014 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -727,7 +753,9 @@ version: 0x2523 is_execution_request: 0 contract_address: 0x1014 -function_data: function_selector: 1015 +function_data: function_selector: +value: 1015 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -912,7 +940,9 @@ portal_contract_address: 0x202020202020202020202020202020202020202 function_tree_root: 0xb03 ] optionally_revealed_data: [ call_stack_item_hash: 0xc01 -function_data: function_selector: c02 +function_data: function_selector: +value: c02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -924,7 +954,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc02 -function_data: function_selector: c03 +function_data: function_selector: +value: c03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -936,7 +968,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc03 -function_data: function_selector: c04 +function_data: function_selector: +value: c04 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -948,7 +982,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc04 -function_data: function_selector: c05 +function_data: function_selector: +value: c05 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1089,7 +1125,9 @@ vk_path: [ 0x1000 0x1001 0x1002 ] private_call: call_stack_item: contract_address: 0x1001 -function_data: function_selector: 4098 +function_data: function_selector: +value: 4098 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1139,7 +1177,9 @@ version: 0x2511 is_execution_request: 0 private_call_stack_preimages: [ contract_address: 0x1011 -function_data: function_selector: 1012 +function_data: function_selector: +value: 1012 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1188,7 +1228,9 @@ version: 0x2521 is_execution_request: 0 contract_address: 0x1012 -function_data: function_selector: 1013 +function_data: function_selector: +value: 1013 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1237,7 +1279,9 @@ version: 0x2522 is_execution_request: 0 contract_address: 0x1013 -function_data: function_selector: 1014 +function_data: function_selector: +value: 1014 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1286,7 +1330,9 @@ version: 0x2523 is_execution_request: 0 contract_address: 0x1014 -function_data: function_selector: 1015 +function_data: function_selector: +value: 1015 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1469,7 +1515,9 @@ portal_contract_address: 0x202020202020202020202020202020202020202 function_tree_root: 0xb03 ] optionally_revealed_data: [ call_stack_item_hash: 0xc01 -function_data: function_selector: c02 +function_data: function_selector: +value: c02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1481,7 +1529,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc02 -function_data: function_selector: c03 +function_data: function_selector: +value: c03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1493,7 +1543,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc03 -function_data: function_selector: c04 +function_data: function_selector: +value: c04 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1505,7 +1557,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc04 -function_data: function_selector: c05 +function_data: function_selector: +value: c05 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1729,7 +1783,9 @@ portal_contract_address: 0x202020202020202020202020202020202020202 function_tree_root: 0xb03 ] optionally_revealed_data: [ call_stack_item_hash: 0xc01 -function_data: function_selector: c02 +function_data: function_selector: +value: c02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1741,7 +1797,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc02 -function_data: function_selector: c03 +function_data: function_selector: +value: c03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1753,7 +1811,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc03 -function_data: function_selector: c04 +function_data: function_selector: +value: c04 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1765,7 +1825,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xc04 -function_data: function_selector: c05 +function_data: function_selector: +value: c05 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -1906,7 +1968,9 @@ vk_path: [ 0x1000 0x1001 0x1002 ] public_call: call_stack_item: contract_address: 0x1001 -function_data: function_selector: 4098 +function_data: function_selector: +value: 4098 + is_internal: 0 is_private: 0 is_constructor: 0 @@ -2023,7 +2087,9 @@ prover_address: 0x1b12 is_execution_request: 0 public_call_stack_preimages: [ contract_address: 0x1301 -function_data: function_selector: 1302 +function_data: function_selector: +value: 1302 + is_internal: 0 is_private: 0 is_constructor: 0 @@ -2139,7 +2205,9 @@ prover_address: 0x1e12 is_execution_request: 0 contract_address: 0x1302 -function_data: function_selector: 1303 +function_data: function_selector: +value: 1303 + is_internal: 0 is_private: 0 is_constructor: 0 @@ -2255,7 +2323,9 @@ prover_address: 0x1e13 is_execution_request: 0 contract_address: 0x1303 -function_data: function_selector: 1304 +function_data: function_selector: +value: 1304 + is_internal: 0 is_private: 0 is_constructor: 0 @@ -2371,7 +2441,9 @@ prover_address: 0x1e14 is_execution_request: 0 contract_address: 0x1304 -function_data: function_selector: 1305 +function_data: function_selector: +value: 1305 + is_internal: 0 is_private: 0 is_constructor: 0 diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap index 2d972ee5a47a..256531c94f21 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap @@ -96,7 +96,9 @@ portal_contract_address: 0x101010101010101010101010101010101010101 function_tree_root: 0xc02 ] optionally_revealed_data: [ call_stack_item_hash: 0xd00 -function_data: function_selector: d01 +function_data: function_selector: +value: d01 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -108,7 +110,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xd01 -function_data: function_selector: d02 +function_data: function_selector: +value: d02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -120,7 +124,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xd02 -function_data: function_selector: d03 +function_data: function_selector: +value: d03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -132,7 +138,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xd03 -function_data: function_selector: d04 +function_data: function_selector: +value: d04 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -364,7 +372,9 @@ portal_contract_address: 0x101010101010101010101010101010101010101 function_tree_root: 0xd02 ] optionally_revealed_data: [ call_stack_item_hash: 0xe00 -function_data: function_selector: e01 +function_data: function_selector: +value: e01 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -376,7 +386,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xe01 -function_data: function_selector: e02 +function_data: function_selector: +value: e02 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -388,7 +400,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xe02 -function_data: function_selector: e03 +function_data: function_selector: +value: e03 + is_internal: 0 is_private: 1 is_constructor: 1 @@ -400,7 +414,9 @@ pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 call_stack_item_hash: 0xe03 -function_data: function_selector: e04 +function_data: function_selector: +value: e04 + is_internal: 0 is_private: 1 is_constructor: 1 diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index e758afa40c02..c06017314073 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -24,6 +24,7 @@ import { Fq, Fr, FunctionData, + FunctionSelector, G1AffineElement, HISTORIC_BLOCKS_TREE_HEIGHT, HistoricBlockData, @@ -134,10 +135,8 @@ export function makeConstantData(seed = 1): CombinedConstantData { * @param seed - The seed to use for generating the selector. * @returns A selector. */ -export function makeSelector(seed: number): Buffer { - const buffer = Buffer.alloc(4); - buffer.writeUInt32BE(seed, 0); - return buffer; +export function makeSelector(seed: number): FunctionSelector { + return new FunctionSelector(seed); } /** diff --git a/yarn-project/circuits.js/src/types/contract_function_dao.ts b/yarn-project/circuits.js/src/types/contract_function_dao.ts index 020964755bb1..597d2f525cf6 100644 --- a/yarn-project/circuits.js/src/types/contract_function_dao.ts +++ b/yarn-project/circuits.js/src/types/contract_function_dao.ts @@ -1,5 +1,7 @@ import { FunctionAbi } from '@aztec/foundation/abi'; +import { FunctionSelector } from '../index.js'; + /** * A contract function Data Access Object (DAO). * Extends the FunctionAbi interface, adding a 'selector' property. @@ -9,5 +11,5 @@ export interface ContractFunctionDao extends FunctionAbi { /** * Unique identifier for a contract function. */ - selector: Buffer; + selector: FunctionSelector; } diff --git a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts index 1296a9b955c2..f35675389480 100644 --- a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts @@ -1,8 +1,7 @@ import { AztecNodeService } from '@aztec/aztec-node'; import { AztecRPCServer } from '@aztec/aztec-rpc'; import { AztecAddress, BatchCall, Wallet, generatePublicKey } from '@aztec/aztec.js'; -import { CompleteAddress, Fr, PrivateKey, getContractDeploymentInfo } from '@aztec/circuits.js'; -import { generateFunctionSelector } from '@aztec/foundation/abi'; +import { CompleteAddress, Fr, FunctionSelector, PrivateKey, getContractDeploymentInfo } from '@aztec/circuits.js'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { DebugLogger } from '@aztec/foundation/log'; import { EscrowContractAbi, PrivateTokenContractAbi } from '@aztec/noir-contracts/artifacts'; @@ -29,8 +28,8 @@ describe('e2e_escrow_contract', () => { beforeAll(() => { // Validate transfer selector. If this fails, then make sure to change it in the escrow contract. const transferAbi = PrivateTokenContractAbi.functions.find(f => f.name === 'transfer')!; - const transferSelector = generateFunctionSelector(transferAbi.name, transferAbi.parameters); - expect(transferSelector).toEqual(toBufferBE(0xdcd4c318n, 4)); + const transferSelector = FunctionSelector.fromNameAndParameters(transferAbi.name, transferAbi.parameters); + expect(transferSelector.toBuffer()).toEqual(toBufferBE(0xdcd4c318n, 4)); }); beforeEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_multi_transfer.test.ts b/yarn-project/end-to-end/src/e2e_multi_transfer.test.ts index 073032fcb28c..76af3b09c4d8 100644 --- a/yarn-project/end-to-end/src/e2e_multi_transfer.test.ts +++ b/yarn-project/end-to-end/src/e2e_multi_transfer.test.ts @@ -1,6 +1,6 @@ import { AztecNodeService } from '@aztec/aztec-node'; import { AztecRPCServer } from '@aztec/aztec-rpc'; -import { AztecAddress, Contract, Fr, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, Contract, Wallet } from '@aztec/aztec.js'; import { DebugLogger } from '@aztec/foundation/log'; import { MultiTransferContract, PrivateTokenAirdropContract } from '@aztec/noir-contracts/types'; import { AztecRPC, CompleteAddress } from '@aztec/types'; @@ -125,7 +125,7 @@ describe('multi-transfer payments', () => { recipients, amounts, ownerAddress, - Fr.fromBuffer(zkTokenContract.methods.batchTransfer.selector), + zkTokenContract.methods.batchTransfer.selector.toField(), noteOffsets, ) .send({ origin: ownerAddress }); @@ -180,7 +180,7 @@ describe('multi-transfer payments', () => { repeatedSelfAdddress, amounts, ownerAddress, - Fr.fromBuffer(zkTokenContract.methods.batchTransfer.selector), + zkTokenContract.methods.batchTransfer.selector.toField(), noteOffsets, ) .send({ origin: ownerAddress }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index 54f4bd9d9182..73429762f952 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -62,7 +62,7 @@ describe('e2e_nested_contract', () => { */ it('performs nested calls', async () => { const tx = parentContract.methods - .entryPoint(childContract.address, Fr.fromBuffer(childContract.methods.value.selector)) + .entryPoint(childContract.address, childContract.methods.value.selector.toField()) .send({ origin: sender }); await tx.isMined({ interval: 0.1 }); @@ -73,7 +73,7 @@ describe('e2e_nested_contract', () => { it('performs public nested calls', async () => { const tx = parentContract.methods - .pubEntryPoint(childContract.address, Fr.fromBuffer(childContract.methods.pubGetValue.selector), 42n) + .pubEntryPoint(childContract.address, childContract.methods.pubGetValue.selector.toField(), 42n) .send({ origin: sender }); await tx.isMined({ interval: 0.1 }); @@ -84,7 +84,7 @@ describe('e2e_nested_contract', () => { it('enqueues a single public call', async () => { const tx = parentContract.methods - .enqueueCallToChild(childContract.address, Fr.fromBuffer(childContract.methods.pubIncValue.selector), 42n) + .enqueueCallToChild(childContract.address, childContract.methods.pubIncValue.selector.toField(), 42n) .send({ origin: sender }); await tx.isMined({ interval: 0.1 }); @@ -101,7 +101,7 @@ describe('e2e_nested_contract', () => { const tx = parentContract.methods .enqueueCallToChildTwice( addressToField(childContract.address), - Fr.fromBuffer(childContract.methods.pubIncValue.selector).value, + childContract.methods.pubIncValue.selector.value, 42n, ) .send({ origin: sender }); @@ -115,11 +115,7 @@ describe('e2e_nested_contract', () => { it('enqueues a public call with nested public calls', async () => { const tx = parentContract.methods - .enqueueCallToPubEntryPoint( - childContract.address, - Fr.fromBuffer(childContract.methods.pubIncValue.selector), - 42n, - ) + .enqueueCallToPubEntryPoint(childContract.address, childContract.methods.pubIncValue.selector.toField(), 42n) .send({ origin: sender }); await tx.isMined({ interval: 0.1 }); @@ -134,11 +130,7 @@ describe('e2e_nested_contract', () => { // Task to repair this test: https://github.com/AztecProtocol/aztec-packages/issues/1587 it.skip('enqueues multiple public calls with nested public calls', async () => { const tx = parentContract.methods - .enqueueCallsToPubEntryPoint( - childContract.address, - Fr.fromBuffer(childContract.methods.pubIncValue.selector), - 42n, - ) + .enqueueCallsToPubEntryPoint(childContract.address, childContract.methods.pubIncValue.selector.toField(), 42n) .send({ origin: sender }); await tx.isMined({ interval: 0.1 }); @@ -156,7 +148,7 @@ describe('e2e_nested_contract', () => { const tx = parentContract.methods .pubEntryPointTwice( addressToField(childContract.address), - Fr.fromBuffer(childContract.methods.pubIncValue.selector).value, + childContract.methods.pubIncValue.selector.value, 42n, ) .send({ origin: sender }); diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index 6fae8e747adc..eb901293c22f 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -2,7 +2,7 @@ import { AztecNodeService } from '@aztec/aztec-node'; import { AztecRPCServer } from '@aztec/aztec-rpc'; import { Wallet } from '@aztec/aztec.js'; -import { Fr } from '@aztec/circuits.js'; +import { Fr, FunctionSelector } from '@aztec/circuits.js'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { toBigInt } from '@aztec/foundation/serialize'; import { ChildContract, ParentContract } from '@aztec/noir-contracts/types'; @@ -39,7 +39,7 @@ describe('e2e_ordering', () => { describe('with parent and child contract', () => { let parent: ParentContract; let child: ChildContract; - let pubSetValueSelector: Buffer; + let pubSetValueSelector: FunctionSelector; beforeEach(async () => { parent = await ParentContract.deploy(wallet).send().deployed(); diff --git a/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts b/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts index 7749b47d01b4..6fa2035341e9 100644 --- a/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts @@ -93,9 +93,9 @@ describe('e2e_pending_commitments_contract', () => { .test_insert_then_get_then_nullify_all_in_nested_calls( mintAmount, owner, - Fr.fromBuffer(deployedContract.methods.insert_note.selector), - Fr.fromBuffer(deployedContract.methods.get_then_nullify_note.selector), - Fr.fromBuffer(deployedContract.methods.get_note_zero_balance.selector), + deployedContract.methods.insert_note.selector.toField(), + deployedContract.methods.get_then_nullify_note.selector.toField(), + deployedContract.methods.get_note_zero_balance.selector.toField(), ) .send({ origin: owner }); @@ -118,8 +118,8 @@ describe('e2e_pending_commitments_contract', () => { .test_insert2_then_get2_then_nullify2_all_in_nested_calls( mintAmount, owner, - Fr.fromBuffer(deployedContract.methods.insert_note.selector), - Fr.fromBuffer(deployedContract.methods.get_then_nullify_note.selector), + deployedContract.methods.insert_note.selector.toField(), + deployedContract.methods.get_then_nullify_note.selector.toField(), ) .send({ origin: owner }); @@ -143,8 +143,8 @@ describe('e2e_pending_commitments_contract', () => { .test_insert2_then_get2_then_nullify1_all_in_nested_calls( mintAmount, owner, - Fr.fromBuffer(deployedContract.methods.insert_note.selector), - Fr.fromBuffer(deployedContract.methods.get_then_nullify_note.selector), + deployedContract.methods.insert_note.selector.toField(), + deployedContract.methods.get_then_nullify_note.selector.toField(), ) .send({ origin: owner }); @@ -181,9 +181,9 @@ describe('e2e_pending_commitments_contract', () => { .test_insert1_then_get2_then_nullify2_all_in_nested_calls( mintAmount, owner, - Fr.fromBuffer(deployedContract.methods.insert_note.selector), - Fr.fromBuffer(deployedContract.methods.get_then_nullify_note.selector), - Fr.fromBuffer(deployedContract.methods.get_note_zero_balance.selector), + deployedContract.methods.insert_note.selector.toField(), + deployedContract.methods.get_then_nullify_note.selector.toField(), + deployedContract.methods.get_note_zero_balance.selector.toField(), ) .send({ origin: owner }); @@ -220,9 +220,9 @@ describe('e2e_pending_commitments_contract', () => { .test_insert_then_get_then_nullify_all_in_nested_calls( mintAmount, owner, - Fr.fromBuffer(deployedContract.methods.dummy.selector), - Fr.fromBuffer(deployedContract.methods.get_then_nullify_note.selector), - Fr.fromBuffer(deployedContract.methods.get_note_zero_balance.selector), + deployedContract.methods.dummy.selector.toField(), + deployedContract.methods.get_then_nullify_note.selector.toField(), + deployedContract.methods.get_note_zero_balance.selector.toField(), ) .send({ origin: owner }); diff --git a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts index f1934b2606ba..688815a24d26 100644 --- a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts @@ -189,7 +189,7 @@ describe('uniswap_trade_on_l1_from_l2', () => { // 4. Send L2 to L1 message to withdraw funds and another message to swap assets. logger('Send L2 tx to withdraw WETH to uniswap portal and send message to swap assets on L1'); - const selector = Fr.fromBuffer(wethCrossChainHarness.l2Contract.methods.withdraw.selector); + const selector = wethCrossChainHarness.l2Contract.methods.withdraw.selector.toField(); const minimumOutputAmount = 0; const withdrawTx = uniswapL2Contract.methods diff --git a/yarn-project/foundation/src/abi/abi_coder.ts b/yarn-project/foundation/src/abi/abi_coder.ts index 5fd4ccd48faf..6971b423757c 100644 --- a/yarn-project/foundation/src/abi/abi_coder.ts +++ b/yarn-project/foundation/src/abi/abi_coder.ts @@ -1,41 +1,4 @@ -import { ABIParameter, ABIType } from '@aztec/foundation/abi'; -import { keccak } from '@aztec/foundation/crypto'; - -/** - * Generate a function signature string for a given function name and parameters. - * The signature is used to uniquely identify functions within noir contracts. - * If the function name is 'constructor', it returns just the name, otherwise it returns the name followed by the list of parameter types. - * - * @param name - The name of the function. - * @param parameters - An array of ABIParameter objects, each containing the type information of a function parameter. - * @returns A string representing the function signature. - */ -export function computeFunctionSignature(name: string, parameters: ABIParameter[]) { - return name === 'constructor' ? name : `${name}(${parameters.map(p => p.type.kind).join(',')})`; -} - -/** - * Generate a function selector for a given function signature. - * @param signature - The signature of the function. - * @param size - Number of bytes of the return buffer. - * @returns A Buffer containing the n-byte function selector. - */ -export function computeFunctionSelector(signature: string, size: number) { - return keccak(Buffer.from(signature)).slice(0, size); -} - -/** - * Generate a function selector for a given function name and parameters. - * It is derived by taking the first 4 bytes of the Keccak-256 hash of the function signature. - * - * @param name - The name of the function. - * @param parameters - An array of ABIParameter objects, each containing the type information of a function parameter. - * @returns A Buffer containing the 4-byte function selector. - */ -export function generateFunctionSelector(name: string, parameters: ABIParameter[]) { - const signature = computeFunctionSignature(name, parameters); - return computeFunctionSelector(signature, 4); -} +import { ABIType } from '@aztec/foundation/abi'; /** * Get the size of an ABI type in field elements. diff --git a/yarn-project/foundation/src/abi/function_selector.ts b/yarn-project/foundation/src/abi/function_selector.ts new file mode 100644 index 000000000000..dac9909eaaa7 --- /dev/null +++ b/yarn-project/foundation/src/abi/function_selector.ts @@ -0,0 +1,111 @@ +import { ABIParameter } from '@aztec/foundation/abi'; +import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; +import { keccak } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader } from '@aztec/foundation/serialize'; + +/** + * A function selector is the first 4 bytes of the hash of a function signature. + */ +export class FunctionSelector { + /** + * The size of the function selector in bytes. + */ + public static SIZE = 4; + + constructor(/** number representing the function selector */ public value: number) { + if (value > 2 ** (FunctionSelector.SIZE * 8) - 1) { + throw new Error(`Function selector must fit in ${FunctionSelector.SIZE} bytes.`); + } + } + + /** + * Checks if the function selector is empty (all bytes are 0). + * @returns True if the function selector is empty (all bytes are 0). + */ + public isEmpty(): boolean { + return this.value === 0; + } + + /** + * Serialize as a buffer. + * @returns The buffer. + */ + toBuffer(): Buffer { + return toBufferBE(BigInt(this.value), FunctionSelector.SIZE); + } + + /** + * Serialize as a hex string. + * @returns The string. + */ + toString(): string { + return this.toBuffer().toString('hex'); + } + + /** + * Checks if this function selector is equal to another. + * @param other - The other function selector. + * @returns True if the function selectors are equal. + */ + equals(other: FunctionSelector): boolean { + return this.value === other.value; + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or BufferReader to read from. + * @returns The FunctionSelector. + */ + static fromBuffer(buffer: Buffer | BufferReader): FunctionSelector { + const reader = BufferReader.asReader(buffer); + const value = Number(toBigIntBE(reader.readBytes(FunctionSelector.SIZE))); + return new FunctionSelector(value); + } + + /** + * Returns a new field with the same contents as this EthAddress. + * + * @returns An Fr instance. + */ + public toField() { + return new Fr(this.value); + } + + /** + * Converts a field to function selector. + * @param fr - The field to convert. + * @returns The function selector. + */ + static fromField(fr: Fr): FunctionSelector { + return new FunctionSelector(Number(fr.value)); + } + + /** + * Creates a function selector from a signature. + * @param signature - Signature of the function to generate the selector for (e.g. "transfer(field,field)"). + * @returns Function selector. + */ + static fromSignature(signature: string): FunctionSelector { + return FunctionSelector.fromBuffer(keccak(Buffer.from(signature)).subarray(0, FunctionSelector.SIZE)); + } + + /** + * Creates a function selector for a given function name and parameters. + * @param name - The name of the function. + * @param parameters - An array of ABIParameter objects, each containing the type information of a function parameter. + * @returns A Buffer containing the 4-byte function selector. + */ + static fromNameAndParameters(name: string, parameters: ABIParameter[]) { + const signature = name === 'constructor' ? name : `${name}(${parameters.map(p => p.type.kind).join(',')})`; + return FunctionSelector.fromSignature(signature); + } + + /** + * Creates an empty function selector. + * @returns An empty function selector. + */ + static empty(): FunctionSelector { + return new FunctionSelector(0); + } +} diff --git a/yarn-project/foundation/src/abi/index.ts b/yarn-project/foundation/src/abi/index.ts index 7553e11adba4..556c2150f394 100644 --- a/yarn-project/foundation/src/abi/index.ts +++ b/yarn-project/foundation/src/abi/index.ts @@ -2,3 +2,4 @@ export * from './abi.js'; export * from './abi_coder.js'; export * from './encoder.js'; export * from './decoder.js'; +export * from './function_selector.js'; diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts b/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts index b5773e23469d..8de534828342 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts @@ -3,9 +3,9 @@ import { ABIVariable, ContractAbi, FunctionAbi, + FunctionSelector, FunctionType, StructType, - generateFunctionSelector, } from '@aztec/foundation/abi'; import camelCase from 'lodash.camelcase'; @@ -28,10 +28,10 @@ function isPrivateCall(functionType: FunctionType) { * @param functionType - Type of the function. * @returns A code string. */ -function generateCallStatement(selector: string, functionType: FunctionType) { +function generateCallStatement(selector: FunctionSelector, functionType: FunctionType) { const callMethod = isPrivateCall(functionType) ? 'call_private_function' : 'call_public_function'; return ` - context.${callMethod}(self.address, ${selector}, serialised_args)`; + context.${callMethod}(self.address, 0x${selector.toString()}, serialised_args)`; } /** @@ -91,7 +91,7 @@ function generateParameter(param: ABIParameter, functionData: FunctionAbi) { /** * Collects all parameters for a given function and flattens them according to how they should be serialised. - * @param parameters - Paramters for a function. + * @param parameters - Parameters for a function. * @returns List of parameters flattened to basic data types. */ function collectParametersForSerialisation(parameters: ABIVariable[]) { @@ -139,7 +139,7 @@ function generateSerialisation(parameters: ABIParameter[]) { */ function generateFunctionInterface(functionData: FunctionAbi) { const { name, parameters } = functionData; - const selector = '0x' + generateFunctionSelector(name, parameters).toString('hex'); + const selector = FunctionSelector.fromNameAndParameters(name, parameters); const serialisation = generateSerialisation(parameters); const callStatement = generateCallStatement(selector, functionData.functionType); const allParams = [ @@ -160,7 +160,7 @@ ${callStatement} } /** - * Generates static impots. + * Generates static imports. * @returns A string of code which will be needed in every contract interface, regardless of the contract. */ function generateStaticImports() { diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 5c561cc544b6..8ff1a223ca0b 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -170,7 +170,7 @@ export class PublicProcessor { const isExecutionRequest = !isPublicExecutionResult(current); const result = isExecutionRequest ? await this.publicExecutor.execute(current, this.globalVariables) : current; newUnencryptedFunctionLogs.push(result.unencryptedLogs); - const functionSelector = result.execution.functionData.functionSelectorBuffer.toString('hex'); + const functionSelector = result.execution.functionData.selector.toString(); this.log( `Running public kernel circuit for ${functionSelector}@${result.execution.contractAddress.toString()}`, ); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 6d144958f457..bef534b6228d 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -6,7 +6,7 @@ import { PublicExecutor, PublicStateDB, } from '@aztec/acir-simulator'; -import { AztecAddress, CircuitsWasm, EthAddress, Fr, HistoricBlockData } from '@aztec/circuits.js'; +import { AztecAddress, CircuitsWasm, EthAddress, Fr, FunctionSelector, HistoricBlockData } from '@aztec/circuits.js'; import { siloCommitment } from '@aztec/circuits.js/abis'; import { ContractDataSource, L1ToL2MessageSource, MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations, computePublicDataTreeLeafIndex } from '@aztec/world-state'; @@ -36,11 +36,11 @@ export function getPublicExecutor( */ class ContractsDataSourcePublicDB implements PublicContractsDB { constructor(private db: ContractDataSource) {} - async getBytecode(address: AztecAddress, functionSelector: Buffer): Promise { - return (await this.db.getPublicFunction(address, functionSelector))?.bytecode; + async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise { + return (await this.db.getPublicFunction(address, selector))?.bytecode; } - async getIsInternal(address: AztecAddress, functionSelector: Buffer): Promise { - return (await this.db.getPublicFunction(address, functionSelector))?.isInternal; + async getIsInternal(address: AztecAddress, selector: FunctionSelector): Promise { + return (await this.db.getPublicFunction(address, selector))?.isInternal; } async getPortalContractAddress(address: AztecAddress): Promise { return (await this.db.getContractData(address))?.portalContractAddress; diff --git a/yarn-project/types/src/contract_dao.ts b/yarn-project/types/src/contract_dao.ts index 9b9ebab9c74d..3faf57469216 100644 --- a/yarn-project/types/src/contract_dao.ts +++ b/yarn-project/types/src/contract_dao.ts @@ -1,5 +1,5 @@ import { ContractFunctionDao } from '@aztec/circuits.js'; -import { ContractAbi, FunctionType, generateFunctionSelector } from '@aztec/foundation/abi'; +import { ContractAbi, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -37,7 +37,7 @@ export interface ContractDao extends ContractAbi { export function toContractDao(abi: ContractAbi, address: AztecAddress, portalContract: EthAddress): ContractDao { const functions = abi.functions.map(f => ({ ...f, - selector: generateFunctionSelector(f.name, f.parameters), + selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), })); return { ...abi, @@ -58,7 +58,7 @@ export function getNewContractPublicFunctions(newContract: ContractDao) { .map( fn => new EncodedContractFunction( - generateFunctionSelector(fn.name, fn.parameters), + FunctionSelector.fromNameAndParameters(fn.name, fn.parameters), fn.isInternal ?? false, Buffer.from(fn.bytecode, 'base64'), ), diff --git a/yarn-project/types/src/contract_data.ts b/yarn-project/types/src/contract_data.ts index 499ec52d7ac6..0879bd5d05d1 100644 --- a/yarn-project/types/src/contract_data.ts +++ b/yarn-project/types/src/contract_data.ts @@ -1,4 +1,4 @@ -import { FUNCTION_SELECTOR_NUM_BYTES } from '@aztec/circuits.js'; +import { FUNCTION_SELECTOR_NUM_BYTES, FunctionSelector } from '@aztec/circuits.js'; import { BufferReader, serializeToBuffer } from '@aztec/circuits.js/utils'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { randomBytes } from '@aztec/foundation/crypto'; @@ -45,10 +45,10 @@ export interface ContractDataSource { /** * Returns a contract's encoded public function, given its function selector. * @param address - The contract aztec address. - * @param functionSelector - The function's selector. + * @param selector - The function's selector. * @returns The function's data. */ - getPublicFunction(address: AztecAddress, functionSelector: Buffer): Promise; + getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise; } /** @@ -59,7 +59,7 @@ export class EncodedContractFunction { /** * The function selector. */ - public functionSelector: Buffer, + public selector: FunctionSelector, /** * Whether the function is internal. */ @@ -76,7 +76,7 @@ export class EncodedContractFunction { */ toBuffer(): Buffer { const bytecodeBuf = Buffer.concat([numToInt32BE(this.bytecode.length), this.bytecode]); - return serializeToBuffer(this.functionSelector, this.isInternal, bytecodeBuf); + return serializeToBuffer(this.selector, this.isInternal, bytecodeBuf); } /** @@ -86,7 +86,7 @@ export class EncodedContractFunction { */ static fromBuffer(buffer: Buffer | BufferReader): EncodedContractFunction { const reader = BufferReader.asReader(buffer); - const fnSelector = reader.readBytes(FUNCTION_SELECTOR_NUM_BYTES); + const fnSelector = FunctionSelector.fromBuffer(reader.readBytes(FUNCTION_SELECTOR_NUM_BYTES)); const isInternal = reader.readBoolean(); return new EncodedContractFunction(fnSelector, isInternal, reader.readBuffer()); } @@ -96,7 +96,7 @@ export class EncodedContractFunction { * @returns A random contract function. */ static random(): EncodedContractFunction { - return new EncodedContractFunction(randomBytes(4), false, randomBytes(64)); + return new EncodedContractFunction(FunctionSelector.fromBuffer(randomBytes(4)), false, randomBytes(64)); } } @@ -128,11 +128,11 @@ export class ContractDataAndBytecode { /** * Gets the public function data or undefined. - * @param functionSelector - The function selector of the function to fetch. + * @param selector - The function selector of the function to fetch. * @returns The public function data (if found). */ - public getPublicFunction(functionSelector: Buffer): EncodedContractFunction | undefined { - return this.publicFunctions.find(fn => fn.functionSelector.equals(functionSelector)); + public getPublicFunction(selector: FunctionSelector): EncodedContractFunction | undefined { + return this.publicFunctions.find(fn => fn.selector.equals(selector)); } /**