diff --git a/.circleci/config.yml b/.circleci/config.yml index 2192378fa81..e449efc6620 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -430,6 +430,11 @@ jobs: command: | should_release || exit 0 yarn-project/deploy_npm.sh canary + - run: + name: "Release canary to NPM: l1-contracts" + command: | + should_release || exit 0 + deploy_npm l1-contracts canary - run: name: "Release latest to NPM: bb.js" command: | @@ -440,6 +445,11 @@ jobs: command: | should_release || exit 0 yarn-project/deploy_npm.sh latest + - run: + name: "Release latest to NPM: l1-contracts" + command: | + should_release || exit 0 + deploy_npm l1-contracts latest - run: name: "Update aztec-up" command: | diff --git a/.github/spot-runner-action/src/userdata.ts b/.github/spot-runner-action/src/userdata.ts index 976cad46eb8..e15b7097e6b 100644 --- a/.github/spot-runner-action/src/userdata.ts +++ b/.github/spot-runner-action/src/userdata.ts @@ -22,7 +22,8 @@ export class UserData { `sudo service docker restart`, "sudo wget -q https://github.com/earthly/earthly/releases/download/v0.8.10/earthly-linux-$(dpkg --print-architecture) -O /usr/local/bin/earthly", "sudo chmod +x /usr/local/bin/earthly", - "for i in {1..3} ; do sudo apt install -y brotli && break; sleep 10; done", + `sudo bash -c 'echo \'Acquire::Retries "3"; Acquire::https::Timeout "240"; Acquire::http::Timeout "240"; APT::Get::Assume-Yes "true"; APT::Install-Recommends "false"; APT::Install-Suggests "false";\' > /etc/apt/apt.conf.d/99-aztec-build'`, + "sudo apt install -y brotli", 'echo "MaxStartups 1000" >> /etc/ssh/sshd_config', 'echo "ClientAliveInterval=30" >> /etc/ssh/sshd_config', 'echo "ClientAliveCountMax=20" >> /etc/ssh/sshd_config', @@ -35,4 +36,4 @@ export class UserData { ); return Buffer.from(cmds.join("\n")).toString("base64"); } -} \ No newline at end of file +} diff --git a/.github/workflows/publish-bb.yml b/.github/workflows/publish-bb.yml index ec489f03244..fc5e0acdce0 100644 --- a/.github/workflows/publish-bb.yml +++ b/.github/workflows/publish-bb.yml @@ -204,6 +204,7 @@ jobs: build-check: name: Check builds are successful needs: [build-x86_64-linux-gnu, build-mac-intel, build-mac-m1,build-wasm-ts] + if: ${{ always() }} runs-on: ubuntu-latest steps: - name: Report overall success diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 8c45fb977e3..e3fd79051d0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -5,6 +5,7 @@ #include "barretenberg/stdlib/primitives/field/field_conversion.hpp" #include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" +#include "proof_surgeon.hpp" #include namespace acir_format { @@ -333,26 +334,13 @@ void process_honk_recursion_constraints(Builder& builder, stdlib::recursion::init_default_agg_obj_indices(builder); // Add recursion constraints - for (size_t i = 0; i < constraint_system.honk_recursion_constraints.size(); ++i) { - auto& constraint = constraint_system.honk_recursion_constraints.at(i); - // A proof passed into the constraint should be stripped of its inner public inputs, but not the nested - // aggregation object itself. The verifier circuit requires that the indices to a nested proof aggregation - // state are a circuit constant. The user tells us they how they want these constants set by keeping the - // nested aggregation object attached to the proof as public inputs. - for (size_t i = 0; i < bb::AGGREGATION_OBJECT_SIZE; ++i) { - // Adding the nested aggregation object to the constraint's public inputs - constraint.public_inputs.emplace_back(constraint.proof[HONK_RECURSION_PUBLIC_INPUT_OFFSET + i]); - } - // Remove the aggregation object so that they can be handled as normal public inputs - // in they way that the recursion constraint expects - constraint.proof.erase( - constraint.proof.begin() + HONK_RECURSION_PUBLIC_INPUT_OFFSET, - constraint.proof.begin() + - static_cast(HONK_RECURSION_PUBLIC_INPUT_OFFSET + bb::AGGREGATION_OBJECT_SIZE)); + size_t idx = 0; + for (auto& constraint : constraint_system.honk_recursion_constraints) { current_aggregation_object = create_honk_recursion_constraints( builder, constraint, current_aggregation_object, has_valid_witness_assignments); + gate_counter.track_diff(constraint_system.gates_per_opcode, - constraint_system.original_opcode_indices.honk_recursion_constraints.at(i)); + constraint_system.original_opcode_indices.honk_recursion_constraints.at(idx++)); } // Now that the circuit has been completely built, we add the output aggregation as public diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp index 5d013cd65ae..8813b9c7614 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp @@ -6,6 +6,7 @@ #include "barretenberg/stdlib/primitives/bigfield/constants.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp" +#include "proof_surgeon.hpp" #include "recursion_constraint.hpp" namespace acir_format { @@ -22,39 +23,41 @@ using aggregation_state_ct = bb::stdlib::recursion::aggregation_state; * aggregation object, and commitments. * * @param builder - * @param input + * @param proof_size Size of proof with NO public inputs + * @param public_inputs_size Total size of public inputs including aggregation object * @param key_fields * @param proof_fields */ void create_dummy_vkey_and_proof(Builder& builder, - const RecursionConstraint& input, - std::vector& key_fields, - std::vector& proof_fields) + size_t proof_size, + size_t public_inputs_size, + const std::vector& key_fields, + const std::vector& proof_fields) { - using Flavor = UltraRecursiveFlavor_; + using Flavor = UltraFlavor; // Set vkey->circuit_size correctly based on the proof size - size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs(); - size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs(); - assert((input.proof.size() - HONK_RECURSION_PUBLIC_INPUT_OFFSET - UltraFlavor::NUM_WITNESS_ENTITIES * num_frs_comm - - UltraFlavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) % - (num_frs_comm + num_frs_fr * UltraFlavor::BATCHED_RELATION_PARTIAL_LENGTH) == + size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs(); + size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs(); + assert((proof_size - HONK_RECURSION_PUBLIC_INPUT_OFFSET - Flavor::NUM_WITNESS_ENTITIES * num_frs_comm - + Flavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) % + (num_frs_comm + num_frs_fr * Flavor::BATCHED_RELATION_PARTIAL_LENGTH) == 0); // Note: this computation should always result in log_circuit_size = CONST_PROOF_SIZE_LOG_N auto log_circuit_size = - (input.proof.size() - HONK_RECURSION_PUBLIC_INPUT_OFFSET - UltraFlavor::NUM_WITNESS_ENTITIES * num_frs_comm - - UltraFlavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) / - (num_frs_comm + num_frs_fr * UltraFlavor::BATCHED_RELATION_PARTIAL_LENGTH); + (proof_size - HONK_RECURSION_PUBLIC_INPUT_OFFSET - Flavor::NUM_WITNESS_ENTITIES * num_frs_comm - + Flavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) / + (num_frs_comm + num_frs_fr * Flavor::BATCHED_RELATION_PARTIAL_LENGTH); // First key field is circuit size builder.assert_equal(builder.add_variable(1 << log_circuit_size), key_fields[0].witness_index); // Second key field is number of public inputs - builder.assert_equal(builder.add_variable(input.public_inputs.size()), key_fields[1].witness_index); + builder.assert_equal(builder.add_variable(public_inputs_size), key_fields[1].witness_index); // Third key field is the pub inputs offset - builder.assert_equal(builder.add_variable(UltraFlavor::has_zero_row ? 1 : 0), key_fields[2].witness_index); + builder.assert_equal(builder.add_variable(Flavor::has_zero_row ? 1 : 0), key_fields[2].witness_index); // Fourth key field is the whether the proof contains an aggregation object. - builder.assert_equal(builder.add_variable(1), key_fields[4].witness_index); + builder.assert_equal(builder.add_variable(1), key_fields[3].witness_index); uint32_t offset = 4; - size_t num_inner_public_inputs = input.public_inputs.size() - bb::AGGREGATION_OBJECT_SIZE; + size_t num_inner_public_inputs = public_inputs_size - bb::AGGREGATION_OBJECT_SIZE; // We are making the assumption that the aggregation object are behind all the inner public inputs for (size_t i = 0; i < bb::AGGREGATION_OBJECT_SIZE; i++) { @@ -75,8 +78,8 @@ void create_dummy_vkey_and_proof(Builder& builder, offset = HONK_RECURSION_PUBLIC_INPUT_OFFSET; // first 3 things builder.assert_equal(builder.add_variable(1 << log_circuit_size), proof_fields[0].witness_index); - builder.assert_equal(builder.add_variable(input.public_inputs.size()), proof_fields[1].witness_index); - builder.assert_equal(builder.add_variable(UltraFlavor::has_zero_row ? 1 : 0), proof_fields[2].witness_index); + builder.assert_equal(builder.add_variable(public_inputs_size), proof_fields[1].witness_index); + builder.assert_equal(builder.add_variable(Flavor::has_zero_row ? 1 : 0), proof_fields[2].witness_index); // the inner public inputs for (size_t i = 0; i < num_inner_public_inputs; i++) { @@ -134,7 +137,7 @@ void create_dummy_vkey_and_proof(Builder& builder, builder.assert_equal(builder.add_variable(frs[3]), proof_fields[offset + 3].witness_index); offset += 4; } - ASSERT(offset == input.proof.size() + input.public_inputs.size()); + ASSERT(offset == proof_size + public_inputs_size); } /** @@ -171,27 +174,26 @@ AggregationObjectIndices create_honk_recursion_constraints(Builder& builder, } std::vector proof_fields; - // Insert the public inputs in the middle the proof fields after 'inner_public_input_offset' because this is how the - // core barretenberg library processes proofs (with the public inputs starting at the third element and not - // separate from the rest of the proof) - proof_fields.reserve(input.proof.size() + input.public_inputs.size()); - size_t i = 0; - for (const auto& idx : input.proof) { + + // Create witness indices for the proof with public inputs reinserted + std::vector proof_indices = + ProofSurgeon::create_indices_for_reconstructed_proof(input.proof, input.public_inputs); + proof_fields.reserve(proof_indices.size()); + for (const auto& idx : proof_indices) { auto field = field_ct::from_witness_index(&builder, idx); proof_fields.emplace_back(field); - i++; - if (i == HONK_RECURSION_PUBLIC_INPUT_OFFSET) { - for (const auto& idx : input.public_inputs) { - auto field = field_ct::from_witness_index(&builder, idx); - proof_fields.emplace_back(field); - } - } } - // Populate the key fields and proof fields with dummy values to prevent issues (usually with points not being on - // the curve). + + // Populate the key fields and proof fields with dummy values to prevent issues (e.g. points must be on curve). if (!has_valid_witness_assignments) { - create_dummy_vkey_and_proof(builder, input, key_fields, proof_fields); + // In the constraint, the agg object public inputs are still contained in the proof. To get the 'raw' size of + // the proof and public_inputs we subtract and add the corresponding amount from the respective sizes. + size_t size_of_proof_with_no_pub_inputs = input.proof.size() - bb::AGGREGATION_OBJECT_SIZE; + size_t total_num_public_inputs = input.public_inputs.size() + bb::AGGREGATION_OBJECT_SIZE; + create_dummy_vkey_and_proof( + builder, size_of_proof_with_no_pub_inputs, total_num_public_inputs, key_fields, proof_fields); } + // Recursively verify the proof auto vkey = std::make_shared(builder, key_fields); RecursiveVerifier verifier(&builder, vkey); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp index 9fe6d5a0ca8..b3741756cbd 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp @@ -8,10 +8,6 @@ using Builder = bb::UltraCircuitBuilder; using namespace bb; -// In Honk, the proof starts with circuit_size, num_public_inputs, and pub_input_offset. We use this offset to keep -// track of where the public inputs start. -static constexpr size_t HONK_RECURSION_PUBLIC_INPUT_OFFSET = 3; - AggregationObjectIndices create_honk_recursion_constraints(Builder& builder, const RecursionConstraint& input, AggregationObjectIndices input_aggregation_object, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp index dc3e1222f7e..b216375b53c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp @@ -4,6 +4,7 @@ #include "barretenberg/sumcheck/instance/prover_instance.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" +#include "proof_surgeon.hpp" #include #include @@ -140,7 +141,6 @@ class AcirHonkRecursionConstraint : public ::testing::Test { { std::vector honk_recursion_constraints; - size_t witness_offset = 0; SlabVector witness; for (auto& inner_circuit : inner_circuits) { @@ -151,60 +151,12 @@ class AcirHonkRecursionConstraint : public ::testing::Test { Verifier verifier(verification_key); auto inner_proof = prover.construct_proof(); - const size_t num_inner_public_inputs = inner_circuit.get_public_inputs().size(); - - std::vector proof_witnesses = inner_proof; - // where the inner public inputs start (after circuit_size, num_pub_inputs, pub_input_offset) - const size_t inner_public_input_offset = HONK_RECURSION_PUBLIC_INPUT_OFFSET; - // - Save the public inputs so that we can set their values. - // - Then truncate them from the proof because the ACIR API expects proofs without public inputs - std::vector inner_public_input_values( - proof_witnesses.begin() + static_cast(inner_public_input_offset), - proof_witnesses.begin() + - static_cast(inner_public_input_offset + num_inner_public_inputs - - bb::AGGREGATION_OBJECT_SIZE)); - - // We want to make sure that we do not remove the nested aggregation object. - proof_witnesses.erase(proof_witnesses.begin() + static_cast(inner_public_input_offset), - proof_witnesses.begin() + - static_cast(inner_public_input_offset + num_inner_public_inputs - - bb::AGGREGATION_OBJECT_SIZE)); - std::vector key_witnesses = verification_key->to_field_elements(); + std::vector proof_witnesses = inner_proof; + const size_t num_public_inputs = inner_circuit.get_public_inputs().size(); - // This is the structure of proof_witnesses and key_witnesses concatenated, which is what we end up putting - // in witness: - // [ circuit size, num_pub_inputs, pub_input_offset, public_input_0, public_input_1, agg_obj_0, - // agg_obj_1, ..., agg_obj_15, rest of proof..., vkey_0, vkey_1, vkey_2, vkey_3...] - const uint32_t public_input_start_idx = - static_cast(inner_public_input_offset + witness_offset); // points to public_input_0 - const uint32_t proof_indices_start_idx = static_cast( - public_input_start_idx + num_inner_public_inputs - bb::AGGREGATION_OBJECT_SIZE); // points to agg_obj_0 - const uint32_t key_indices_start_idx = - static_cast(proof_indices_start_idx + proof_witnesses.size() - - inner_public_input_offset); // would point to vkey_3 without the - - // inner_public_input_offset, points to vkey_0 - - std::vector proof_indices; - std::vector key_indices; - std::vector inner_public_inputs; - for (size_t i = 0; i < inner_public_input_offset; ++i) { // go over circuit size, num_pub_inputs, pub_offset - proof_indices.emplace_back(static_cast(i + witness_offset)); - } - for (size_t i = 0; i < proof_witnesses.size() - inner_public_input_offset; - ++i) { // goes over agg_obj_0, agg_obj_1, ..., agg_obj_15 and rest of proof - proof_indices.emplace_back(static_cast(i + proof_indices_start_idx)); - } - const size_t key_size = key_witnesses.size(); - for (size_t i = 0; i < key_size; ++i) { - key_indices.emplace_back(static_cast(i + key_indices_start_idx)); - } - // We keep the nested aggregation object attached to the proof, - // thus we do not explicitly have to keep the public inputs while setting up the initial recursion - // constraint. They will later be attached as public inputs when creating the circuit. - for (size_t i = 0; i < num_inner_public_inputs - bb::AGGREGATION_OBJECT_SIZE; ++i) { - inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); - } + auto [key_indices, proof_indices, inner_public_inputs] = ProofSurgeon::populate_recursion_witness_data( + witness, proof_witnesses, key_witnesses, num_public_inputs); RecursionConstraint honk_recursion_constraint{ .key = key_indices, @@ -214,40 +166,6 @@ class AcirHonkRecursionConstraint : public ::testing::Test { .proof_type = HONK_RECURSION, }; honk_recursion_constraints.push_back(honk_recursion_constraint); - - // Setting the witness vector which just appends proof witnesses and key witnesses. - // We need to reconstruct the proof witnesses in the same order as the proof indices, with this structure: - // [ circuit size, num_pub_inputs, pub_input_offset, public_input_0, public_input_1, agg_obj_0, - // agg_obj_1, ..., agg_obj_15, rest of proof..., vkey_0, vkey_1, vkey_2, vkey_3...] - size_t idx = 0; - for (const auto& wit : proof_witnesses) { - witness.emplace_back(wit); - idx++; - if (idx == - inner_public_input_offset) { // before this is true, the loop adds the first three into witness - for (size_t i = 0; i < proof_indices_start_idx - public_input_start_idx; - ++i) { // adds the inner public inputs - witness.emplace_back(0); - } - } // after this, it adds the agg obj and rest of proof - } - - for (const auto& wit : key_witnesses) { - witness.emplace_back(wit); - } - - // Set the values for the inner public inputs - // TODO(maxim): check this is wrong I think - // Note: this is confusing, but we minus one here due to the fact that the - // witness values have not taken into account that zero is taken up by the zero_idx - // - // We once again have to check whether we have a nested proof, because if we do have one - // then we could get a segmentation fault as `inner_public_inputs` was never filled with values. - for (size_t i = 0; i < num_inner_public_inputs - bb::AGGREGATION_OBJECT_SIZE; ++i) { - witness[inner_public_inputs[i]] = inner_public_input_values[i]; - } - - witness_offset = key_indices_start_idx + key_witnesses.size(); } std::vector honk_recursion_opcode_indices(honk_recursion_constraints.size()); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp new file mode 100644 index 00000000000..c4eaaefad1b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp @@ -0,0 +1,116 @@ +#pragma once +#include "barretenberg/common/serialize.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/plonk_honk_shared/types/aggregation_object_type.hpp" +#include "barretenberg/serialize/msgpack.hpp" +#include + +namespace acir_format { + +// Where the public inputs start within a proof (after circuit_size, num_pub_inputs, pub_input_offset) +static constexpr size_t HONK_RECURSION_PUBLIC_INPUT_OFFSET = 3; + +class ProofSurgeon { + public: + /** + * @brief Reconstruct a bberg style proof from a acir style proof + public inputs + * @details Insert the public inputs in the middle the proof fields after 'inner_public_input_offset' because this + * is how the core barretenberg library processes proofs (with the public inputs starting at the third element and + * not separate from the rest of the proof) + * + * @param proof_in A proof stripped of its public inputs + * @param public_inputs The public inputs to be reinserted into the proof + * @return std::vector The witness indices of the complete proof + */ + static std::vector create_indices_for_reconstructed_proof(const std::vector& proof_in, + const std::vector& public_inputs) + { + std::vector proof; + proof.reserve(proof_in.size() + public_inputs.size()); + + // Construct a the complete proof as the concatenation {"initial data" | public_inputs | proof_in} + proof.insert(proof.end(), proof_in.begin(), proof_in.begin() + HONK_RECURSION_PUBLIC_INPUT_OFFSET); + proof.insert(proof.end(), public_inputs.begin(), public_inputs.end()); + proof.insert(proof.end(), proof_in.begin() + HONK_RECURSION_PUBLIC_INPUT_OFFSET, proof_in.end()); + + return proof; + } + + /** + * @brief Extract then remove a given number of public inputs from a proof + * + * @param proof_witnesses Witness values of a bberg style proof containing public inputs + * @param num_public_inputs The number of public inputs to extract from the proof + * @return std::vector The extracted public input witness values + */ + static std::vector cut_public_inputs_from_proof(std::vector& proof_witnesses, + const size_t num_public_inputs_to_extract) + { + // Construct iterators pointing to the start and end of the public inputs within the proof + auto pub_inputs_begin_itr = + proof_witnesses.begin() + static_cast(HONK_RECURSION_PUBLIC_INPUT_OFFSET); + auto pub_inputs_end_itr = + proof_witnesses.begin() + + static_cast(HONK_RECURSION_PUBLIC_INPUT_OFFSET + num_public_inputs_to_extract); + + // Construct the isolated public inputs + std::vector public_input_witnesses{ pub_inputs_begin_itr, pub_inputs_end_itr }; + + // Erase the public inputs from the proof + proof_witnesses.erase(pub_inputs_begin_itr, pub_inputs_end_itr); + + return public_input_witnesses; + } + + struct RecursionWitnessData { + std::vector key_indices; + std::vector proof_indices; + std::vector public_inputs_indices; + }; + + /** + * @brief Populate a witness vector with key, proof, and public inputs; track witness indices for each component + * @details This method is used to constuct acir-style inputs to a recursion constraint. It is assumed that the + * provided proof contains all of its public inputs (i.e. the conventional bberg format) which are extracted herein. + * Each component is appended to the witness which may already contain data. The order in which they are added is + * arbitrary as long as the corresponding witness indices are correct. + * + * @param witness + * @param proof_witnesses + * @param key_witnesses + * @param num_public_inputs + * @return RecursionWitnessData + */ + static RecursionWitnessData populate_recursion_witness_data(bb::SlabVector& witness, + std::vector& proof_witnesses, + const std::vector& key_witnesses, + const size_t num_public_inputs) + { + // Extract all public inputs except for those corresponding to the aggregation object + const size_t num_public_inputs_to_extract = num_public_inputs - bb::AGGREGATION_OBJECT_SIZE; + std::vector public_input_witnesses = + cut_public_inputs_from_proof(proof_witnesses, num_public_inputs_to_extract); + + // Helper to append some values to the witness vector and return their corresponding indices + auto add_to_witness_and_track_indices = [](bb::SlabVector& witness, + const std::vector& input) -> std::vector { + std::vector indices; + indices.reserve(input.size()); + auto witness_idx = static_cast(witness.size()); + for (const auto& value : input) { + witness.push_back(value); + indices.push_back(witness_idx++); + } + return indices; + }; + + // Append key, proof, and public inputs while storing the associated witness indices + std::vector key_indices = add_to_witness_and_track_indices(witness, key_witnesses); + std::vector proof_indices = add_to_witness_and_track_indices(witness, proof_witnesses); + std::vector public_input_indices = add_to_witness_and_track_indices(witness, public_input_witnesses); + + return { key_indices, proof_indices, public_input_indices }; + } +}; + +} // namespace acir_format diff --git a/docker-compose.provernet.yml b/docker-compose.provernet.yml index ab9154d2c9d..7fdf67c3b6a 100644 --- a/docker-compose.provernet.yml +++ b/docker-compose.provernet.yml @@ -145,6 +145,11 @@ services: condition: service_healthy command: [ "start", "--prover" ] restart: on-failure:5 + healthcheck: + test: [ "CMD", "curl", "-fSs", "http://127.0.0.1:$AZTEC_PORT/status" ] + interval: 3s + timeout: 30s + start_period: 20s # Simple watcher that logs the latest block numbers every few seconds using the CLI and the bot's PXE aztec-block-watcher: diff --git a/l1-contracts/Dockerfile b/l1-contracts/Dockerfile index 2cfabf3ca1b..fbdf61b0e50 100644 --- a/l1-contracts/Dockerfile +++ b/l1-contracts/Dockerfile @@ -14,6 +14,10 @@ RUN foundryup --version nightly-de33b6af53005037b463318d2628b5cfcaf39916 WORKDIR /usr/src/l1-contracts COPY . . + +# Cleanup CI/CD files +RUN rm -rf terraform scripts + #RUN git init RUN forge clean && forge fmt --check && forge build && forge test --no-match-contract UniswapPortalTest diff --git a/l1-contracts/package.json b/l1-contracts/package.json new file mode 100644 index 00000000000..263d57c74d5 --- /dev/null +++ b/l1-contracts/package.json @@ -0,0 +1,15 @@ +{ + "name": "@aztec/l1-contracts", + "version": "0.1.0", + "license": "Apache-2.0", + "description": "Aztec contracts for the Ethereum mainnet and testnets", + "devDependencies": { + "solhint": "https://github.com/LHerskind/solhint#master" + }, + "scripts": { + "format": "forge fmt", + "lint": "solhint --config ./.solhint.json --fix \"src/**/*.sol\"", + "slither": "forge clean && forge build --build-info --skip '*/test/**' --force && slither . --checklist --ignore-compile --show-ignored-findings --config-file ./slither.config.json | tee slither_output.md", + "slither-has-diff": "./slither_has_diff.sh" + } +} \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_sorted_transformed_value_array/get_combined_order_hints.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_sorted_transformed_value_array/get_combined_order_hints.nr index 7b7822fa272..94ec60bbbf6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_sorted_transformed_value_array/get_combined_order_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_sorted_transformed_value_array/get_combined_order_hints.nr @@ -30,7 +30,7 @@ unconstrained fn count_private_items(array: [T; N]) -> u32 where length } -pub fn get_combined_order_hints_asc( +pub fn get_combined_order_hints_asc( array_lt: [T; N], array_gte: [T; N] ) -> [CombinedOrderHint; N] where T: Ordered + Eq + Empty { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_exposed_sorted_transformed_value_array/get_order_hints.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_exposed_sorted_transformed_value_array/get_order_hints.nr index 68b967efe2c..6bfdca7a162 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_exposed_sorted_transformed_value_array/get_order_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_exposed_sorted_transformed_value_array/get_order_hints.nr @@ -44,11 +44,11 @@ pub fn get_order_hints( hints } -pub fn get_order_hints_asc(array: [T; N]) -> [OrderHint; N] where T: Ordered + Eq + Empty { +pub fn get_order_hints_asc(array: [T; N]) -> [OrderHint; N] where T: Ordered + Eq + Empty { get_order_hints(array, compare_by_counter_empty_padded_asc) } -pub fn get_order_hints_desc(array: [T; N]) -> [OrderHint; N] where T: Ordered + Eq + Empty { +pub fn get_order_hints_desc(array: [T; N]) -> [OrderHint; N] where T: Ordered + Eq + Empty { get_order_hints(array, compare_by_counter_empty_padded_desc) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_sorted_transformed_value_arrays/get_split_order_hints.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_sorted_transformed_value_arrays/get_split_order_hints.nr index 433cfbbb1d4..f00a7650b30 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_sorted_transformed_value_arrays/get_split_order_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_sorted_transformed_value_arrays/get_split_order_hints.nr @@ -67,14 +67,14 @@ fn get_split_order_hints( SplitOrderHints { sorted_counters_lt, sorted_counters_gte, sorted_indexes } } -pub fn get_split_order_hints_asc( +pub fn get_split_order_hints_asc( array: [T; N], split_counter: u32 ) -> SplitOrderHints where T: Ordered + Eq + Empty { get_split_order_hints(array, split_counter, true) } -pub fn get_split_order_hints_desc( +pub fn get_split_order_hints_desc( array: [T; N], split_counter: u32 ) -> SplitOrderHints where T: Ordered + Eq + Empty { diff --git a/yarn-project/README.md b/yarn-project/README.md index ef499215bcc..d3da1172535 100644 --- a/yarn-project/README.md +++ b/yarn-project/README.md @@ -85,7 +85,7 @@ COMMIT_TAG= - Best to run the `deploy_package()` method line by line by manually setting `REPOSITORY` var. - Extract `VERSION` as the script shows (in the eg it should be 0.8.8) - Skip the version existing checks like `if [ "$VERSION" == "$PUBLISHED_VERSION" ]` and `if [ "$VERSION" != "$HIGHER_VERSION" ]`. Since this is our first time deploying the package, `PUBLISHED_VERSION` and `HIGHER_VERSION` will be empty and hence these checks would fail. These checks are necessary in the CI for continual releases. - - Locally update the package version in package.json using `jq` as shown in the script + - Locally update the package version in package.json using `jq` as shown in the script. - Do a dry-run - If dry run succeeds, publish the package! 5. Create a PR by adding your package into the `deploy-npm` script so next release onwards, CI can cut releases for your package. diff --git a/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts b/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts index 0a6534fae54..8fa31fd6428 100644 --- a/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts +++ b/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts @@ -1,7 +1,11 @@ import { BBNativeRollupProver, TestCircuitProver } from '@aztec/bb-prover'; import { type ServerCircuitProver } from '@aztec/circuit-types'; import { type ProverClientConfig, proverClientConfigMappings } from '@aztec/prover-client'; -import { ProverAgent, createProvingJobSourceClient } from '@aztec/prover-client/prover-agent'; +import { + ProverAgent, + createProverAgentRpcServer, + createProvingJobSourceClient, +} from '@aztec/prover-client/prover-agent'; import { type TelemetryClientConfig, createAndStartTelemetryClient, @@ -43,5 +47,5 @@ export const startProverAgent: ServiceStarter = async (options, signalHandlers, signalHandlers.push(() => agent.stop()); - return Promise.resolve([]); + return [{ prover: createProverAgentRpcServer(agent) }]; }; diff --git a/yarn-project/prover-client/src/prover-agent/prover-agent.ts b/yarn-project/prover-client/src/prover-agent/prover-agent.ts index 2dd1c5b4727..b91b4639baf 100644 --- a/yarn-project/prover-client/src/prover-agent/prover-agent.ts +++ b/yarn-project/prover-client/src/prover-agent/prover-agent.ts @@ -53,6 +53,10 @@ export class ProverAgent { return this.runningPromise?.isRunning() ?? false; } + getCurrentJobs(): { id: string; type: string }[] { + return Array.from(this.inFlightPromises.values()).map(({ id, type }) => ({ id, type: ProvingRequestType[type] })); + } + start(jobSource: ProvingJobSource): void { if (this.runningPromise) { throw new Error('Agent is already running'); @@ -139,9 +143,9 @@ export class ProverAgent { const type = ProvingRequestType[job.request.type]; if (this.isRunning()) { if (job.request.type === ProvingRequestType.PUBLIC_VM && !process.env.AVM_PROVING_STRICT) { - this.log.error(`Error processing proving job id=${job.id} type=${type}: ${err}`, err); + this.log.warn(`Expected error processing VM proving job id=${job.id} type=${type}: ${err}`); } else { - this.log.warn(`Ignoring error processing proving job id=${job.id} type=${type}: ${err}`); + this.log.error(`Error processing proving job id=${job.id} type=${type}: ${err}`, err); } await jobSource.rejectProvingJob(job.id, new ProvingError((err as any)?.message ?? String(err))); } else { diff --git a/yarn-project/prover-client/src/prover-agent/rpc.ts b/yarn-project/prover-client/src/prover-agent/rpc.ts index 8f18f7b2889..4474882f187 100644 --- a/yarn-project/prover-client/src/prover-agent/rpc.ts +++ b/yarn-project/prover-client/src/prover-agent/rpc.ts @@ -1,12 +1,14 @@ import { type ProvingJobSource } from '@aztec/circuit-types'; import { AvmCircuitInputs, + AztecAddress, BaseOrMergeRollupPublicInputs, BaseParityInputs, BaseRollupInputs, BlockMergeRollupInputs, BlockRootOrBlockMergePublicInputs, BlockRootRollupInputs, + EthAddress, Fr, Header, KernelCircuitPublicInputs, @@ -28,6 +30,7 @@ import { import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client'; import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; +import { type ProverAgent } from './prover-agent.js'; import { ProvingError } from './proving-error.js'; export function createProvingJobSourceServer(queue: ProvingJobSource): JsonRpcServer { @@ -104,3 +107,24 @@ export function createProvingJobSourceClient( fetch, ) as ProvingJobSource; } + +/** + * Wrap a ProverAgent instance with a JSON RPC HTTP server. + * @param node - The ProverNode + * @returns An JSON-RPC HTTP server + */ +export function createProverAgentRpcServer(agent: ProverAgent) { + const rpc = new JsonRpcServer( + agent, + { + AztecAddress, + EthAddress, + Fr, + Header, + }, + {}, + // disable methods + ['start', 'stop', 'setCircuitProver', 'work', 'getProof'], + ); + return rpc; +}