Skip to content

Commit

Permalink
feat: #[derive(Packable)] (#11531)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan authored Jan 29, 2025
1 parent 0ba31df commit 83fe192
Show file tree
Hide file tree
Showing 23 changed files with 136 additions and 272 deletions.
6 changes: 4 additions & 2 deletions noir-projects/aztec-nr/address-note/src/address_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use dep::aztec::{
},
oracle::random::random,
protocol_types::{
address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator, traits::Serialize,
address::AztecAddress,
constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator,
traits::{Packable, Serialize},
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,11 @@ use std::meta::derive;

// A Fixedsize Compressed String.
// Essentially a special version of Compressed String for practical use.
#[derive(Serialize, Deserialize)]
#[derive(Deserialize, Packable, Serialize)]
pub struct FieldCompressedString {
value: Field,
}

/// We implement the Packable trait for FieldCompressedString because it can be stored in contract's storage
/// (and there the implementation of Packable is required).
impl Packable<1> for FieldCompressedString {
fn pack(self) -> [Field; 1] {
self.serialize()
}

fn unpack(input: [Field; 1]) -> Self {
Self::deserialize(input)
}
}

impl FieldCompressedString {
pub fn is_eq(self, other: FieldCompressedString) -> bool {
self.value == other.value
Expand Down
6 changes: 4 additions & 2 deletions noir-projects/aztec-nr/uint-note/src/uint_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ use dep::aztec::{
oracle::random::random,
prelude::{NoteHeader, NullifiableNote, PrivateContext},
protocol_types::{
address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator, traits::Serialize,
address::AztecAddress,
constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator,
traits::{Packable, Serialize},
},
};

Expand Down
6 changes: 4 additions & 2 deletions noir-projects/aztec-nr/value-note/src/value_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use dep::aztec::{
},
oracle::random::random,
protocol_types::{
address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator, traits::Serialize,
address::AztecAddress,
constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator,
traits::{Packable, Serialize},
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}};
use std::meta::derive;

global CONFIG_LENGTH: u32 = 3;

/// We store the tokens of the pool in a struct such that to load it from SharedImmutable asserts only a single
/// merkle proof.
/// (Once we actually do the optimization. WIP in https://github.com/AztecProtocol/aztec-packages/pull/8022).
#[derive(Serialize, Deserialize)]
#[derive(Deserialize, Packable, Serialize)]
pub struct Config {
pub token0: AztecAddress,
pub token1: AztecAddress,
pub liquidity_token: AztecAddress,
}

/// We implement the Packable trait for Config because it can be stored in contract's storage (and there
/// the implementation of Packable is required).
impl Packable<CONFIG_LENGTH> for Config {
fn pack(self: Self) -> [Field; CONFIG_LENGTH] {
self.serialize()
}

fn unpack(fields: [Field; CONFIG_LENGTH]) -> Self {
Self::deserialize(fields)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use dep::aztec::{
note::utils::compute_note_hash_for_nullify,
oracle::random::random,
prelude::{NoteHeader, NullifiableNote, PrivateContext},
protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER},
protocol_types::{
address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, traits::Packable,
},
};

#[note]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,9 @@
use dep::aztec::{macros::aztec, protocol_types::traits::{Deserialize, Packable, Serialize}};

// I tried using #[derive(Serialize, Deserialize)] macro here but for whatever reason it fails to compile.
pub struct Note {
a: Field,
b: Field,
}

impl Serialize<2> for Note {
fn serialize(self) -> [Field; 2] {
[self.a, self.b]
}
}

impl Deserialize<2> for Note {
fn deserialize(wire: [Field; 2]) -> Note {
Note { a: wire[0], b: wire[1] }
}
}

/// We implement the Packable trait for Note because it can be stored in contract's storage (and there
/// the implementation of Packable is required).
impl Packable<2> for Note {
fn pack(self) -> [Field; 2] {
self.serialize()
}

fn unpack(fields: [Field; 2]) -> Self {
Self::deserialize(fields)
}
}
mod note;
use dep::aztec::macros::aztec;

#[aztec]
contract AvmTest {
use crate::Note;
use crate::note::Note;

global big_field_128_bits: Field = 0x001234567890abcdef1234567890abcdef;
global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use dep::aztec::protocol_types::traits::{Deserialize, Packable, Serialize};
use std::meta::derive;

#[derive(Deserialize, Packable, Serialize)]
pub struct Note {
a: Field,
b: Field,
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::cards::Card;
use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable}};
use std::meta::derive;

global NUMBER_OF_PLAYERS: u32 = 2;
global NUMBER_OF_CARDS_DECK: u32 = 2;

#[derive(Deserialize, Eq)]
pub struct PlayerEntry {
address: AztecAddress,
deck_strength: u32,
Expand All @@ -16,28 +18,9 @@ impl PlayerEntry {
}
}

global PLAYER_SERIALIZED_LEN: u32 = 3;

impl Deserialize<PLAYER_SERIALIZED_LEN> for PlayerEntry {
fn deserialize(fields: [Field; PLAYER_SERIALIZED_LEN]) -> PlayerEntry {
let address = AztecAddress::from_field(fields[0]);
let deck_strength = fields[1] as u32;
let points = fields[2] as u64;

PlayerEntry { address, deck_strength, points }
}
}

impl Eq for PlayerEntry {
fn eq(self, other: PlayerEntry) -> bool {
self.address.eq(other.address)
& self.deck_strength.eq(other.deck_strength)
& self.points.eq(other.points)
}
}

global PLAYABLE_CARDS: u32 = 4;

#[derive(Packable)]
pub struct Game {
players: [PlayerEntry; NUMBER_OF_PLAYERS],
rounds_cards: [Card; PLAYABLE_CARDS],
Expand All @@ -48,52 +31,6 @@ pub struct Game {
current_round: u32,
}

global GAME_SERIALIZED_LEN: u32 = 15;

impl Packable<GAME_SERIALIZED_LEN> for Game {
fn pack(game: Game) -> [Field; GAME_SERIALIZED_LEN] {
[
game.players[0].address.to_field(),
game.players[0].deck_strength as Field,
game.players[0].points as Field,
game.players[1].address.to_field(),
game.players[1].deck_strength as Field,
game.players[1].points as Field,
game.rounds_cards[0].to_field(),
game.rounds_cards[1].to_field(),
game.rounds_cards[2].to_field(),
game.rounds_cards[3].to_field(),
game.started as Field,
game.finished as Field,
game.claimed as Field,
game.current_player as Field,
game.current_round as Field,
]
}

fn unpack(fields: [Field; GAME_SERIALIZED_LEN]) -> Game {
let player1 = PlayerEntry::deserialize([fields[0], fields[1], fields[2]]);
let player2 = PlayerEntry::deserialize([fields[3], fields[4], fields[5]]);

let players = [player1, player2];
let rounds_cards = [
Card::from_field(fields[6]),
Card::from_field(fields[7]),
Card::from_field(fields[8]),
Card::from_field(fields[9]),
];
Game {
players,
rounds_cards,
started: fields[10] as bool,
finished: fields[11] as bool,
claimed: fields[12] as bool,
current_player: fields[13] as u32,
current_round: fields[14] as u32,
}
}
}

impl Game {
pub fn add_player(&mut self, player_entry: PlayerEntry) -> bool {
let mut added = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use dep::aztec::{
macros::notes::note,
note::utils::compute_note_hash_for_nullify,
protocol_types::{
address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator, traits::Serialize,
address::AztecAddress,
constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator,
traits::{Packable, Serialize},
},
};
use dep::aztec::prelude::{NoteHeader, NullifiableNote, PrivateContext};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,9 @@
use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}};
use std::meta::derive;

// Shows how to create a custom struct in Public
#[derive(Deserialize, Packable, Serialize)]
pub struct Leader {
account: AztecAddress,
points: u8,
}

global LEADER_SERIALIZED_LEN: u32 = 2;

impl Deserialize<LEADER_SERIALIZED_LEN> for Leader {
fn deserialize(fields: [Field; LEADER_SERIALIZED_LEN]) -> Self {
Leader { account: AztecAddress::from_field(fields[0]), points: fields[1] as u8 }
}
}

impl Serialize<LEADER_SERIALIZED_LEN> for Leader {
fn serialize(self) -> [Field; LEADER_SERIALIZED_LEN] {
[self.account.to_field(), self.points as Field]
}
}

impl Packable<LEADER_SERIALIZED_LEN> for Leader {
fn pack(self) -> [Field; LEADER_SERIALIZED_LEN] {
self.serialize()
}

fn unpack(fields: [Field; LEADER_SERIALIZED_LEN]) -> Self {
Self::deserialize(fields)
}
}
29 changes: 2 additions & 27 deletions noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr
Original file line number Diff line number Diff line change
@@ -1,33 +1,8 @@
use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}};
use std::meta::derive;

global CONFIG_LENGTH: u32 = 2;

#[derive(Deserialize, Packable, Serialize)]
pub struct Config {
pub accepted_asset: AztecAddress, // Asset the FPC accepts (denoted as AA below)
pub admin: AztecAddress, // Address to which AA is sent during the private fee payment flow
}

impl Serialize<CONFIG_LENGTH> for Config {
fn serialize(self: Self) -> [Field; CONFIG_LENGTH] {
[self.accepted_asset.to_field(), self.admin.to_field()]
}
}

impl Deserialize<CONFIG_LENGTH> for Config {
fn deserialize(fields: [Field; CONFIG_LENGTH]) -> Self {
Config {
accepted_asset: AztecAddress::from_field(fields[0]),
admin: AztecAddress::from_field(fields[1]),
}
}
}

impl Packable<CONFIG_LENGTH> for Config {
fn pack(self) -> [Field; CONFIG_LENGTH] {
self.serialize()
}

fn unpack(fields: [Field; CONFIG_LENGTH]) -> Self {
Self::deserialize(fields)
}
}
Original file line number Diff line number Diff line change
@@ -1,52 +1,18 @@
use dep::aztec::prelude::AztecAddress;
use dep::aztec::protocol_types::traits::{Deserialize, Packable, Serialize};
use dep::aztec::{prelude::AztecAddress, protocol_types::traits::{Deserialize, Packable, Serialize}};
use std::meta::derive;

// Struct to be used to represent "totals". Generally, there should be one per Asset.
// It stores the global values that are shared among all users, such as an accumulator
// and last time it was updated.
// In practice, it should also point to an oracle and have more fields related to
// loan to value ratios and other things, but we did not have enough reads/writes for this.
/// Struct to be used to represent "totals". Generally, there should be one per Asset.
/// It stores the global values that are shared among all users, such as an accumulator
/// and last time it was updated.
/// In practice, it should also point to an oracle and have more fields related to
/// loan to value ratios and other things, but we did not have enough reads/writes for this.
///
/// Note: Right now we are wasting so many writes. If changing last_updated_ts we will end
/// up rewriting all the values.
#[derive(Deserialize, Packable, Serialize)]
pub struct Asset {
interest_accumulator: U128,
last_updated_ts: u64,
loan_to_value: U128,
oracle: AztecAddress,
}

global SERIALIZED_LEN: u32 = 6;

impl Serialize<SERIALIZED_LEN> for Asset {
fn serialize(Asset: Asset) -> [Field; SERIALIZED_LEN] {
[
Asset.interest_accumulator.lo,
Asset.interest_accumulator.hi,
Asset.last_updated_ts as Field,
Asset.loan_to_value.lo,
Asset.loan_to_value.hi,
Asset.oracle.to_field(),
]
}
}

impl Deserialize<SERIALIZED_LEN> for Asset {
// Right now we are wasting so many writes. If changing last_updated_ts
// we will end up rewriting all of them, wasting writes.
fn deserialize(fields: [Field; SERIALIZED_LEN]) -> Asset {
let interest_accumulator = U128 { lo: fields[0], hi: fields[1] };
let last_updated_ts = fields[2] as u64;
let loan_to_value = U128 { lo: fields[3], hi: fields[4] };
let oracle = AztecAddress::from_field(fields[5]);

Asset { interest_accumulator, last_updated_ts, loan_to_value, oracle }
}
}

impl Packable<SERIALIZED_LEN> for Asset {
fn pack(self) -> [Field; SERIALIZED_LEN] {
self.serialize()
}

fn unpack(fields: [Field; SERIALIZED_LEN]) -> Self {
Self::deserialize(fields)
}
}
Loading

0 comments on commit 83fe192

Please sign in to comment.