Skip to content

Commit 4753196

Browse files
author
dbanks12
committed
feat!: getcontractinstance instruction returns only a specified member
1 parent 419642b commit 4753196

25 files changed

Lines changed: 392 additions & 283 deletions

File tree

avm-transpiler/src/transpile.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,6 @@ fn handle_foreign_call(
423423
"avmOpcodeNullifierExists" => handle_nullifier_exists(avm_instrs, destinations, inputs),
424424
"avmOpcodeL1ToL2MsgExists" => handle_l1_to_l2_msg_exists(avm_instrs, destinations, inputs),
425425
"avmOpcodeSendL2ToL1Msg" => handle_send_l2_to_l1_msg(avm_instrs, destinations, inputs),
426-
"avmOpcodeGetContractInstance" => {
427-
handle_get_contract_instance(avm_instrs, destinations, inputs);
428-
}
429426
"avmOpcodeCalldataCopy" => handle_calldata_copy(avm_instrs, destinations, inputs),
430427
"avmOpcodeReturn" => handle_return(avm_instrs, destinations, inputs),
431428
"avmOpcodeStorageRead" => handle_storage_read(avm_instrs, destinations, inputs),
@@ -435,6 +432,11 @@ fn handle_foreign_call(
435432
_ if inputs.is_empty() && destinations.len() == 1 => {
436433
handle_getter_instruction(avm_instrs, function, destinations, inputs);
437434
}
435+
// Get contract instance variations.
436+
// TODO(dbanks12): pattern match instead
437+
_ if inputs.len() == 1 && destinations.len() == 2 => {
438+
handle_get_contract_instance(avm_instrs, function, destinations, inputs);
439+
}
438440
// Anything else.
439441
_ => panic!("Transpiler doesn't know how to process ForeignCall function {}", function),
440442
}
@@ -1288,35 +1290,58 @@ fn handle_storage_write(
12881290
/// Emit a GETCONTRACTINSTANCE opcode
12891291
fn handle_get_contract_instance(
12901292
avm_instrs: &mut Vec<AvmInstruction>,
1293+
function: &str,
12911294
destinations: &Vec<ValueOrArray>,
12921295
inputs: &Vec<ValueOrArray>,
12931296
) {
1297+
enum ContractInstanceMember {
1298+
DEPLOYER,
1299+
CLASS_ID,
1300+
INIT_HASH,
1301+
}
1302+
12941303
assert!(inputs.len() == 1);
1295-
assert!(destinations.len() == 1);
1304+
assert!(destinations.len() == 2);
1305+
1306+
let member_idx = match function {
1307+
"avmOpcodeGetContractInstanceDeployer" => ContractInstanceMember::DEPLOYER,
1308+
"avmOpcodeGetContractInstanceClassId" => ContractInstanceMember::CLASS_ID,
1309+
"avmOpcodeGetContractInstanceInitializationHash" => ContractInstanceMember::INIT_HASH,
1310+
_ => panic!("Transpiler doesn't know how to process function {:?}", function),
1311+
};
12961312

12971313
let address_offset_maybe = inputs[0];
12981314
let address_offset = match address_offset_maybe {
1299-
ValueOrArray::MemoryAddress(slot_offset) => slot_offset,
1315+
ValueOrArray::MemoryAddress(offset) => offset,
13001316
_ => panic!("GETCONTRACTINSTANCE address should be a single value"),
13011317
};
13021318

13031319
let dest_offset_maybe = destinations[0];
13041320
let dest_offset = match dest_offset_maybe {
1305-
ValueOrArray::HeapArray(HeapArray { pointer, .. }) => pointer,
1306-
_ => panic!("GETCONTRACTINSTANCE destination should be an array"),
1321+
ValueOrArray::MemoryAddress(offset) => offset,
1322+
_ => panic!("GETCONTRACTINSTANCE dst destination should be a single value"),
1323+
};
1324+
1325+
let exists_offset_maybe = destinations[1];
1326+
let exists_offset = match exists_offset_maybe {
1327+
ValueOrArray::MemoryAddress(offset) => offset,
1328+
_ => panic!("GETCONTRACTINSTANCE exists destination should be a single value"),
13071329
};
13081330

13091331
avm_instrs.push(AvmInstruction {
13101332
opcode: AvmOpcode::GETCONTRACTINSTANCE,
13111333
indirect: Some(
13121334
AddressingModeBuilder::default()
13131335
.direct_operand(&address_offset)
1314-
.indirect_operand(&dest_offset)
1336+
.direct_operand(&dest_offset)
1337+
.direct_operand(&exists_offset)
13151338
.build(),
13161339
),
13171340
operands: vec![
1318-
AvmOperand::U32 { value: address_offset.to_usize() as u32 },
1319-
AvmOperand::U32 { value: dest_offset.to_usize() as u32 },
1341+
AvmOperand::U8 { value: member_idx as u8 },
1342+
AvmOperand::U16 { value: address_offset.to_usize() as u16 },
1343+
AvmOperand::U16 { value: dest_offset.to_usize() as u16 },
1344+
AvmOperand::U16 { value: exists_offset.to_usize() as u16 },
13201345
],
13211346
..Default::default()
13221347
});

barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,43 +2274,14 @@ TEST_F(AvmExecutionTests, opCallOpcodes)
22742274
validate_trace(std::move(trace), public_inputs, calldata, returndata);
22752275
}
22762276

2277-
TEST_F(AvmExecutionTests, opGetContractInstanceOpcodes)
2277+
TEST_F(AvmExecutionTests, opGetContractInstanceOpcode)
22782278
{
2279-
std::string bytecode_hex = to_hex(OpCode::SET_8) + // opcode SET
2280-
"00" // Indirect flag
2281-
+ to_hex(AvmMemoryTag::U32) +
2282-
"00" // val
2283-
"00" // dst_offset
2284-
+ to_hex(OpCode::SET_8) + // opcode SET
2285-
"00" // Indirect flag
2286-
+ to_hex(AvmMemoryTag::U32) +
2287-
"01" // val
2288-
"01" +
2289-
to_hex(OpCode::CALLDATACOPY) + // opcode CALLDATACOPY for addr
2290-
"00" // Indirect flag
2291-
"0000" // cd_offset
2292-
"0001" // copy_size
2293-
"0001" // dst_offset, (i.e. where we store the addr)
2294-
+ to_hex(OpCode::SET_8) + // opcode SET for the indirect dst offset
2295-
"00" // Indirect flag
2296-
+ to_hex(AvmMemoryTag::U32) +
2297-
"03" // val i
2298-
"02" + // dst_offset 2
2299-
to_hex(OpCode::GETCONTRACTINSTANCE) + // opcode CALL
2300-
"02" // Indirect flag
2301-
"00000001" // address offset
2302-
"00000002" // dst offset
2303-
+ to_hex(OpCode::RETURN) + // opcode RETURN
2304-
"00" // Indirect flag
2305-
"0003" // ret offset 3
2306-
"0006"; // ret size 6
2307-
2308-
auto bytecode = hex_to_bytes(bytecode_hex);
2309-
auto instructions = Deserialization::parse(bytecode);
2310-
2311-
FF address = 10;
2312-
std::vector<FF> calldata = { address };
2313-
std::vector<FF> returndata = {};
2279+
const uint8_t address_byte = 0x42;
2280+
const FF address(address_byte);
2281+
const FF deployer = 42;
2282+
const FF class_id = 66;
2283+
const FF init_hash = 99;
2284+
const FF exists = 1;
23142285

23152286
// Generate Hint for call operation
23162287
// Note: opcode does not write 'address' into memory
@@ -2322,14 +2293,56 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcodes)
23222293
grumpkin::g1::affine_element::random_element(),
23232294
grumpkin::g1::affine_element::random_element(),
23242295
};
2325-
auto execution_hints =
2326-
ExecutionHints().with_contract_instance_hints({ { address, { address, 1, 2, 3, 4, 5, public_keys_hints } } });
2296+
const auto execution_hints = ExecutionHints().with_contract_instance_hints(
2297+
{ { address, { address, exists, /*salt=*/2, deployer, class_id, init_hash, public_keys_hints } } });
2298+
2299+
std::string bytecode_hex = to_hex(OpCode::SET_8) + // opcode SET
2300+
"00" // Indirect flag
2301+
+ to_hex(AvmMemoryTag::U8) + to_hex(address_byte) + // val
2302+
"01" // dst_offset 0
2303+
+ to_hex(OpCode::GETCONTRACTINSTANCE) + // opcode GETCONTRACTINSTANCE
2304+
"00" // Indirect flag
2305+
+ to_hex(static_cast<uint8_t>(ContractInstanceMember::DEPLOYER)) + // member enum
2306+
"0001" // address offset
2307+
"0010" // dst offset
2308+
"0011" // exists offset
2309+
+ to_hex(OpCode::GETCONTRACTINSTANCE) + // opcode GETCONTRACTINSTANCE
2310+
"00" // Indirect flag
2311+
+ to_hex(static_cast<uint8_t>(ContractInstanceMember::CLASS_ID)) + // member enum
2312+
"0001" // address offset
2313+
"0012" // dst offset
2314+
"0013" // exists offset
2315+
+ to_hex(OpCode::GETCONTRACTINSTANCE) + // opcode GETCONTRACTINSTANCE
2316+
"00" // Indirect flag
2317+
+ to_hex(static_cast<uint8_t>(ContractInstanceMember::INIT_HASH)) + // member enum
2318+
"0001" // address offset
2319+
"0014" // dst offset
2320+
"0015" // exists offset
2321+
+ to_hex(OpCode::RETURN) + // opcode RETURN
2322+
"00" // Indirect flag
2323+
"0010" // ret offset 1
2324+
"0006"; // ret size 6 (dst & exists for all 3)
23272325

2326+
auto bytecode = hex_to_bytes(bytecode_hex);
2327+
auto instructions = Deserialization::parse(bytecode);
2328+
2329+
ASSERT_THAT(instructions, SizeIs(5));
2330+
2331+
std::vector<FF> const calldata{};
2332+
// alternating member value, exists bool
2333+
std::vector<FF> const expected_returndata = {
2334+
deployer, 1, class_id, 1, init_hash, 1,
2335+
};
2336+
2337+
std::vector<FF> returndata{};
23282338
auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);
2329-
EXPECT_EQ(returndata, std::vector<FF>({ 1, 2, 3, 4, 5, returned_point.x })); // The first one represents true
23302339

