From 820fc668e7235567c83662b35e7bbf7905f9b3e6 Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Tue, 19 Mar 2024 12:15:57 +0100 Subject: [PATCH] feat!: automatic NoteInterface and NoteGetterOptions auto select (#4508) Partially addresses: https://github.com/AztecProtocol/aztec-packages/issues/4519 (moved autogeneration to the macro, even if not incremental) Closes: https://github.com/AztecProtocol/aztec-packages/issues/3011 Added the `#[aztec(note)]` attribute, which automatically implements most of the `NoteInterface` trait in a struct marked as such, plus several utilities. Even if this adds a fair share of "magic" to the note implementation logic, it is structured in a way that it's hopefully easy to follow, including meaningful errors attached to the correct span during the process. ![Screenshot 2024-03-14 at 14 59 07](https://github.com/AztecProtocol/aztec-packages/assets/5404052/84a3d6e4-e346-4cfe-93eb-ec317632f344) Hey you! Implement the trait! ![Screenshot 2024-03-14 at 14 46 39](https://github.com/AztecProtocol/aztec-packages/assets/5404052/bebfb3dd-c178-44d0-b9bc-005b5c9f0f38) But only the meat and potatoes though. As long as the user doesn't want to do any custom stuff, `get_header`, `set_header`, `compute_note_content_hash`, `get_note_type_id`, `serialize_content` and `deserialize_content` get automatically implemented. Any combination of them can be overridden by the developer though. A metadata struct is also added, which takes the following form: ```rust struct CardNote { points: FieldSelector, randomness: FieldSelector, owner: FieldSelector, } ``` This is used to implement a `properties()` function, which in turn can be used in conjunction with the `NoteGetterOptions.select` and `.sort` Screenshot 2024-03-18 at 15 27 27 --- address-note/src/address_note.nr | 33 +---------- aztec/src/note/note_getter.nr | 79 +++++++++++++++++++++------ aztec/src/note/note_getter_options.nr | 44 +++++++++++---- aztec/src/note/note_interface.nr | 18 ++++-- aztec/src/note/note_viewer_options.nr | 26 +++++++-- aztec/src/oracle/notes.nr | 40 ++++++++++---- field-note/src/field_note.nr | 31 +---------- value-note/src/utils.nr | 2 +- value-note/src/value_note.nr | 34 +----------- 9 files changed, 159 insertions(+), 148 deletions(-) diff --git a/address-note/src/address_note.nr b/address-note/src/address_note.nr index ebacf94a..cd5ab4b8 100644 --- a/address-note/src/address_note.nr +++ b/address-note/src/address_note.nr @@ -12,31 +12,14 @@ global ADDRESS_NOTE_LEN: Field = 3; // docs:start:address_note_def // Stores an address +#[aztec(note)] struct AddressNote { address: AztecAddress, owner: AztecAddress, randomness: Field, - header: NoteHeader, } impl NoteInterface for AddressNote { - fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ - [self.address.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { - AddressNote { - address: AztecAddress::from_field(serialized_note[0]), - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); @@ -60,14 +43,6 @@ impl NoteInterface for AddressNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(note: Self) -> NoteHeader { - note.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -82,12 +57,6 @@ impl NoteInterface for AddressNote { ); // docs:end:encrypted } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'AddressNote')))" - 6510010011410111511578111116101 - } } impl AddressNote { diff --git a/aztec/src/note/note_getter.nr b/aztec/src/note/note_getter.nr index 25398ada..679f097e 100644 --- a/aztec/src/note/note_getter.nr +++ b/aztec/src/note/note_getter.nr @@ -6,12 +6,30 @@ use dep::protocol_types::{ }; use crate::context::PrivateContext; use crate::note::{ - note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus}, + note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_consumption }; use crate::oracle; +fn extract_property_value_from_selector(serialized_note: [Field; N], selector: PropertySelector) -> Field { + // Selectors use PropertySelectors in order to locate note properties inside the serialized note. + // This allows easier packing and custom (de)serialization schemas. A note property is located + // inside the serialized note using the index inside the array, a byte offset and a length. + let value = serialized_note[selector.index].to_be_bytes(32); + let offset = selector.offset; + let length = selector.length; + let mut value_field = 0 as Field; + let mut acc: Field = 1; + for i in 0..32 { + if i < length { + value_field += value[31 + offset - i] as Field * acc; + acc = acc * 256; + } + } + value_field +} + fn check_note_header(context: PrivateContext, storage_slot: Field, note: Note) where Note: NoteInterface { let header = note.get_header(); let contract_address = context.this_address(); @@ -19,13 +37,14 @@ fn check_note_header(context: PrivateContext, storage_slot: Field, note assert(header.storage_slot == storage_slot); } -fn check_note_fields(fields: [Field; N], selects: BoundedVec, N>) { +fn check_note_fields(serialized_note: [Field; N], selects: BoundedVec, N>) { for i in 0..selects.len { let select = selects.get_unchecked(i).unwrap_unchecked(); + let value_field = extract_property_value_from_selector(serialized_note, select.property_selector); // Values are computed ahead of time because circuits evaluate all branches - let isEqual = fields[select.field_index] == select.value; - let isLt = fields[select.field_index].lt(select.value); + let isEqual = value_field == select.value.to_field(); + let isLt = value_field.lt(select.value.to_field()); if (select.comparator == Comparator.EQ) { assert(isEqual, "Mismatch return note field."); @@ -50,8 +69,10 @@ fn check_notes_order( ) { for i in 0..sorts.len { let sort = sorts.get_unchecked(i).unwrap_unchecked(); - let eq = fields_0[sort.field_index] == fields_1[sort.field_index]; - let lt = fields_0[sort.field_index].lt(fields_1[sort.field_index]); + let field_0 = extract_property_value_from_selector(fields_0, sort.property_selector); + let field_1 = extract_property_value_from_selector(fields_1, sort.property_selector); + let eq = field_0 == field_1; + let lt = field_0.lt(field_1); if sort.order == SortOrder.ASC { assert(eq | lt, "Return notes not sorted in ascending order."); } else if !eq { @@ -120,6 +141,10 @@ unconstrained fn get_note_internal(storage_slot: Field) -> Note where N [], [], [], + [], + [], + [], + [], 1, // limit 0, // offset NoteStatus.ACTIVE, @@ -133,17 +158,21 @@ unconstrained fn get_notes_internal( storage_slot: Field, options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { - let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); + let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; let opt_notes = oracle::notes::get_notes( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, options.limit, options.offset, @@ -162,17 +191,21 @@ unconstrained pub fn view_notes( storage_slot: Field, options: NoteViewerOptions ) -> [Option; MAX_NOTES_PER_PAGE] where Note: NoteInterface { - let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); + let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE]; let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; oracle::notes::get_notes( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, options.limit, options.offset, @@ -186,31 +219,41 @@ unconstrained pub fn view_notes( unconstrained fn flatten_options( selects: BoundedVec, N>, sorts: BoundedVec, N> -) -> (u8, [u8; N], [Field; N], [u8; N], [u8; N], [u8; N]) { +) -> (u8, [u8; N], [u8; N], [u8; N], [Field; N], [u8; N], [u8; N], [u8; N], [u8; N], [u8; N]) { let mut num_selects = 0; - let mut select_by = [0; N]; + let mut select_by_indexes = [0; N]; + let mut select_by_offsets = [0; N]; + let mut select_by_lengths = [0; N]; let mut select_values = [0; N]; let mut select_comparators = [0; N]; for i in 0..selects.len { let select = selects.get(i); if select.is_some() { - select_by[num_selects] = select.unwrap_unchecked().field_index; + select_by_indexes[num_selects] = select.unwrap_unchecked().property_selector.index; + select_by_offsets[num_selects] = select.unwrap_unchecked().property_selector.offset; + select_by_lengths[num_selects] = select.unwrap_unchecked().property_selector.length; select_values[num_selects] = select.unwrap_unchecked().value; select_comparators[num_selects] = select.unwrap_unchecked().comparator; num_selects += 1; }; } - let mut sort_by = [0; N]; + let mut sort_by_indexes = [0; N]; + let mut sort_by_offsets = [0; N]; + let mut sort_by_lengths = [0; N]; let mut sort_order = [0; N]; for i in 0..sorts.len { let sort = sorts.get(i); if sort.is_some() { - sort_by[i] = sort.unwrap_unchecked().field_index; + sort_by_indexes[i] = sort.unwrap_unchecked().property_selector.index; + sort_by_offsets[i] = sort.unwrap_unchecked().property_selector.offset; + sort_by_lengths[i] = sort.unwrap_unchecked().property_selector.length; sort_order[i] = sort.unwrap_unchecked().order; }; } - (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) + ( + num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order + ) } diff --git a/aztec/src/note/note_getter_options.nr b/aztec/src/note/note_getter_options.nr index b24104a2..0389ee76 100644 --- a/aztec/src/note/note_getter_options.nr +++ b/aztec/src/note/note_getter_options.nr @@ -1,6 +1,13 @@ -use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; +use dep::std::option::Option; +use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::ToField}; use crate::note::note_interface::NoteInterface; +struct PropertySelector { + index: u8, + offset: u8, + length: u8, +} + struct ComparatorEnum { EQ: u8, NEQ: u8, @@ -20,14 +27,14 @@ global Comparator = ComparatorEnum { }; struct Select { - field_index: u8, + property_selector: PropertySelector, value: Field, comparator: u8, } impl Select { - pub fn new(field_index: u8, value: Field, comparator: u8) -> Self { - Select { field_index, value, comparator } + pub fn new(property_selector: PropertySelector, value: Field, comparator: u8) -> Self { + Select { property_selector, value, comparator } } } @@ -42,13 +49,13 @@ global SortOrder = SortOrderEnum { }; struct Sort { - field_index: u8, + property_selector: PropertySelector, order: u8, } impl Sort { - pub fn new(field_index: u8, order: u8) -> Self { - Sort { field_index, order } + pub fn new(property_selector: PropertySelector, order: u8) -> Self { + Sort { property_selector, order } } } @@ -118,18 +125,31 @@ impl NoteGetterOptions { } // This method adds a `Select` criterion to the options. - // It takes a field_index indicating which field to select, + // It takes a property_selector indicating which field to select, // a value representing the specific value to match in that field, and // a comparator (For possible values of comparators, please see the Comparator enum above) - pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { - self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); + pub fn select( + &mut self, + property_selector: PropertySelector, + value: T, + comparator: Option + ) -> Self where T: ToField { + self.selects.push( + Option::some( + Select::new( + property_selector, + value.to_field(), + comparator.unwrap_or(Comparator.EQ) + ) + ) + ); *self } // This method adds a `Sort` criterion to the options. // It takes a field_index indicating which field to sort by and an order (SortOrder) to determine the sorting direction. - pub fn sort(&mut self, field_index: u8, order: u8) -> Self { - self.sorts.push(Option::some(Sort::new(field_index, order))); + pub fn sort(&mut self, property_selector: PropertySelector, order: u8) -> Self { + self.sorts.push(Option::some(Sort::new(property_selector, order))); *self } diff --git a/aztec/src/note/note_interface.nr b/aztec/src/note/note_interface.nr index a663051f..3eaf10c0 100644 --- a/aztec/src/note/note_interface.nr +++ b/aztec/src/note/note_interface.nr @@ -3,22 +3,28 @@ use crate::note::note_header::NoteHeader; // docs:start:note_interface trait NoteInterface { + fn compute_nullifier(self, context: &mut PrivateContext) -> Field; + + fn compute_nullifier_without_context(self) -> Field; + + fn broadcast(self, context: &mut PrivateContext, slot: Field) -> (); + + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn serialize_content(self) -> [Field; N]; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn deserialize_content(fields: [Field; N]) -> Self; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn compute_note_content_hash(self) -> Field; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn get_header(self) -> NoteHeader; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn set_header(&mut self, header: NoteHeader) -> (); - fn compute_nullifier(self, context: &mut PrivateContext) -> Field; - - fn compute_nullifier_without_context(self) -> Field; - - fn broadcast(self, context: &mut PrivateContext, slot: Field) -> (); - + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn get_note_type_id() -> Field; } // docs:end:note_interface diff --git a/aztec/src/note/note_viewer_options.nr b/aztec/src/note/note_viewer_options.nr index 97496eb7..eeed1dda 100644 --- a/aztec/src/note/note_viewer_options.nr +++ b/aztec/src/note/note_viewer_options.nr @@ -1,5 +1,6 @@ -use crate::note::note_getter_options::{Select, Sort, Comparator, NoteStatus}; -use dep::protocol_types::{constants::MAX_NOTES_PER_PAGE}; +use dep::std::option::Option; +use crate::note::note_getter_options::{PropertySelector, Select, Sort, Comparator, NoteStatus}; +use dep::protocol_types::{constants::MAX_NOTES_PER_PAGE, traits::ToField}; use crate::note::note_interface::NoteInterface; // docs:start:NoteViewerOptions @@ -27,13 +28,26 @@ impl NoteViewerOptions { // It takes a field_index indicating which field to select, // a value representing the specific value to match in that field, and // a comparator (For possible values of comparators, please see the Comparator enum from note_getter_options) - pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { - self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); + pub fn select( + &mut self, + property_selector: PropertySelector, + value: T, + comparator: Option + ) -> Self where T: ToField { + self.selects.push( + Option::some( + Select::new( + property_selector, + value.to_field(), + comparator.unwrap_or(Comparator.EQ) + ) + ) + ); *self } - pub fn sort(&mut self, field_index: u8, order: u8) -> Self { - self.sorts.push(Option::some(Sort::new(field_index, order))); + pub fn sort(&mut self, property_selector: PropertySelector, order: u8) -> Self { + self.sorts.push(Option::some(Sort::new(property_selector, order))); *self } diff --git a/aztec/src/oracle/notes.nr b/aztec/src/oracle/notes.nr index cfad4710..50ee2367 100644 --- a/aztec/src/oracle/notes.nr +++ b/aztec/src/oracle/notes.nr @@ -30,10 +30,14 @@ unconstrained pub fn notify_nullified_note(nullifier: Field, inner_note_hash: fn get_notes_oracle( _storage_slot: Field, _num_selects: u8, - _select_by: [u8; N], + _select_by_indexes: [u8; N], + _select_by_offsets: [u8; N], + _select_by_lengths: [u8; N], _select_values: [Field; N], _select_comparators: [u8; N], - _sort_by: [u8; N], + _sort_by_indexes: [u8; N], + _sort_by_offsets: [u8; N], + _sort_by_lengths: [u8; N], _sort_order: [u8; N], _limit: u32, _offset: u32, @@ -45,10 +49,14 @@ fn get_notes_oracle( unconstrained fn get_notes_oracle_wrapper( storage_slot: Field, num_selects: u8, - select_by: [u8; N], + select_by_indexes: [u8; N], + select_by_offsets: [u8; N], + select_by_lengths: [u8; N], select_values: [Field; N], select_comparators: [u8; N], - sort_by: [u8; N], + sort_by_indexes: [u8; N], + sort_by_offsets: [u8; N], + sort_by_lengths: [u8; N], sort_order: [u8; N], limit: u32, offset: u32, @@ -59,10 +67,14 @@ unconstrained fn get_notes_oracle_wrapper( get_notes_oracle( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, limit, offset, @@ -75,10 +87,14 @@ unconstrained fn get_notes_oracle_wrapper( unconstrained pub fn get_notes( storage_slot: Field, num_selects: u8, - select_by: [u8; M], + select_by_indexes: [u8; M], + select_by_offsets: [u8; M], + select_by_lengths: [u8; M], select_values: [Field; M], select_comparators: [u8; M], - sort_by: [u8; M], + sort_by_indexes: [u8; M], + sort_by_offsets: [u8; M], + sort_by_lengths: [u8; M], sort_order: [u8; M], limit: u32, offset: u32, @@ -90,10 +106,14 @@ unconstrained pub fn get_notes( let fields = get_notes_oracle_wrapper( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, limit, offset, diff --git a/field-note/src/field_note.nr b/field-note/src/field_note.nr index 1f546596..f6350ddd 100644 --- a/field-note/src/field_note.nr +++ b/field-note/src/field_note.nr @@ -8,27 +8,12 @@ global FIELD_NOTE_LEN: Field = 1; // A note which stores a field and is expected to be passed around using the `addNote` function. // WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform serialized_note // attack on it. +#[aztec(note)] struct FieldNote { value: Field, - header: NoteHeader, } impl NoteInterface for FieldNote { - fn serialize_content(self) -> [Field; FIELD_NOTE_LEN]{ - [self.value] - } - - fn deserialize_content(serialized_note: [Field; FIELD_NOTE_LEN]) -> Self { - FieldNote { - value: serialized_note[0], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { // This note is expected to be shared between users and for this reason can't be nullified using a secret. @@ -40,25 +25,11 @@ impl NoteInterface for FieldNote { 0 } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - fn broadcast(self, context: &mut PrivateContext, slot: Field) { assert( false, "FieldNote does not support broadcast. Add it to PXE directly using the `.addNote` function." ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'FieldNote')))" - 7010510110810078111116101 - } } impl FieldNote { diff --git a/value-note/src/utils.nr b/value-note/src/utils.nr index 446a00c2..5cb4b75b 100644 --- a/value-note/src/utils.nr +++ b/value-note/src/utils.nr @@ -6,7 +6,7 @@ use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN // Sort the note values (0th field) in descending order. // Pick the fewest notes whose sum is equal to or greater than `amount`. pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteGetterOptions { - NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort(0, SortOrder.DESC) + NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort(ValueNote::properties().value, SortOrder.DESC) } // Creates a new note for the recipient. diff --git a/value-note/src/value_note.nr b/value-note/src/value_note.nr index f0d59d31..eb03acd2 100644 --- a/value-note/src/value_note.nr +++ b/value-note/src/value_note.nr @@ -8,33 +8,15 @@ use dep::aztec::{ global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. // docs:start:value-note-def +#[aztec(note)] struct ValueNote { value: Field, owner: AztecAddress, randomness: Field, - header: NoteHeader, } // docs:end:value-note-def impl NoteInterface for ValueNote { - fn serialize_content(self) -> [Field; VALUE_NOTE_LEN] { - [self.value, self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; VALUE_NOTE_LEN]) -> Self { - ValueNote { - value: serialized_note[0], - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(),0) - } - // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext) -> Field { @@ -61,14 +43,6 @@ impl NoteInterface for ValueNote { ],0) } - 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. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -81,12 +55,6 @@ impl NoteInterface for ValueNote { self.serialize_content(), ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'ValueNote')))" - 869710811710178111116101 - } } impl ValueNote {