Skip to content

Commit

Permalink
chore!: Serialize, Deserialize and NoteInterface as Traits (#4135)
Browse files Browse the repository at this point in the history
Closes: #3756,
#2838


Taking advantage of @jfecher's fantastic work in
noir-lang/noir#4000, implemented `Serialize<N>`
and `Deserialize<N>`. Together with `NoteInterface`, they make possible
getting rid of all the serialization interfaces, which greatly simplify
how the storage is handled and opens the door to further improvements.
~~Still some clutter to go, the lengths are still needed in some
places.~~


![Brace yourself](https://i.imgflip.com/8crkve.jpg)

I'm so sorry.

---------

Co-authored-by: sirasistant <sirasistant@gmail.com>
  • Loading branch information
Thunkar and sirasistant authored Jan 30, 2024
1 parent 648229c commit 9e6605c
Show file tree
Hide file tree
Showing 102 changed files with 1,452 additions and 1,677 deletions.
30 changes: 10 additions & 20 deletions boxes/token/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ contract Token {
context::{PrivateContext, PublicContext, Context},
hash::{compute_secret_hash},
state_vars::{map::Map, public_state::PublicState, set::Set},
types::type_serialization::{
field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN},
bool_serialization::{BoolSerializationMethods, BOOL_SERIALIZED_LEN},
address_serialization::{AddressSerializationMethods, AZTEC_ADDRESS_SERIALIZED_LEN},
},
protocol_types::{
abis::function_selector::FunctionSelector,
address::AztecAddress,
Expand All @@ -45,29 +40,28 @@ contract Token {
// docs:end:import_authwit

use crate::types::{
transparent_note::{TransparentNote, TransparentNoteMethods, TRANSPARENT_NOTE_LEN},
token_note::{TokenNote, TokenNoteMethods, TOKEN_NOTE_LEN},
transparent_note::TransparentNote,
token_note::{TokenNote, TOKEN_NOTE_LEN},
balances_map::{BalancesMap},
safe_u120_serialization::{SafeU120SerializationMethods, SAFE_U120_SERIALIZED_LEN}
};
// docs:end::imports

// docs:start:storage_struct
struct Storage {
// docs:start:storage_admin
admin: PublicState<AztecAddress, AZTEC_ADDRESS_SERIALIZED_LEN>,
admin: PublicState<AztecAddress>,
// docs:end:storage_admin
// docs:start:storage_minters
minters: Map<AztecAddress, PublicState<bool, BOOL_SERIALIZED_LEN>>,
minters: Map<AztecAddress, PublicState<bool>>,
// docs:end:storage_minters
// docs:start:storage_balances
balances: BalancesMap,
// docs:end:storage_balances
total_supply: PublicState<SafeU120, SAFE_U120_SERIALIZED_LEN>,
total_supply: PublicState<SafeU120>,
// docs:start:storage_pending_shields
pending_shields: Set<TransparentNote, TRANSPARENT_NOTE_LEN>,
pending_shields: Set<TransparentNote>,
// docs:end:storage_pending_shields
public_balances: Map<AztecAddress, PublicState<SafeU120, SAFE_U120_SERIALIZED_LEN>>,
public_balances: Map<AztecAddress, PublicState<SafeU120>>,
}
// docs:end:storage_struct

Expand All @@ -79,7 +73,6 @@ contract Token {
admin: PublicState::new(
context,
1,
AddressSerializationMethods,
),
// docs:end:storage_admin_init
// docs:start:storage_minters_init
Expand All @@ -90,7 +83,6 @@ contract Token {
PublicState::new(
context,
slot,
BoolSerializationMethods,
)
},
),
Expand All @@ -101,10 +93,9 @@ contract Token {
total_supply: PublicState::new(
context,
4,
SafeU120SerializationMethods,
),
// docs:start:storage_pending_shields_init
pending_shields: Set::new(context, 5, TransparentNoteMethods),
pending_shields: Set::new(context, 5),
// docs:end:storage_pending_shields_init
public_balances: Map::new(
context,
Expand All @@ -113,7 +104,6 @@ contract Token {
PublicState::new(
context,
slot,
SafeU120SerializationMethods,
)
},
),
Expand Down Expand Up @@ -385,9 +375,9 @@ contract Token {
) -> pub [Field; 4] {
let note_header = NoteHeader::new(contract_address, nonce, storage_slot);
if (storage_slot == 5) {
note_utils::compute_note_hash_and_nullifier(TransparentNoteMethods, note_header, serialized_note)
note_utils::compute_note_hash_and_nullifier(TransparentNote::deserialize, note_header, serialized_note)
} else {
note_utils::compute_note_hash_and_nullifier(TokenNoteMethods, note_header, serialized_note)
note_utils::compute_note_hash_and_nullifier(TokenNote::deserialize, note_header, serialized_note)
}
}
// docs:end:compute_note_hash_and_nullifier
Expand Down
1 change: 0 additions & 1 deletion boxes/token/src/contracts/src/types.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ mod transparent_note;
mod balance_set;
mod balances_map;
mod token_note;
mod safe_u120_serialization;
12 changes: 4 additions & 8 deletions boxes/token/src/contracts/src/types/balance_set.nr
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,19 @@ use dep::aztec::note::{
note_getter_options::{NoteGetterOptions, SortOrder},
note_viewer_options::NoteViewerOptions
};
use dep::aztec::note::{
note_header::NoteHeader,
note_interface::NoteInterface,
utils::compute_note_hash_for_read_or_nullify,
};
use crate::types::token_note::{TokenNote, TOKEN_NOTE_LEN, TokenNoteMethods};

use crate::types::token_note::TokenNote;

// A set implementing standard manipulation of balances.
// Does not require spending key, but only knowledge.
// Spending key requirement should be enforced by the contract using this.
struct BalanceSet {
owner: AztecAddress,
set: Set<TokenNote, TOKEN_NOTE_LEN>
set: Set<TokenNote>
}

impl BalanceSet {
pub fn new(set: Set<TokenNote, TOKEN_NOTE_LEN>, owner: AztecAddress) -> Self {
pub fn new(set: Set<TokenNote>, owner: AztecAddress) -> Self {
Self {
owner,
set,
Expand Down
5 changes: 2 additions & 3 deletions boxes/token/src/contracts/src/types/balances_map.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use crate::types::balance_set::BalanceSet;
use dep::aztec::hash::pedersen_hash;
use dep::aztec::protocol_types::address::AztecAddress;

use crate::types::token_note::{TokenNote, TOKEN_NOTE_LEN, TokenNoteMethods};
use crate::types::token_note::TokenNote;
use dep::aztec::state_vars::{map::Map, set::Set};

struct BalancesMap {
store: Map<AztecAddress, Set<TokenNote, TOKEN_NOTE_LEN>>,
store: Map<AztecAddress, Set<TokenNote>>,
}

impl BalancesMap {
Expand All @@ -20,7 +20,6 @@ impl BalancesMap {
Set {
context,
storage_slot,
note_interface: TokenNoteMethods,
}
});
Self {
Expand Down
18 changes: 0 additions & 18 deletions boxes/token/src/contracts/src/types/safe_u120_serialization.nr

This file was deleted.

89 changes: 28 additions & 61 deletions boxes/token/src/contracts/src/types/token_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use dep::aztec::{
state_vars::set::Set,
log::emit_encrypted_log,
hash::pedersen_hash,
protocol_types::traits::{Serialize, Deserialize},
};
use dep::aztec::oracle::{
rand::rand,
Expand All @@ -39,30 +40,25 @@ struct TokenNote {
header: NoteHeader,
}

impl TokenNote {
pub fn new(amount: SafeU120, owner: AztecAddress) -> Self {
Self {
amount,
owner,
randomness: rand(),
header: NoteHeader::empty(),
}
}

pub fn serialize(self) -> [Field; TOKEN_NOTE_LEN] {
impl Serialize<TOKEN_NOTE_LEN> for TokenNote {
fn serialize(self) -> [Field; TOKEN_NOTE_LEN] {
[self.amount.value as Field, self.owner.to_field(), self.randomness]
}
}

pub fn deserialize(serialized_note: [Field; TOKEN_NOTE_LEN]) -> Self {
impl Deserialize<TOKEN_NOTE_LEN> for TokenNote {
fn deserialize(serialized_note: [Field; TOKEN_NOTE_LEN]) -> Self {
Self {
amount: SafeU120::new(serialized_note[0]),
owner: AztecAddress::from_field(serialized_note[1]),
randomness: serialized_note[2],
header: NoteHeader::empty(),
}
}
}

pub fn compute_note_hash(self) -> Field {
impl NoteInterface for TokenNote {
fn compute_note_hash(self) -> Field {
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
self.amount.value as Field,
Expand All @@ -72,8 +68,8 @@ impl TokenNote {
}

// docs:start:nullifier
pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(TokenNoteMethods, self);
fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self);
let secret = context.request_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
Expand All @@ -84,8 +80,8 @@ impl TokenNote {
}
// docs:end:nullifier

pub fn compute_nullifier_without_context(self) -> Field {
let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(TokenNoteMethods, self);
fn compute_nullifier_without_context(self) -> Field {
let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self);
let secret = get_nullifier_secret_key(self.owner);
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash([
Expand All @@ -95,12 +91,16 @@ impl TokenNote {
],0)
}

pub fn set_header(&mut self, header: NoteHeader) {
fn set_header(&mut self, header: NoteHeader) {
self.header = header;
}

fn get_header(self) -> NoteHeader {
self.header
}

// Broadcasts the note as an encrypted log on L1.
pub fn broadcast(self, context: &mut PrivateContext, slot: Field) {
fn broadcast(self, context: &mut PrivateContext, slot: Field) {
// We only bother inserting the note if non-empty to save funds on gas.
if !self.amount.is_zero() {
let encryption_pub_key = get_public_key(self.owner);
Expand All @@ -115,46 +115,13 @@ impl TokenNote {
}
}

fn deserialize(serialized_note: [Field; TOKEN_NOTE_LEN]) -> TokenNote {
TokenNote::deserialize(serialized_note)
}

fn serialize(note: TokenNote) -> [Field; TOKEN_NOTE_LEN] {
note.serialize()
}

fn compute_note_hash(note: TokenNote) -> Field {
note.compute_note_hash()
}

fn compute_nullifier(note: TokenNote, context: &mut PrivateContext) -> Field {
note.compute_nullifier(context)
}

fn compute_nullifier_without_context(note: TokenNote) -> Field {
note.compute_nullifier_without_context()
}

fn get_header(note: TokenNote) -> NoteHeader {
note.header
}

fn set_header(note: &mut TokenNote, header: NoteHeader) {
note.set_header(header)
}

// Broadcasts the note as an encrypted log on L1.
fn broadcast(context: &mut PrivateContext, slot: Field, note: TokenNote) {
note.broadcast(context, slot);
impl TokenNote {
pub fn new(amount: SafeU120, owner: AztecAddress) -> Self {
Self {
amount,
owner,
randomness: rand(),
header: NoteHeader::empty(),
}
}
}

global TokenNoteMethods = NoteInterface {
deserialize,
serialize,
compute_note_hash,
compute_nullifier,
compute_nullifier_without_context,
get_header,
set_header,
broadcast,
};
Loading

0 comments on commit 9e6605c

Please sign in to comment.