Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: AVM inserts fee write on txs with public calls #10394

Merged
merged 22 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_map>
Expand Down Expand Up @@ -377,10 +378,16 @@ std::vector<Row> Execution::gen_trace(AvmPublicInputs const& public_inputs,

if (!is_ok(phase_error) && phase == TxExecutionPhase::SETUP) {
// Stop processing phases. Halt TX.
info("A revert during SETUP phase halts the entire TX");
info("A revert was encountered in the SETUP phase, killing the entire TX");
throw std::runtime_error("A revert was encountered in the SETUP phase, killing the entire TX");
break;
}
}

if (apply_e2e_assertions) {
trace_builder.pay_fee();
}

auto trace = trace_builder.finalize(apply_e2e_assertions);

returndata = trace_builder.get_all_returndata();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ class AvmPublicInputs {
TreeSnapshots start_tree_snapshots;
Gas start_gas_used;
GasSettings gas_settings;
FF fee_payer;
std::array<PublicCallRequest, MAX_ENQUEUED_CALLS_PER_TX> public_setup_call_requests;
std::array<PublicCallRequest, MAX_ENQUEUED_CALLS_PER_TX> public_app_logic_call_requests;
PublicCallRequest public_teardown_call_request;
Expand All @@ -330,6 +331,7 @@ class AvmPublicInputs {
read(it, public_inputs.start_tree_snapshots);
read(it, public_inputs.start_gas_used);
read(it, public_inputs.gas_settings);
read(it, public_inputs.fee_payer);
read(it, public_inputs.public_setup_call_requests);
read(it, public_inputs.public_app_logic_call_requests);
read(it, public_inputs.public_teardown_call_request);
Expand Down
62 changes: 62 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <iostream>
#include <limits>
#include <set>
#include <stdexcept>
#include <string>
#include <sys/types.h>
#include <unordered_map>
Expand All @@ -32,6 +33,7 @@
#include "barretenberg/vm/avm/trace/gadgets/cmp.hpp"
#include "barretenberg/vm/avm/trace/gadgets/keccak.hpp"
#include "barretenberg/vm/avm/trace/gadgets/merkle_tree.hpp"
#include "barretenberg/vm/avm/trace/gadgets/poseidon2.hpp"
#include "barretenberg/vm/avm/trace/gadgets/slice_trace.hpp"
#include "barretenberg/vm/avm/trace/helper.hpp"
#include "barretenberg/vm/avm/trace/opcode.hpp"
Expand Down Expand Up @@ -225,6 +227,63 @@ void AvmTraceBuilder::insert_private_state(const std::vector<FF>& siloed_nullifi
}
}

void AvmTraceBuilder::pay_fee()
{
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;

auto tx_fee = (public_inputs.global_variables.gas_fees.fee_per_da_gas * public_inputs.end_gas_used.da_gas) +
(public_inputs.global_variables.gas_fees.fee_per_l2_gas * public_inputs.end_gas_used.l2_gas);

if (public_inputs.fee_payer == 0) {
vinfo("No one is paying the fee of ", tx_fee);
return;
}

// ** Compute the storage slot **
// using the base slot of the balances map and the fee payer address (map key)
// TS equivalent:
// computeFeePayerBalanceStorageSlot(fee_payer);
std::vector<FF> slot_hash_inputs = { FEE_JUICE_BALANCES_SLOT, public_inputs.fee_payer };
const auto balance_slot = poseidon2_trace_builder.poseidon2_hash(slot_hash_inputs, clk, Poseidon2Caller::SILO);

// ** Read the balance before fee payment **
// TS equivalent:
// current_balance = readStorage(FEE_JUICE_ADDRESS, balance_slot);
PublicDataReadTreeHint read_hint = execution_hints.storage_read_hints.at(storage_read_counter++);
FF computed_tree_slot =
merkle_tree_trace_builder.compute_public_tree_leaf_slot(clk, FEE_JUICE_ADDRESS, balance_slot);
// Sanity check that the computed slot using the value read from slot_offset should match the read hint
ASSERT(computed_tree_slot == read_hint.leaf_preimage.slot);

// ** Write the updated balance after fee payment **
// TS equivalent:
// Check that the leaf is a member of the public data tree
bool is_member = merkle_tree_trace_builder.perform_storage_read(
clk, read_hint.leaf_preimage, read_hint.leaf_index, read_hint.sibling_path);
ASSERT(is_member);
FF current_balance = read_hint.leaf_preimage.value;

const auto updated_balance = current_balance - tx_fee;
if (current_balance < tx_fee) {
info("Not enough balance for fee payer to pay for transaction (got ", current_balance, " needs ", tx_fee);
throw std::runtime_error("Not enough balance for fee payer to pay for transaction");
}

// writeStorage(FEE_JUICE_ADDRESS, balance_slot, updated_balance);
PublicDataWriteTreeHint write_hint = execution_hints.storage_write_hints.at(storage_write_counter++);
ASSERT(write_hint.new_leaf_preimage.value == updated_balance);
merkle_tree_trace_builder.perform_storage_write(clk,
write_hint.low_leaf_membership.leaf_preimage,
write_hint.low_leaf_membership.leaf_index,
write_hint.low_leaf_membership.sibling_path,
write_hint.new_leaf_preimage.slot,
write_hint.new_leaf_preimage.value,
write_hint.insertion_path);

debug("pay fee side-effect cnt: ", side_effect_counter);
side_effect_counter++;
}

/**
* @brief Loads a value from memory into a given intermediate register at a specified clock cycle.
* Handles both direct and indirect memory access.
Expand Down Expand Up @@ -2528,6 +2587,9 @@ AvmError AvmTraceBuilder::op_sstore(uint8_t indirect, uint32_t src_offset, uint3
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;

if (storage_write_counter >= MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX) {
// NOTE: the circuit constraint for this limit should only be applied
// for the storage writes performed by this opcode. An exception should before
// made for the fee juice storage write made after teardown.
error = AvmError::SIDE_EFFECT_LIMIT_REACHED;
auto row = Row{
.main_clk = clk,
Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class AvmTraceBuilder {
std::vector<uint8_t> get_bytecode(const FF contract_address, bool check_membership = false);
std::unordered_set<FF> bytecode_membership_cache;
void insert_private_state(const std::vector<FF>& siloed_nullifiers, const std::vector<FF>& siloed_note_hashes);
void pay_fee();

// These are used for testing only.
AvmTraceBuilder& set_range_check_required(bool required)
Expand Down
5 changes: 3 additions & 2 deletions barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define MULTI_CALL_ENTRYPOINT_ADDRESS 4
#define FEE_JUICE_ADDRESS 5
#define ROUTER_ADDRESS 6
#define FEE_JUICE_BALANCES_SLOT 1
#define AZTEC_ADDRESS_LENGTH 1
#define GAS_FEES_LENGTH 2
#define GAS_LENGTH 2
Expand All @@ -45,8 +46,8 @@
#define STATE_REFERENCE_LENGTH 8
#define TOTAL_FEES_LENGTH 1
#define PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH 867
#define AVM_ACCUMULATED_DATA_LENGTH 318
#define AVM_CIRCUIT_PUBLIC_INPUTS_LENGTH 1006
#define AVM_ACCUMULATED_DATA_LENGTH 320
#define AVM_CIRCUIT_PUBLIC_INPUTS_LENGTH 1008
#define AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS 86
#define AVM_PROOF_LENGTH_IN_FIELDS 4155
#define AVM_PUBLIC_COLUMN_MAX_SIZE 1024
Expand Down
5 changes: 3 additions & 2 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ library Constants {
uint256 internal constant MULTI_CALL_ENTRYPOINT_ADDRESS = 4;
uint256 internal constant FEE_JUICE_ADDRESS = 5;
uint256 internal constant ROUTER_ADDRESS = 6;
uint256 internal constant FEE_JUICE_BALANCES_SLOT = 1;
uint256 internal constant DEFAULT_NPK_M_X =
582240093077765400562621227108555700500271598878376310175765873770292988861;
uint256 internal constant DEFAULT_NPK_M_Y =
Expand Down Expand Up @@ -208,7 +209,7 @@ library Constants {
uint256 internal constant SCOPED_READ_REQUEST_LEN = 3;
uint256 internal constant PUBLIC_DATA_READ_LENGTH = 3;
uint256 internal constant PRIVATE_VALIDATION_REQUESTS_LENGTH = 772;
uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 900;
uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 902;
uint256 internal constant TX_CONSTANT_DATA_LENGTH = 35;
uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = 44;
uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = 1412;
Expand All @@ -217,7 +218,7 @@ library Constants {
uint256 internal constant PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160;
uint256 internal constant NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3;
uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1845;
uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 956;
uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 958;
uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 13;
uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 31;
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 90;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@ pub(crate) global MERGE_ROLLUP_TYPE: u32 = 1;
pub struct BaseOrMergeRollupPublicInputs {
// rollup_type is either 0 (base) or 1 (merge)
// TODO(Kev): Why is this a u32 instead of a u8/u16?
pub rollup_type: u32,
pub num_txs: u32,
pub constants: ConstantRollupData,
pub(crate) rollup_type: u32,
pub(crate) num_txs: u32,
pub(crate) constants: ConstantRollupData,

pub start: PartialStateReference,
pub end: PartialStateReference,
pub(crate) start: PartialStateReference,
pub(crate) end: PartialStateReference,

// We hash public inputs to make them constant-sized (to then be unpacked on-chain)
// U128 isn't safe if it's an input to the circuit (it won't automatically constrain the witness)
// So we want to constrain it when casting these fields to U128

// We hash public inputs to make them constant-sized (to then be unpacked on-chain)
pub txs_effects_hash: Field,
pub out_hash: Field,
pub(crate) txs_effects_hash: Field,
pub(crate) out_hash: Field,

pub accumulated_fees: Field,
pub accumulated_mana_used: Field,
pub(crate) accumulated_fees: Field,
pub(crate) accumulated_mana_used: Field,
}

impl Empty for BaseOrMergeRollupPublicInputs {
Expand Down
Loading
Loading