Skip to content
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
16 changes: 16 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,20 @@ template <typename Leaf> struct SequentialInsertHint {
MSGPACK_FIELDS(hintKey, treeId, leaf, lowLeavesWitnessData, insertionWitnessData, stateAfter);
};

// Hint for MerkleTreeDB.appendLeaves.
// Note: only supported for NOTE_HASH_TREE and L1_TO_L2_MESSAGE_TREE.
struct AppendLeavesHint {
AppendOnlyTreeSnapshot hintKey;
AppendOnlyTreeSnapshot stateAfter;
// params
world_state::MerkleTreeId treeId;
std::vector<FF> leaves;

bool operator==(const AppendLeavesHint& other) const = default;

MSGPACK_FIELDS(hintKey, stateAfter, treeId, leaves);
};

struct CheckpointActionNoStateChangeHint {
// key
uint32_t actionCounter;
Expand Down Expand Up @@ -286,6 +300,7 @@ struct ExecutionHints {
std::vector<GetLeafValueHint> getLeafValueHints;
std::vector<SequentialInsertHint<crypto::merkle_tree::PublicDataLeafValue>> sequentialInsertHintsPublicDataTree;
std::vector<SequentialInsertHint<crypto::merkle_tree::NullifierLeafValue>> sequentialInsertHintsNullifierTree;
std::vector<AppendLeavesHint> appendLeavesHints;
std::vector<CreateCheckpointHint> createCheckpointHints;
std::vector<CommitCheckpointHint> commitCheckpointHints;
std::vector<RevertCheckpointHint> revertCheckpointHints;
Expand All @@ -303,6 +318,7 @@ struct ExecutionHints {
getLeafValueHints,
sequentialInsertHintsPublicDataTree,
sequentialInsertHintsNullifierTree,
appendLeavesHints,
createCheckpointHints,
commitCheckpointHints,
revertCheckpointHints);
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ ExecutionResult Execution::execute_internal(ContextInterface& context)
// Go from a wire instruction to an execution opcode.
const WireInstructionSpec& wire_spec = instruction_info_db.get(instruction.opcode);
context.set_next_pc(pc + wire_spec.size_in_bytes);
info("@", pc, " ", instruction.to_string());
debug("@", pc, " ", instruction.to_string());
ExecutionOpCode opcode = wire_spec.exec_opcode;
ex_event.opcode = opcode;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <optional>
#include <span>

#include "barretenberg/crypto/merkle_tree/hash_path.hpp"
#include "barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp"
Expand Down Expand Up @@ -44,6 +45,7 @@ class LowLevelMerkleDBInterface {
insert_indexed_leaves_public_data_tree(const crypto::merkle_tree::PublicDataLeafValue& leaf_value) = 0;
virtual world_state::SequentialInsertionResult<crypto::merkle_tree::NullifierLeafValue>
insert_indexed_leaves_nullifier_tree(const crypto::merkle_tree::NullifierLeafValue& leaf_value) = 0;
virtual void append_leaves(world_state::MerkleTreeId tree_id, std::span<const FF> leaves) = 0;

virtual void create_checkpoint() = 0;
virtual void commit_checkpoint() = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cassert>
#include <optional>
#include <span>
#include <stdexcept>
#include <string>

Expand Down Expand Up @@ -129,6 +130,8 @@ HintedRawMerkleDB::HintedRawMerkleDB(const ExecutionHints& hints, const TreeSnap
hints.sequentialInsertHintsPublicDataTree.size(),
"\n * sequential_insert_hints_nullifier_tree: ",
hints.sequentialInsertHintsNullifierTree.size(),
"\n * append_leaves_hints: ",
hints.appendLeavesHints.size(),
"\n * create_checkpoint_hints: ",
hints.createCheckpointHints.size(),
"\n * commit_checkpoint_hints: ",
Expand Down Expand Up @@ -183,6 +186,12 @@ HintedRawMerkleDB::HintedRawMerkleDB(const ExecutionHints& hints, const TreeSnap
sequential_insert_hints_nullifier_tree[key] = sequential_insert_hint;
}

for (const auto& append_leaves_hint : hints.appendLeavesHints) {
// Convert the span from the hint to a vector for the key
AppendLeavesHintKey key = { append_leaves_hint.hintKey, append_leaves_hint.treeId, append_leaves_hint.leaves };
append_leaves_hints[key] = append_leaves_hint.stateAfter;
}

for (const auto& create_checkpoint_hint : hints.createCheckpointHints) {
create_checkpoint_hints[create_checkpoint_hint.actionCounter] = create_checkpoint_hint;
}
Expand Down Expand Up @@ -324,8 +333,7 @@ world_state::SequentialInsertionResult<crypto::merkle_tree::PublicDataLeafValue>
hint.insertionWitnessData.leaf, hint.insertionWitnessData.index, hint.insertionWitnessData.path);

// Evolve state.
tree_roots.publicDataTree.root = hint.stateAfter.root;
tree_roots.publicDataTree.nextAvailableLeafIndex = hint.stateAfter.nextAvailableLeafIndex;
tree_roots.publicDataTree = hint.stateAfter;

debug("Evolved state of PUBLIC_DATA_TREE: ",
tree_roots.publicDataTree.root,
Expand Down Expand Up @@ -364,8 +372,7 @@ world_state::SequentialInsertionResult<crypto::merkle_tree::NullifierLeafValue>
hint.insertionWitnessData.leaf, hint.insertionWitnessData.index, hint.insertionWitnessData.path);

// Evolve state.
tree_roots.nullifierTree.root = hint.stateAfter.root;
tree_roots.nullifierTree.nextAvailableLeafIndex = hint.stateAfter.nextAvailableLeafIndex;
tree_roots.nullifierTree = hint.stateAfter;

debug("Evolved state of NULLIFIER_TREE: ",
tree_roots.nullifierTree.root,
Expand Down Expand Up @@ -500,4 +507,51 @@ void HintedRawMerkleDB::revert_checkpoint()
checkpoint_action_counter++;
}

void HintedRawMerkleDB::append_leaves(world_state::MerkleTreeId tree_id, std::span<const FF> leaves)
{
if (leaves.empty()) {
return;
}

auto tree_info = get_tree_info(tree_id);
AppendLeavesHintKey key = { tree_info, tree_id, std::vector<FF>(leaves.begin(), leaves.end()) };
auto it = append_leaves_hints.find(key);
if (it == append_leaves_hints.end()) {
throw std::runtime_error(format("Append leaves hint not found for key (root: ",
tree_info.root,
", size: ",
tree_info.nextAvailableLeafIndex,
", tree_id: ",
static_cast<uint32_t>(tree_id),
", leaves: ",
leaves[0],
"..., leaves count: ",
leaves.size(),
")"));
}
const auto& stateAfter = it->second;

// Update the tree state based on the hint
switch (tree_id) {
case world_state::MerkleTreeId::NOTE_HASH_TREE:
tree_roots.noteHashTree = stateAfter;
debug("Evolved state of NOTE_HASH_TREE: ",
tree_roots.noteHashTree.root,
" (size: ",
tree_roots.noteHashTree.nextAvailableLeafIndex,
")");
break;
case world_state::MerkleTreeId::L1_TO_L2_MESSAGE_TREE:
tree_roots.l1ToL2MessageTree = stateAfter;
debug("Evolved state of L1_TO_L2_MESSAGE_TREE: ",
tree_roots.l1ToL2MessageTree.root,
" (size: ",
tree_roots.l1ToL2MessageTree.nextAvailableLeafIndex,
")");
break;
default:
throw std::runtime_error("append_leaves is only supported for NOTE_HASH_TREE and L1_TO_L2_MESSAGE_TREE");
}
}

} // namespace bb::avm2::simulation
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <span>
#include <stack>
#include <tuple>

Expand Down Expand Up @@ -57,6 +58,7 @@ class HintedRawMerkleDB final : public LowLevelMerkleDBInterface {
insert_indexed_leaves_public_data_tree(const crypto::merkle_tree::PublicDataLeafValue& leaf_value) override;
world_state::SequentialInsertionResult<crypto::merkle_tree::NullifierLeafValue>
insert_indexed_leaves_nullifier_tree(const crypto::merkle_tree::NullifierLeafValue& leaf_value) override;
void append_leaves(world_state::MerkleTreeId tree_id, std::span<const FF> leaves) override;

void create_checkpoint() override;
void commit_checkpoint() override;
Expand Down Expand Up @@ -94,6 +96,8 @@ class HintedRawMerkleDB final : public LowLevelMerkleDBInterface {
unordered_flat_map<SequentialInsertHintNullifierTreeKey,
SequentialInsertHint<crypto::merkle_tree::NullifierLeafValue>>
sequential_insert_hints_nullifier_tree;
using AppendLeavesHintKey = std::tuple<AppendOnlyTreeSnapshot, world_state::MerkleTreeId, std::vector<FF>>;
unordered_flat_map<AppendLeavesHintKey, AppendOnlyTreeSnapshot> append_leaves_hints;
unordered_flat_map</*action_counter*/ uint32_t, CreateCheckpointHint> create_checkpoint_hints;
unordered_flat_map</*action_counter*/ uint32_t, CommitCheckpointHint> commit_checkpoint_hints;
unordered_flat_map</*action_counter*/ uint32_t, RevertCheckpointHint> revert_checkpoint_hints;
Expand All @@ -102,3 +106,17 @@ class HintedRawMerkleDB final : public LowLevelMerkleDBInterface {
};

} // namespace bb::avm2::simulation

// Specialization of std::hash for std::vector<FF> to be used as a key in unordered_flat_map.
namespace std {
template <> struct hash<std::vector<bb::avm2::FF>> {
size_t operator()(const std::vector<bb::avm2::FF>& vec) const
{
size_t seed = vec.size();
for (const auto& item : vec) {
seed ^= std::hash<bb::avm2::FF>{}(item) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
} // namespace std
6 changes: 3 additions & 3 deletions barretenberg/cpp/src/barretenberg/vm2/simulation/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void Memory::set(MemoryAddress index, MemoryValue value, MemoryTag tag)
{
// TODO: validate tag-value makes sense.
memory[index] = { value, tag };
vinfo("Memory write: ", index, " <- ", value, " (tag: ", static_cast<int>(tag), ")");
debug("Memory write: ", index, " <- ", value, " (tag: ", static_cast<int>(tag), ")");
events.emit({ .mode = MemoryMode::WRITE, .addr = index, .value = value, .tag = tag, .space_id = space_id });
}

Expand All @@ -37,7 +37,7 @@ ValueRefAndTag Memory::get(MemoryAddress index) const
const auto& vt = it != memory.end() ? it->second : default_value;
events.emit({ .mode = MemoryMode::READ, .addr = index, .value = vt.value, .tag = vt.tag, .space_id = space_id });

vinfo("Memory read: ", index, " -> ", vt.value, " (tag: ", static_cast<int>(vt.tag), ")");
debug("Memory read: ", index, " -> ", vt.value, " (tag: ", static_cast<int>(vt.tag), ")");
return { vt.value, vt.tag };
}

Expand All @@ -53,4 +53,4 @@ std::pair<std::vector<MemoryValue>, std::vector<MemoryTag>> Memory::get_slice(Me
return { std::move(values), std::move(tags) };
}

} // namespace bb::avm2::simulation
} // namespace bb::avm2::simulation
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <cassert>
#include <gmock/gmock.h>
#include <optional>
#include <span>

namespace bb::avm2::simulation {

Expand Down Expand Up @@ -54,6 +55,7 @@ class MockLowLevelMerkleDB : public LowLevelMerkleDBInterface {
insert_indexed_leaves_nullifier_tree,
(const crypto::merkle_tree::NullifierLeafValue& leaf_value),
(override));
MOCK_METHOD(void, append_leaves, (world_state::MerkleTreeId tree_id, std::span<const FF> leaves), (override));
MOCK_METHOD(void, create_checkpoint, (), (override));
MOCK_METHOD(void, commit_checkpoint, (), (override));
MOCK_METHOD(void, revert_checkpoint, (), (override));
Expand Down
24 changes: 24 additions & 0 deletions yarn-project/simulator/src/public/hinting_db_sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
import type { IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
import type { FunctionSelector } from '@aztec/stdlib/abi';
import {
AvmAppendLeavesHint,
AvmBytecodeCommitmentHint,
AvmCommitCheckpointHint,
AvmContractClassHint,
Expand Down Expand Up @@ -264,6 +265,29 @@ export class HintingPublicTreesDB extends PublicTreesDB {
return result;
}

public override async appendLeaves<ID extends MerkleTreeId>(
treeId: ID,
leaves: MerkleTreeLeafType<ID>[],
): Promise<void> {
// Use sequentialInsert for PublicDataTree and NullifierTree.
assert(treeId == MerkleTreeId.NOTE_HASH_TREE || treeId == MerkleTreeId.L1_TO_L2_MESSAGE_TREE);

if (leaves.length === 0) {
return;
}

const beforeState = await this.getHintKey(treeId);

await super.appendLeaves<ID>(treeId, leaves);

const afterState = await this.getHintKey(treeId);

HintingPublicTreesDB.log.debug('[appendLeaves] Evolved tree state.');
HintingPublicTreesDB.logTreeChange(beforeState, afterState, treeId);

this.hints.appendLeavesHints.push(new AvmAppendLeavesHint(beforeState, afterState, treeId, leaves as Fr[]));
}

public override async createCheckpoint(): Promise<void> {
const actionCounter = this.checkpointActionCounter++;
const oldCheckpointId = this.getCurrentCheckpointId();
Expand Down
29 changes: 29 additions & 0 deletions yarn-project/stdlib/src/avm/avm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,31 @@ function AvmSequentialInsertHintFactory(klass: IndexedTreeLeafPreimagesClasses)
export class AvmSequentialInsertHintPublicDataTree extends AvmSequentialInsertHintFactory(PublicDataTreeLeafPreimage) {}
export class AvmSequentialInsertHintNullifierTree extends AvmSequentialInsertHintFactory(NullifierLeafPreimage) {}

// Hint for MerkleTreeDB.appendLeaves.
// Note: only supported for NOTE_HASH_TREE and L1_TO_L2_MESSAGE_TREE.
export class AvmAppendLeavesHint {
constructor(
public readonly hintKey: AppendOnlyTreeSnapshot,
public readonly stateAfter: AppendOnlyTreeSnapshot,
// params
public readonly treeId: MerkleTreeId,
public readonly leaves: Fr[],
) {}

static get schema() {
return z
.object({
hintKey: AppendOnlyTreeSnapshot.schema,
stateAfter: AppendOnlyTreeSnapshot.schema,
treeId: z.number().int().nonnegative(),
leaves: schemas.Fr.array(),
})
.transform(
({ hintKey, stateAfter, treeId, leaves }) => new AvmAppendLeavesHint(hintKey, stateAfter, treeId, leaves),
);
}
}

// Hint for checkpoint actions that don't change the state.
class AvmCheckpointActionNoStateChangeHint {
constructor(
Expand Down Expand Up @@ -497,6 +522,7 @@ export class AvmExecutionHints {
public readonly getLeafValueHints: AvmGetLeafValueHint[] = [],
public readonly sequentialInsertHintsPublicDataTree: AvmSequentialInsertHintPublicDataTree[] = [],
public readonly sequentialInsertHintsNullifierTree: AvmSequentialInsertHintNullifierTree[] = [],
public readonly appendLeavesHints: AvmAppendLeavesHint[] = [],
public readonly createCheckpointHints: AvmCreateCheckpointHint[] = [],
public readonly commitCheckpointHints: AvmCommitCheckpointHint[] = [],
public readonly revertCheckpointHints: AvmRevertCheckpointHint[] = [],
Expand All @@ -520,6 +546,7 @@ export class AvmExecutionHints {
getLeafValueHints: AvmGetLeafValueHint.schema.array(),
sequentialInsertHintsPublicDataTree: AvmSequentialInsertHintPublicDataTree.schema.array(),
sequentialInsertHintsNullifierTree: AvmSequentialInsertHintNullifierTree.schema.array(),
appendLeavesHints: AvmAppendLeavesHint.schema.array(),
createCheckpointHints: AvmCreateCheckpointHint.schema.array(),
commitCheckpointHints: AvmCommitCheckpointHint.schema.array(),
revertCheckpointHints: AvmRevertCheckpointHint.schema.array(),
Expand All @@ -537,6 +564,7 @@ export class AvmExecutionHints {
getLeafValueHints,
sequentialInsertHintsPublicDataTree,
sequentialInsertHintsNullifierTree,
appendLeavesHints,
createCheckpointHints,
commitCheckpointHints,
revertCheckpointHints,
Expand All @@ -553,6 +581,7 @@ export class AvmExecutionHints {
getLeafValueHints,
sequentialInsertHintsPublicDataTree,
sequentialInsertHintsNullifierTree,
appendLeavesHints,
createCheckpointHints,
commitCheckpointHints,
revertCheckpointHints,
Expand Down
13 changes: 13 additions & 0 deletions yarn-project/stdlib/src/tests/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { ContractStorageRead } from '../avm/contract_storage_read.js';
import { ContractStorageUpdateRequest } from '../avm/contract_storage_update_request.js';
import {
AvmAccumulatedData,
AvmAppendLeavesHint,
AvmBytecodeCommitmentHint,
AvmCircuitInputs,
AvmCircuitPublicInputs,
Expand Down Expand Up @@ -1385,6 +1386,16 @@ export function makeAvmSequentialInsertHintNullifierTree(seed = 0): AvmSequentia
);
}

export function makeAvmAppendLeavesHint(seed = 0): AvmAppendLeavesHint {
return new AvmAppendLeavesHint(
makeAppendOnlyTreeSnapshot(seed),
makeAppendOnlyTreeSnapshot(seed + 1),
// Use NOTE_HASH_TREE or L1_TO_L2_MESSAGE_TREE as mentioned in the comment on AvmAppendLeavesHint
seed % 2 === 0 ? MerkleTreeId.NOTE_HASH_TREE : MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
makeArray((seed % 5) + 1, i => new Fr(seed + i + 2), 0),
);
}

export function makeAvmCheckpointActionCreateCheckpointHint(seed = 0): AvmCreateCheckpointHint {
return new AvmCreateCheckpointHint(
/*actionCounter=*/ seed,
Expand Down Expand Up @@ -1511,6 +1522,7 @@ export async function makeAvmExecutionHints(
makeAvmSequentialInsertHintNullifierTree,
seed + 0x5700,
),
appendLeavesHints: makeArray(baseLength + 5, makeAvmAppendLeavesHint, seed + 0x5800),
createCheckpointHints: makeArray(baseLength + 5, makeAvmCheckpointActionCreateCheckpointHint, seed + 0x5900),
commitCheckpointHints: makeArray(baseLength + 5, makeAvmCheckpointActionCommitCheckpointHint, seed + 0x5b00),
revertCheckpointHints: makeArray(baseLength + 5, makeAvmCheckpointActionRevertCheckpointHint, seed + 0x5d00),
Expand All @@ -1529,6 +1541,7 @@ export async function makeAvmExecutionHints(
fields.getLeafValueHints,
fields.sequentialInsertHintsPublicDataTree,
fields.sequentialInsertHintsNullifierTree,
fields.appendLeavesHints,
fields.createCheckpointHints,
fields.commitCheckpointHints,
fields.revertCheckpointHints,
Expand Down