Skip to content
Open
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
430 changes: 0 additions & 430 deletions noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::{
entities::EntityBody,
messages::encoding::MESSAGE_CIPHERTEXT_LEN,
protocol::{address::AztecAddress, hash::{poseidon2_hash, sha256_to_field}, traits::{Deserialize, Serialize}},
};

/// Entity type id shared by every offchain message reception entity in the entity store.
pub(crate) global OFFCHAIN_RECEPTION_ENTITY: Field = sha256_to_field("AZTEC_NR::OFFCHAIN_RECEPTION_ENTITY".as_bytes());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
pub(crate) global OFFCHAIN_RECEPTION_ENTITY: Field = sha256_to_field("AZTEC_NR::OFFCHAIN_RECEPTION_ENTITY".as_bytes());
pub(crate) global OFFCHAIN_RECEPTION_ENTITY_TYPE_ID: Field = sha256_to_field("AZTEC_NR::OFFCHAIN_RECEPTION_ENTITY".as_bytes());


/// A message delivered via the `offchain_receive` utility function.
#[derive(Serialize, Deserialize)]
pub struct OffchainMessage {
/// The encrypted message payload.
pub ciphertext: BoundedVec<Field, MESSAGE_CIPHERTEXT_LEN>,
/// The intended recipient of the message.
pub recipient: AztecAddress,
/// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.
pub tx_hash: Option<Field>,
/// Anchor block timestamp at message emission.
pub anchor_block_timestamp: u64,
}

/// Number of fields produced by serializing a `BoundedVec<Field, MESSAGE_CIPHERTEXT_LEN>`.
///
/// A `BoundedVec` serializes as its storage fields followed by a trailing length field, so the total is
/// `MESSAGE_CIPHERTEXT_LEN + 1`.
global SERIALIZED_CIPHERTEXT_LEN: u32 = MESSAGE_CIPHERTEXT_LEN + 1;
Comment on lines +23 to +27

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think you need this? this value doesn't seem to be used anywhere except inside a fn body:

        let serialized_ciphertext: [Field; SERIALIZED_CIPHERTEXT_LEN] = self.ciphertext.serialize();

and there it should be inferred from the retun type.


impl EntityBody for OffchainMessage {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not well versed in Rust idioms so I'm not sure what a good pattern here would be, I just find this slightly strange. I'm personally tempted to do impl EntityId for OffchainMessage, but that also doesn't seem fantastic. I'd consider taking a look at Rust crates or something for inspiration.

/// All offchain messages share the reception state-machine entity type.
fn entity_type_id() -> Field {
OFFCHAIN_RECEPTION_ENTITY
}

/// Computes the entity id that identifies this message's reception entity in the entity store.
///
/// The id is a poseidon2 hash over the serialized ciphertext fields and the normalized tx hash (0 when absent).
/// Re-delivering the same `(ciphertext, tx_hash)` pair therefore maps to the same entity, making `receive`
/// idempotent. The `recipient` and `anchor_block_timestamp` fields are intentionally excluded, so identity depends
/// only on the message content and its originating transaction.
fn entity_id(self) -> Field {
Comment on lines +35 to +41

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think trait impls get docstrings, so these don't make it to the docs.

The second paragraph is an implementation detail, so I'd put it in the body. The overall explanation of what the id represents ('all offchain messages, regardless of content') sounds more like it should go in the docs for OffchainMessage, which is the actual entity, alongside an explanation of the entity lifecycle etc.

let serialized_ciphertext: [Field; SERIALIZED_CIPHERTEXT_LEN] = self.ciphertext.serialize();
let mut inputs: [Field; SERIALIZED_CIPHERTEXT_LEN + 1] = [0; SERIALIZED_CIPHERTEXT_LEN + 1];
for i in 0..SERIALIZED_CIPHERTEXT_LEN {
inputs[i] = serialized_ciphertext[i];
}
inputs[SERIALIZED_CIPHERTEXT_LEN] = self.tx_hash.unwrap_or(0);
poseidon2_hash(inputs)
Comment on lines +42 to +48

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the goal is to make the id be 1-1 with the content, then we could request that EntityBody implement Serialize, and then have the generic Entity compute the id as the hash of the body's serialization.

If we don't, like we do here (because recipient and anchor block are not included) then we should definitely explain what it means for there to be multiple entities with the same id and different recipients / anchor blocks.

(incidentally I think we would not actually support that? Because the entity store only checks for pre-existence of the entity id and then does nothing if there's a match, regardless of content. So e.g. same message for multiple recipients would result in the latter ones being dropped)

}
}

mod test {
use crate::{
messages::encoding::MESSAGE_CIPHERTEXT_LEN,
protocol::{address::AztecAddress, traits::{Deserialize, FromField, Serialize}},
};
use super::OffchainMessage;

#[test]
unconstrained fn pack_unpack_round_trips_offchain_message() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is just testing that #[derive(Serialize, Deserialize)] works correctly, you can delete this entirely.

let ciphertext: BoundedVec<Field, MESSAGE_CIPHERTEXT_LEN> = BoundedVec::new();
let msg = OffchainMessage {
ciphertext,
recipient: AztecAddress::from_field(42),
tx_hash: Option::some(99),
anchor_block_timestamp: 12345,
};
let packed = msg.serialize();
let roundtripped: OffchainMessage = Deserialize::deserialize(packed);
assert_eq(roundtripped.recipient, msg.recipient);
assert_eq(roundtripped.tx_hash, msg.tx_hash);
assert_eq(roundtripped.anchor_block_timestamp, msg.anchor_block_timestamp);
assert_eq(roundtripped.ciphertext.len(), msg.ciphertext.len());
}
}
Loading
Loading