Skip to content

Commit

Permalink
feat: AVM inserts fee write on txs with public calls (#10394)
Browse files Browse the repository at this point in the history
Co-authored-by: dbanks12 <[email protected]>
  • Loading branch information
2 people authored and lucasxia01 committed Dec 11, 2024
1 parent db37318 commit 225cda6
Show file tree
Hide file tree
Showing 39 changed files with 398 additions and 631 deletions.
9 changes: 8 additions & 1 deletion barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp
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 @@ -2535,6 +2594,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

0 comments on commit 225cda6

Please sign in to comment.