From 694cebc10c5713b2fa82ac6a29961bf44b026046 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:51:04 +0200 Subject: [PATCH] feat: add support for fieldable in events (#7310) Finishes #6951 --- .../src/main.nr | 32 +++++++------------ .../contracts/test_log_contract/src/main.nr | 8 ++--- .../contracts/token_contract/src/main.nr | 6 ++-- .../aztec_macros/src/transforms/events.rs | 26 +++++++++++++-- .../end-to-end/src/e2e_event_logs.test.ts | 19 +++++++++-- 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index 2310b39f60a..bea326ca5f1 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -9,9 +9,9 @@ contract ContractInstanceDeployer { oracle::logs::emit_unencrypted_log_private_internal }; - // @todo This should be using an event, but currently we only support fields in the struct. - // #[aztec(event)] + #[aztec(event)] struct ContractInstanceDeployed { + DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE: Field, address: AztecAddress, version: u8, salt: Field, @@ -21,23 +21,6 @@ contract ContractInstanceDeployer { deployer: AztecAddress, } - global CONTRACT_INSTANCE_DEPLOYED_SERIALIZED_SIZE: Field = 8; - - impl Serialize for ContractInstanceDeployed { - fn serialize(self: Self) -> [Field; CONTRACT_INSTANCE_DEPLOYED_SERIALIZED_SIZE] { - [ - DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, - self.address.to_field(), - self.version as Field, - self.salt, - self.contract_class_id.to_field(), - self.initialization_hash, - self.public_keys_hash.to_field(), - self.deployer.to_field(), - ] - } - } - #[aztec(private)] fn deploy( salt: Field, @@ -62,7 +45,16 @@ contract ContractInstanceDeployer { context.push_nullifier(address.to_field(), 0); // Broadcast the event - let event = ContractInstanceDeployed { contract_class_id, address, public_keys_hash, initialization_hash, salt, deployer, version: 1 }; + let event = ContractInstanceDeployed { + DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, + contract_class_id, + address, + public_keys_hash, + initialization_hash, + salt, + deployer, + version: 1 + }; let payload = event.serialize(); dep::aztec::oracle::debug_log::debug_log_format("ContractInstanceDeployed: {}", payload); diff --git a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr index 0d1d06b731d..46489bf2b5c 100644 --- a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr @@ -18,8 +18,8 @@ contract TestLog { #[aztec(event)] struct ExampleEvent1 { - value2: Field, - value3: Field, + value2: AztecAddress, + value3: u8, } #[aztec(storage)] @@ -69,7 +69,7 @@ contract TestLog { ) ); - let event1 = ExampleEvent1 { value2: preimages[2], value3: preimages[3] }; + let event1 = ExampleEvent1 { value2: AztecAddress::from_field(preimages[2]), value3: preimages[3] as u8 }; event1.emit( encode_and_encrypt_event_with_randomness( @@ -88,7 +88,7 @@ contract TestLog { event0.emit(encode_event(&mut context)); - let event1 = ExampleEvent1 { value2: preimages[2], value3: preimages[3] }; + let event1 = ExampleEvent1 { value2: AztecAddress::from_field(preimages[2]), value3: preimages[3] as u8 }; event1.emit(encode_event(&mut context)); } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 3f8bdfd8bea..87919c600aa 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -36,8 +36,8 @@ contract Token { #[aztec(event)] struct Transfer { - from: Field, - to: Field, + from: AztecAddress, + to: AztecAddress, amount: Field, } @@ -338,7 +338,7 @@ contract Token { storage.balances.sub(from, amount).emit(encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_ovpk, from_ivpk)); storage.balances.add(to, amount).emit(encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_ovpk, to_ivpk)); - Transfer { from: from.to_field(), to: to.to_field(), amount: amount.to_field() }.emit(encode_and_encrypt_event_with_keys_unconstrained(&mut context, from_ovpk, to_ivpk)); + Transfer { from, to, amount: amount.to_field() }.emit(encode_and_encrypt_event_with_keys_unconstrained(&mut context, from_ovpk, to_ivpk)); } // docs:end:transfer diff --git a/noir/noir-repo/aztec_macros/src/transforms/events.rs b/noir/noir-repo/aztec_macros/src/transforms/events.rs index 05861b96eb4..ecfca40189d 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/events.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/events.rs @@ -117,8 +117,19 @@ fn generate_trait_impl_serialize( event_len: u32, event_fields: &[(String, String)], ) -> Result { - let field_names = - event_fields.iter().map(|field| format!("self.{}", field.0)).collect::>(); + let field_names = event_fields + .iter() + .map(|field| { + let field_type = field.1.as_str(); + match field_type { + "Field" => format!("self.{}", field.0), + "bool" | "u8" | "u32" | "u64" | "i8" | "i32" | "i64" => { + format!("self.{} as Field", field.0) + } + _ => format!("self.{}.to_field()", field.0), + } + }) + .collect::>(); let field_input = field_names.join(","); let trait_impl_source = format!( @@ -154,7 +165,16 @@ fn generate_trait_impl_deserialize( let field_names: Vec = event_fields .iter() .enumerate() - .map(|(index, field)| format!("{}: fields[{}]", field.0, index)) + .map(|(index, field)| { + let field_type = field.1.as_str(); + match field_type { + "Field" => format!("{}: fields[{}]", field.0, index), + "bool" | "u8" | "u32" | "u64" | "i8" | "i32" | "i64" => { + format!("{}: fields[{}] as {}", field.0, index, field_type) + } + _ => format!("{}: {}::from_field(fields[{}])", field.0, field.1, index), + } + }) .collect::>(); let field_input = field_names.join(","); diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index d49bef63dd1..576a8f2da17 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -97,7 +97,8 @@ describe('Logs', () => { // We expect the fields to have been populated correctly expect(event1?.value2).toStrictEqual(preimage[2]); - expect(event1?.value3).toStrictEqual(preimage[3]); + // We get the last byte here because value3 is of type u8 + expect(event1?.value3).toStrictEqual(new Fr(preimage[3].toBuffer().subarray(31))); // Again, trying to decode another event with mismatching data does not yield anything const badEvent1 = TestLogContract.events.ExampleEvent0.decode(decryptedLog1!.payload); @@ -189,7 +190,13 @@ describe('Logs', () => { const exampleEvent1Sort = (a: ExampleEvent1, b: ExampleEvent1) => (a.value2 > b.value2 ? 1 : -1); expect(collectedEvent1s.sort(exampleEvent1Sort)).toStrictEqual( - preimage.map(preimage => ({ value2: preimage[2], value3: preimage[3] })).sort(exampleEvent1Sort), + preimage + .map(preimage => ({ + value2: preimage[2], + // We get the last byte here because value3 is of type u8 + value3: new Fr(preimage[3].toBuffer().subarray(31)), + })) + .sort(exampleEvent1Sort), ); }); @@ -227,7 +234,13 @@ describe('Logs', () => { const exampleEvent1Sort = (a: ExampleEvent1, b: ExampleEvent1) => (a.value2 > b.value2 ? 1 : -1); expect(collectedEvent1s.sort(exampleEvent1Sort)).toStrictEqual( - preimage.map(preimage => ({ value2: preimage[2], value3: preimage[3] })).sort(exampleEvent1Sort), + preimage + .map(preimage => ({ + value2: preimage[2], + // We get the last byte here because value3 is of type u8 + value3: new Fr(preimage[3].toBuffer().subarray(31)), + })) + .sort(exampleEvent1Sort), ); }); });