Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bytecode_manager.test.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
6#include <memory>
7#include <optional>
8#include <vector>
9
19
20using ::testing::_;
21using ::testing::Return;
22using ::testing::SizeIs;
23using ::testing::StrictMock;
24
25namespace bb::avm2::simulation {
26
27namespace {
28
29// Simple mock for ContractInstanceManagerInterface
30class MockContractInstanceManager : public ContractInstanceManagerInterface {
31 public:
32 MOCK_METHOD(std::optional<ContractInstance>, get_contract_instance, (const FF& contract_address), (override));
33};
34
35class BytecodeManagerTest : public ::testing::Test {
36 protected:
37 BytecodeManagerTest()
39 {}
40
41 StrictMock<MockContractDB> contract_db;
42 StrictMock<MockHighLevelMerkleDB> merkle_db;
43 StrictMock<MockPoseidon2> poseidon2;
44 StrictMock<MockRangeCheck> range_check;
45 StrictMock<MockContractInstanceManager> contract_instance_manager;
46
47 EventEmitter<BytecodeRetrievalEvent> retrieval_events;
48 EventEmitter<BytecodeDecompositionEvent> decomposition_events;
49 EventEmitter<InstructionFetchingEvent> instruction_fetching_events;
50 EventEmitter<BytecodeHashingEvent> hashing_events;
51 BytecodeHasher bytecode_hasher;
52};
53
54TEST_F(BytecodeManagerTest, RetrievalAndDeduplication)
55{
56 TxBytecodeManager tx_bytecode_manager(contract_db,
64
65 // Setup for base case
66 AztecAddress address1 = AztecAddress::random_element();
67 ContractInstance instance1 = testing::random_contract_instance();
68 ContractClass klass = testing::random_contract_class();
69
70 // Expected interactions for first retrieval
71 EXPECT_CALL(contract_instance_manager, get_contract_instance(address1))
72 .WillOnce(Return(std::make_optional(instance1)));
73
74 EXPECT_CALL(contract_db, get_contract_class(instance1.current_class_id))
75 .WillOnce(Return(std::make_optional(klass)));
76
77 // Let the real bytecode hasher run - it will emit hashing events
78 EXPECT_CALL(poseidon2, hash(_)).WillOnce(Return(klass.public_bytecode_commitment));
79
80 TreeStates tree_states = {};
81 EXPECT_CALL(merkle_db, get_tree_state()).WillOnce(Return(tree_states));
82
83 // Base case: First retrieval - should do full processing
84 BytecodeId result1 = tx_bytecode_manager.get_bytecode(address1);
85 EXPECT_EQ(result1, klass.public_bytecode_commitment);
86
87 // Verify events after first retrieval
88 // Verify retrieval events - should have exactly one retrieval event total
89 auto retrieval_events_dump = retrieval_events.dump_events();
90 EXPECT_THAT(retrieval_events_dump, SizeIs(1));
91 EXPECT_EQ(retrieval_events_dump[0].address, address1);
92 EXPECT_EQ(retrieval_events_dump[0].bytecode_id, klass.public_bytecode_commitment);
93 EXPECT_FALSE(retrieval_events_dump[0].error);
94 // Verify hashing events - should have exactly one hashing event total
95 // TODO(dbanks12): re-enable once C++ and PIL use standard poseidon2 hashing for bytecode commitments.
96 // auto hashing_events_dump = hashing_events.dump_events();
97 // EXPECT_THAT(hashing_events_dump, SizeIs(1));
98 // EXPECT_EQ(hashing_events_dump[0].bytecode_id, klass.public_bytecode_commitment);
99 // Verify decomposition events - should have exactly one decomposition event total
100 auto decomposition_events_dump = decomposition_events.dump_events();
101 EXPECT_THAT(decomposition_events_dump, SizeIs(1));
102 EXPECT_EQ(decomposition_events_dump[0].bytecode_id, klass.public_bytecode_commitment);
103
104 // Deduplication case 1: Same address retrieval
105 // Expected interactions for second retrieval of same address
106 EXPECT_CALL(contract_instance_manager, get_contract_instance(address1))
107 .WillOnce(Return(std::make_optional(instance1)));
108 EXPECT_CALL(contract_db, get_contract_class(instance1.current_class_id))
109 .WillOnce(Return(std::make_optional(klass)));
110 // No hashing should occur for duplicate retrieval
111 EXPECT_CALL(merkle_db, get_tree_state()).WillOnce(Return(tree_states));
112
113 // Second retrieval of same address - should be deduplicated
114 BytecodeId result2 = tx_bytecode_manager.get_bytecode(address1);
115 EXPECT_EQ(result2, klass.public_bytecode_commitment);
116
117 // Verify events after second retrieval - retrieval event emitted, but no hashing or decomposition
118 retrieval_events_dump = retrieval_events.dump_events();
119 EXPECT_THAT(retrieval_events_dump, SizeIs(1));
120 EXPECT_EQ(retrieval_events_dump[0].address, address1);
121 EXPECT_EQ(retrieval_events_dump[0].bytecode_id, klass.public_bytecode_commitment);
122 auto hashing_events_dump = hashing_events.dump_events();
123 EXPECT_THAT(hashing_events_dump, SizeIs(0)); // No hashing for deduplicated bytecode
124 decomposition_events_dump = decomposition_events.dump_events();
125 EXPECT_THAT(decomposition_events_dump, SizeIs(0)); // No decomposition for deduplicated retrieval
126
127 // Deduplication case 2: Different address with same bytecode
128 AztecAddress address2 = address1 + 1; // force a different address
129 ContractInstance instance2 = testing::random_contract_instance();
130 instance2.current_class_id = instance1.current_class_id + 1; // force a different class id
131
132 // Expected interactions for different address with same bytecode
133 EXPECT_CALL(contract_instance_manager, get_contract_instance(address2))
134 .WillOnce(Return(std::make_optional(instance2)));
135 EXPECT_CALL(contract_db, get_contract_class(instance2.current_class_id))
136 .WillOnce(Return(std::make_optional(klass))); // Same class/bytecode
137 // No hashing should occur since we've already processed this bytecode
138 EXPECT_CALL(merkle_db, get_tree_state()).WillOnce(Return(tree_states));
139
140 // Third retrieval with different address but same bytecode - should be deduplicated
141 BytecodeId result3 = tx_bytecode_manager.get_bytecode(address2);
142 EXPECT_EQ(result3, klass.public_bytecode_commitment);
143
144 // Verify events after third retrieval - retrieval event emitted, but no hashing or decomposition
145 retrieval_events_dump = retrieval_events.dump_events();
146 EXPECT_THAT(retrieval_events_dump, SizeIs(1));
147 EXPECT_EQ(retrieval_events_dump[0].address, address2);
148 EXPECT_EQ(retrieval_events_dump[0].bytecode_id, klass.public_bytecode_commitment);
149 hashing_events_dump = hashing_events.dump_events();
150 EXPECT_THAT(hashing_events_dump, SizeIs(0)); // No hashing for deduplicated bytecode
151 decomposition_events_dump = decomposition_events.dump_events();
152 EXPECT_THAT(decomposition_events_dump, SizeIs(0)); // No decomposition for deduplicated bytecode
153}
154
155} // namespace
156} // namespace bb::avm2::simulation
EventEmitter< BytecodeDecompositionEvent > decomposition_events
StrictMock< MockHighLevelMerkleDB > merkle_db
EventEmitter< InstructionFetchingEvent > instruction_fetching_events
EventEmitter< BytecodeRetrievalEvent > retrieval_events
BytecodeHasher bytecode_hasher
StrictMock< MockContractDB > contract_db
StrictMock< MockContractInstanceManager > contract_instance_manager
EventEmitter< BytecodeHashingEvent > hashing_events
RangeCheck range_check
void hash(State &state) noexcept
ContractClass random_contract_class(size_t bytecode_size)
Definition fixtures.cpp:174
ContractInstance random_contract_instance()
Definition fixtures.cpp:158
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:123
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13