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): plumb start side effect counter in circuit #7007

Merged
merged 1 commit into from
Jun 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 @@ -116,7 +116,7 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
*/
VmPublicInputs Execution::convert_public_inputs(std::vector<FF> const& public_inputs_vec)
{
VmPublicInputs public_inputs = {};
VmPublicInputs public_inputs;

// Case where we pass in empty public inputs - this will be used in tests where they are not required
if (public_inputs_vec.empty()) {
Expand Down Expand Up @@ -306,7 +306,10 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/6718): construction of the public input columns
// should be done in the kernel - this is stubbed and underconstrained
VmPublicInputs public_inputs = convert_public_inputs(public_inputs_vec);
AvmTraceBuilder trace_builder(public_inputs, execution_hints);
uint32_t start_side_effect_counter =
!public_inputs_vec.empty() ? static_cast<uint32_t>(public_inputs_vec[PCPI_START_SIDE_EFFECT_COUNTER_OFFSET])
: 0;
AvmTraceBuilder trace_builder(public_inputs, execution_hints, start_side_effect_counter);

// Copied version of pc maintained in trace builder. The value of pc is evolving based
// on opcode logic and therefore is not maintained here. However, the next opcode in the execution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace bb::avm_trace {

AvmKernelTraceBuilder::AvmKernelTraceBuilder(VmPublicInputs public_inputs)
: public_inputs(public_inputs)
: public_inputs(std::move(public_inputs))
{}

void AvmKernelTraceBuilder::reset()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class AvmKernelTraceBuilder {
bool op_sstore = false;
};

VmPublicInputs public_inputs{};
VmPublicInputs public_inputs;

// Counts the number of accesses into each SELECTOR for the environment selector lookups;
std::unordered_map<uint32_t, uint32_t> kernel_input_selector_counter;
Expand Down
14 changes: 9 additions & 5 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ namespace bb::avm_trace {
* @brief Constructor of a trace builder of AVM. Only serves to set the capacity of the
* underlying traces and initialize gas values.
*/
AvmTraceBuilder::AvmTraceBuilder(VmPublicInputs public_inputs, ExecutionHints execution_hints)
AvmTraceBuilder::AvmTraceBuilder(VmPublicInputs public_inputs,
ExecutionHints execution_hints,
uint32_t side_effect_counter)
// NOTE: we initialise the environment builder here as it requires public inputs
: kernel_trace_builder(public_inputs)
, execution_hints(execution_hints)
: kernel_trace_builder(std::move(public_inputs))
, side_effect_counter(side_effect_counter)
, execution_hints(std::move(execution_hints))
Comment on lines -29 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ordering of member initializations does not match ordering of constructor args

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it complained when I changed it! We'll see.

{
main_trace.reserve(AVM_TRACE_SIZE);

Expand Down Expand Up @@ -1643,11 +1646,12 @@ void AvmTraceBuilder::op_note_hash_exists(uint8_t indirect, uint32_t note_offset
side_effect_counter++;
}

void AvmTraceBuilder::op_nullifier_exists(uint8_t indirect, uint32_t note_offset, uint32_t dest_offset)
void AvmTraceBuilder::op_nullifier_exists(uint8_t indirect, uint32_t nullifier_offset, uint32_t dest_offset)
{
auto const clk = static_cast<uint32_t>(main_trace.size()) + 1;

Row row = create_kernel_output_opcode_with_set_metadata_output_from_hint(indirect, clk, note_offset, dest_offset);
Row row =
create_kernel_output_opcode_with_set_metadata_output_from_hint(indirect, clk, nullifier_offset, dest_offset);
kernel_trace_builder.op_nullifier_exists(
clk, side_effect_counter, row.avm_main_ia, /*safe*/ static_cast<uint32_t>(row.avm_main_ib));
row.avm_main_sel_op_nullifier_exists = FF(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ using Row = bb::AvmFullRow<bb::fr>;
class AvmTraceBuilder {

public:
AvmTraceBuilder(VmPublicInputs public_inputs = {}, ExecutionHints execution_hints = {});
AvmTraceBuilder(VmPublicInputs public_inputs = {},
ExecutionHints execution_hints = {},
uint32_t side_effect_counter = 0);

std::vector<Row> finalize(uint32_t min_trace_size = 0, bool range_check_required = false);
void reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ inline const uint32_t PCPI_NEW_NULLIFIERS_OFFSET =
inline const uint32_t PCPI_NEW_L2_TO_L1_MSGS_OFFSET =
PCPI_NEW_NULLIFIERS_OFFSET + (MAX_NEW_NULLIFIERS_PER_CALL * NULLIFIER_LENGTH);

inline const uint32_t PCPI_NEW_UNENCRYPTED_LOGS_OFFSET /*2 item gap*/ =
PCPI_NEW_L2_TO_L1_MSGS_OFFSET + (MAX_NEW_L2_TO_L1_MSGS_PER_CALL * L2_TO_L1_MESSAGE_LENGTH) + 2;
inline const uint32_t PCPI_START_SIDE_EFFECT_COUNTER_OFFSET =
PCPI_NEW_L2_TO_L1_MSGS_OFFSET + (MAX_NEW_L2_TO_L1_MSGS_PER_CALL * L2_TO_L1_MESSAGE_LENGTH);

inline const uint32_t PCPI_NEW_UNENCRYPTED_LOGS_OFFSET = PCPI_START_SIDE_EFFECT_COUNTER_OFFSET + /*1 item gap*/ 1;
Comment on lines -70 to +73
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This offset thing is so bad 😅 we need to figure out a proper way to do this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed


// END INDEXES in the PUBLIC_CIRCUIT_PUBLIC_INPUTS

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { Fr } from '@aztec/circuits.js';
import { makePublicKernelCircuitPublicInputs } from '@aztec/circuits.js/testing';

import { lastSideEffectCounter } from './utils.js';
import { AbstractPhaseManager } from './abstract_phase_manager.js';

describe('sequencer utils', () => {
describe('lastSideEffectCounter', () => {
describe('AbstractPhaseManager utils', () => {
describe('getMaxSideEffectCounter', () => {
it('correctly identifies the highest side effect counter in a transaction', () => {
const inputs = makePublicKernelCircuitPublicInputs();

const startingCounter = lastSideEffectCounter(inputs);
const startingCounter = AbstractPhaseManager.getMaxSideEffectCounter(inputs);

inputs.endNonRevertibleData.newNoteHashes.at(-1)!.counter = startingCounter + 1;
expect(lastSideEffectCounter(inputs)).toBe(startingCounter + 1);
expect(AbstractPhaseManager.getMaxSideEffectCounter(inputs)).toBe(startingCounter + 1);

inputs.endNonRevertibleData.publicCallStack.at(-1)!.startSideEffectCounter = new Fr(startingCounter + 2);
expect(lastSideEffectCounter(inputs)).toBe(startingCounter + 2);
expect(AbstractPhaseManager.getMaxSideEffectCounter(inputs)).toBe(startingCounter + 2);

inputs.end.newNoteHashes.at(-1)!.counter = startingCounter + 3;
expect(lastSideEffectCounter(inputs)).toBe(startingCounter + 3);
expect(AbstractPhaseManager.getMaxSideEffectCounter(inputs)).toBe(startingCounter + 3);

inputs.end.newNullifiers.at(-1)!.counter = startingCounter + 4;
expect(lastSideEffectCounter(inputs)).toBe(startingCounter + 4);
expect(AbstractPhaseManager.getMaxSideEffectCounter(inputs)).toBe(startingCounter + 4);
});
});
});
49 changes: 41 additions & 8 deletions yarn-project/simulator/src/public/abstract_phase_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import { type MerkleTreeOperations } from '@aztec/world-state';

import { HintsBuilder } from './hints_builder.js';
import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js';
import { lastSideEffectCounter } from './utils.js';

export const PhaseIsRevertible: Record<PublicKernelType, boolean> = {
[PublicKernelType.NON_PUBLIC]: false,
Expand Down Expand Up @@ -263,19 +262,15 @@ export abstract class AbstractPhaseManager {
while (executionStack.length) {
const current = executionStack.pop()!;
const isExecutionRequest = !isPublicExecutionResult(current);
const sideEffectCounter = lastSideEffectCounter(kernelPublicOutput) + 1;
const availableGas = this.getAvailableGas(tx, kernelPublicOutput);
const pendingNullifiers = this.getSiloedPendingNullifiers(kernelPublicOutput);

const result = isExecutionRequest
? await this.publicExecutor.simulate(
current,
this.globalVariables,
availableGas,
/*availableGas=*/ this.getAvailableGas(tx, kernelPublicOutput),
tx.data.constants.txContext,
pendingNullifiers,
/*pendingNullifiers=*/ this.getSiloedPendingNullifiers(kernelPublicOutput),
transactionFee,
sideEffectCounter,
/*startSideEffectCounter=*/ AbstractPhaseManager.getMaxSideEffectCounter(kernelPublicOutput) + 1,
)
: current;

Expand Down Expand Up @@ -493,6 +488,44 @@ export abstract class AbstractPhaseManager {
return await Promise.all(nested.map(n => this.getPublicCallStackItem(n)));
}

/**
* Looks at the side effects of a transaction and returns the highest counter
* @param tx - A transaction
* @returns The highest side effect counter in the transaction so far
*/
static getMaxSideEffectCounter(inputs: PublicKernelCircuitPublicInputs): number {
const sideEffectCounters = [
...inputs.endNonRevertibleData.newNoteHashes,
...inputs.endNonRevertibleData.newNullifiers,
...inputs.endNonRevertibleData.noteEncryptedLogsHashes,
...inputs.endNonRevertibleData.encryptedLogsHashes,
...inputs.endNonRevertibleData.unencryptedLogsHashes,
...inputs.endNonRevertibleData.publicCallStack,
...inputs.endNonRevertibleData.publicDataUpdateRequests,
...inputs.end.newNoteHashes,
...inputs.end.newNullifiers,
...inputs.end.noteEncryptedLogsHashes,
...inputs.end.encryptedLogsHashes,
...inputs.end.unencryptedLogsHashes,
...inputs.end.publicCallStack,
...inputs.end.publicDataUpdateRequests,
];

let max = 0;
for (const sideEffect of sideEffectCounters) {
if ('startSideEffectCounter' in sideEffect) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a more robust way to perform this filtering by not using a string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is old code. This is actually testing that sideEffect. startSideEffectCounter exists, which is only in publicCallStack I think. I'm afraid to touch it and break it ;)

// look at both start and end counters because for enqueued public calls start > 0 while end === 0
max = Math.max(max, sideEffect.startSideEffectCounter.toNumber(), sideEffect.endSideEffectCounter.toNumber());
} else if ('counter' in sideEffect) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

max = Math.max(max, sideEffect.counter);
} else {
throw new Error('Unknown side effect type');
}
}

return max;
}

protected getBytecodeHash(_result: PublicExecutionResult) {
// TODO: Determine how to calculate bytecode hash. Circuits just check it isn't zero for now.
// See https://github.com/AztecProtocol/aztec3-packages/issues/378
Expand Down
6 changes: 2 additions & 4 deletions yarn-project/simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class PublicExecutor {
txContext: TxContext,
pendingNullifiers: Nullifier[],
transactionFee: Fr = Fr.ZERO,
sideEffectCounter: number = 0,
startSideEffectCounter: number = 0,
): Promise<PublicExecutionResult> {
const address = execution.contractAddress;
const selector = execution.functionSelector;
Expand All @@ -52,13 +52,11 @@ export class PublicExecutor {
// These data structures will permeate across the simulator when the public executor is phased out
const hostStorage = new HostStorage(this.stateDb, this.contractsDb, this.commitmentsDb);

const startSideEffectCounter = sideEffectCounter;
const worldStateJournal = new AvmPersistableStateManager(hostStorage);
for (const nullifier of pendingNullifiers) {
worldStateJournal.nullifiers.cache.appendSiloed(nullifier.value);
}
// All the subsequent side effects will have a counter larger than the call's start counter.
worldStateJournal.trace.accessCounter = startSideEffectCounter + 1;
worldStateJournal.trace.accessCounter = startSideEffectCounter;

const executionEnv = createAvmExecutionEnvironment(
execution,
Expand Down
39 changes: 0 additions & 39 deletions yarn-project/simulator/src/public/utils.ts

This file was deleted.

Loading