23312340
validate_trace(std::move(trace), public_inputs, calldata, returndata);
2341+
2342+
// Validate returndata
2343+
EXPECT_EQ(returndata, expected_returndata);
23322344
}
2345+
23332346
// Negative test detecting an invalid opcode byte.
23342347
TEST_F(AvmExecutionTests, invalidOpcode)
23352348
{

barretenberg/cpp/src/barretenberg/vm/avm/trace/deserialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ const std::unordered_map<OpCode, std::vector<OperandType>> OPCODE_WIRE_FORMAT =
136136
OperandType::UINT16,
137137
/*TODO: leafIndexOffset is not constrained*/ OperandType::UINT16,
138138
OperandType::UINT16 } },
139-
{ OpCode::GETCONTRACTINSTANCE, { OperandType::INDIRECT8, OperandType::UINT32, OperandType::UINT32 } },
139+
{ OpCode::GETCONTRACTINSTANCE, { OperandType::INDIRECT8, OperandType::UINT8, OperandType::UINT16, OperandType::UINT16, OperandType::UINT16 } },
140140
{ OpCode::EMITUNENCRYPTEDLOG,
141141
{
142142
OperandType::INDIRECT8,

barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,8 +621,10 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
621621
break;
622622
case OpCode::GETCONTRACTINSTANCE:
623623
trace_builder.op_get_contract_instance(std::get<uint8_t>(inst.operands.at(0)),
624-
std::get<uint32_t>(inst.operands.at(1)),
625-
std::get<uint32_t>(inst.operands.at(2)));
624+
std::get<uint8_t>(inst.operands.at(1)),
625+
std::get<uint16_t>(inst.operands.at(2)),
626+
std::get<uint16_t>(inst.operands.at(3)),
627+
std::get<uint16_t>(inst.operands.at(4)));
626628
break;
627629

628630
// Accrued Substate

barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ enum class EnvironmentVariable {
133133
MAX_ENV_VAR
134134
};
135135

136+
enum class ContractInstanceMember {
137+
DEPLOYER,
138+
CLASS_ID,
139+
INIT_HASH,
140+
// sentinel
141+
MAX_MEMBER,
142+
};
143+
136144
class Bytecode {
137145
public:
138146
static bool is_valid(uint8_t byte);

barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,45 +2373,71 @@ void AvmTraceBuilder::op_l1_to_l2_msg_exists(uint8_t indirect,
23732373
debug("l1_to_l2_msg_exists side-effect cnt: ", side_effect_counter);
23742374
}
23752375

2376-
void AvmTraceBuilder::op_get_contract_instance(uint8_t indirect, uint32_t address_offset, uint32_t dst_offset)
2376+
void AvmTraceBuilder::op_get_contract_instance(
2377+
uint8_t indirect, uint8_t member_enum, uint16_t address_offset, uint16_t dst_offset, uint16_t exists_offset)
23772378
{
2379+
ASSERT(member_enum < static_cast<int>(ContractInstanceMember::MAX_MEMBER));
2380+
ContractInstanceMember chosen_member = static_cast<ContractInstanceMember>(member_enum);
2381+
23782382
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;
23792383

2380-
auto [resolved_address_offset, resolved_dst_offset] =
2381-
Addressing<2>::fromWire(indirect, call_ptr).resolve({ address_offset, dst_offset }, mem_trace_builder);
2384+
auto [resolved_address_offset, resolved_dst_offset, resolved_exists_offset] =
2385+
Addressing<3>::fromWire(indirect, call_ptr)
2386+
.resolve({ address_offset, dst_offset, exists_offset }, mem_trace_builder);
23822387

23832388
auto read_address = constrained_read_from_memory(
23842389
call_ptr, clk, resolved_address_offset, AvmMemoryTag::FF, AvmMemoryTag::FF, IntermRegister::IA);
23852390
bool tag_match = read_address.tag_match;
23862391

2392+
// Read the contract instance
2393+
ContractInstanceHint instance = execution_hints.contract_instance_hints.at(read_address.val);
2394+
2395+
const FF member_value = chosen_member == ContractInstanceMember::DEPLOYER ? instance.deployer_addr
2396+
: chosen_member == ContractInstanceMember::CLASS_ID
2397+
? instance.contract_class_id
2398+
: instance.initialisation_hash; // chosen_member == ContractInstanceMember::INIT_HASH
2399+
2400+
// TODO:(8603): once instructions can have multiple different tags for writes, write dst as FF and exists as U1
2401+
// auto write_dst = constrained_write_to_memory(call_ptr, clk, resolved_dst_offset, member_value, AvmMemoryTag::FF,
2402+
// AvmMemoryTag::FF, IntermRegister::IC); auto write_exists = constrained_write_to_memory(call_ptr, clk,
2403+
// resolved_exists_offset, instance.instance_found_in_address, AvmMemoryTag::FF, AvmMemoryTag::FF,
2404+
// IntermRegister::ID);
2405+
23872406
// Constrain gas cost
23882407
gas_trace_builder.constrain_gas(clk, OpCode::GETCONTRACTINSTANCE);
23892408

23902409
main_trace.push_back(Row{
23912410
.main_clk = clk,
2411+
.main_call_ptr = call_ptr,
23922412
.main_ia = read_address.val,
2413+
// TODO:(8603): uncomment this and below blocks once instructions can have multiple different tags for writes
2414+
//.main_ic = write_dst.val,
2415+
//.main_id = write_exists.val,
23932416
.main_ind_addr_a = FF(read_address.indirect_address),
2417+
//.main_ind_addr_c = FF(write_dst.indirect_address),
2418+
//.main_ind_addr_d = FF(write_exists.indirect_address),
23942419
.main_internal_return_ptr = FF(internal_return_ptr),
23952420
.main_mem_addr_a = FF(read_address.direct_address),
2421+
//.main_mem_addr_c = FF(write_dst.direct_address),
2422+
//.main_mem_addr_d = FF(write_exists.direct_address),
23962423
.main_pc = FF(pc++),
23972424
.main_r_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::FF)),
23982425
.main_sel_mem_op_a = FF(1),
2426+
//.main_sel_mem_op_c = FF(1),
2427+
//.main_sel_mem_op_d = FF(1),
23992428
.main_sel_op_get_contract_instance = FF(1),
24002429
.main_sel_resolve_ind_addr_a = FF(static_cast<uint32_t>(read_address.is_indirect)),
2430+
//.main_sel_resolve_ind_addr_c = FF(static_cast<uint32_t>(write_dst.is_indirect)),
2431+
//.main_sel_resolve_ind_addr_d = FF(static_cast<uint32_t>(write_exists.is_indirect)),
24012432
.main_tag_err = FF(static_cast<uint32_t>(!tag_match)),
24022433
});
24032434

2404-
// Read the contract instance
2405-
ContractInstanceHint contract_instance = execution_hints.contract_instance_hints.at(read_address.val);
2406-
std::vector<FF> public_key_fields = contract_instance.public_keys.to_fields();
2407-
// NOTE: we don't write the first entry (the contract instance's address/key) to memory
2408-
std::vector<FF> contract_instance_vec = { contract_instance.instance_found_in_address,
2409-
contract_instance.salt,
2410-
contract_instance.deployer_addr,
2411-
contract_instance.contract_class_id,
2412-
contract_instance.initialisation_hash };
2413-
contract_instance_vec.insert(contract_instance_vec.end(), public_key_fields.begin(), public_key_fields.end());
2414-
write_slice_to_memory(resolved_dst_offset, AvmMemoryTag::FF, contract_instance_vec);
2435+
// TODO:(8603): once instructions can have multiple different tags for writes, remove this and do a constrained
2436+
// writes
2437+
write_to_memory(resolved_dst_offset, member_value, AvmMemoryTag::FF);
2438+
write_to_memory(resolved_exists_offset, instance.instance_found_in_address, AvmMemoryTag::U1);
2439+
2440+
// TODO(dbanks12): compute contract address nullifier from instance preimage and perform membership check
24152441

24162442
debug("contract_instance cnt: ", side_effect_counter);
24172443
side_effect_counter++;

barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class AvmTraceBuilder {
114114
uint32_t log_offset,
115115
uint32_t leaf_index_offset,
116116
uint32_t dest_offset);
117-
void op_get_contract_instance(uint8_t indirect, uint32_t address_offset, uint32_t dst_offset);
117+
void op_get_contract_instance(uint8_t indirect, uint8_t member_enum, uint16_t address_offset, uint16_t dst_offset, uint16_t exists_offset);
118118

119119
// Accrued Substate
120120
void op_emit_unencrypted_log(uint8_t indirect, uint32_t log_offset, uint32_t log_size_offset);

noir-projects/aztec-nr/aztec/src/context/public_context.nr

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,6 @@ unconstrained fn sender() -> AztecAddress {
219219
unconstrained fn portal() -> EthAddress {
220220
portal_opcode()
221221
}
222-
// UNUSED: Remove.
223-
// unconstrained fn function_selector() -> u32 {
224-
// function_selector_opcode()
225-
// }
226222
unconstrained fn transaction_fee() -> Field {
227223
transaction_fee_opcode()
228224
}
@@ -326,10 +322,6 @@ unconstrained fn sender_opcode() -> AztecAddress {}
326322
#[oracle(avmOpcodePortal)]
327323
unconstrained fn portal_opcode() -> EthAddress {}
328324

329-
// UNUSED: Remove.
330-
// #[oracle(avmOpcodeFunctionSelector)]
331-
// unconstrained fn function_selector_opcode() -> u32 {}
332-
333325
#[oracle(avmOpcodeTransactionFee)]
334326
unconstrained fn transaction_fee_opcode() -> Field {}
335327

0 commit comments

Comments
 (0)