miden_agglayer/update_ger_note.rs
1//! UPDATE_GER note creation utilities.
2//!
3//! This module provides helpers for creating UPDATE_GER notes,
4//! which are used to update the Global Exit Root in the bridge account.
5
6extern crate alloc;
7
8use alloc::string::ToString;
9use alloc::vec;
10
11use miden_assembly::Library;
12use miden_assembly::serde::Deserializable;
13use miden_protocol::account::AccountId;
14use miden_protocol::crypto::rand::FeltRng;
15use miden_protocol::errors::NoteError;
16use miden_protocol::note::{
17 Note,
18 NoteAssets,
19 NoteAttachment,
20 NoteAttachments,
21 NoteRecipient,
22 NoteScript,
23 NoteScriptRoot,
24 NoteStorage,
25 NoteType,
26 PartialNoteMetadata,
27};
28use miden_standards::note::{NetworkAccountTarget, NoteExecutionHint};
29use miden_utils_sync::LazyLock;
30
31use crate::ExitRoot;
32
33// NOTE SCRIPT
34// ================================================================================================
35
36// Initialize the UPDATE_GER note script only once
37static UPDATE_GER_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
38 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/update_ger.masl"));
39 let library =
40 Library::read_from_bytes(bytes).expect("shipped UPDATE_GER script library is well-formed");
41 NoteScript::from_library(&library).expect("shipped UPDATE_GER script is well-formed")
42});
43
44// UPDATE_GER NOTE
45// ================================================================================================
46
47/// UPDATE_GER note.
48///
49/// This note is used to update the Global Exit Root (GER) in the bridge account.
50/// It carries the new GER data and is always public.
51pub struct UpdateGerNote;
52
53impl UpdateGerNote {
54 // CONSTANTS
55 // --------------------------------------------------------------------------------------------
56
57 /// Expected number of storage items for an UPDATE_GER note.
58 pub const NUM_STORAGE_ITEMS: usize = 8;
59
60 // PUBLIC ACCESSORS
61 // --------------------------------------------------------------------------------------------
62
63 /// Returns the UPDATE_GER note script.
64 pub fn script() -> NoteScript {
65 UPDATE_GER_SCRIPT.clone()
66 }
67
68 /// Returns the UPDATE_GER note script root.
69 pub fn script_root() -> NoteScriptRoot {
70 UPDATE_GER_SCRIPT.root()
71 }
72
73 // BUILDERS
74 // --------------------------------------------------------------------------------------------
75
76 /// Creates an UPDATE_GER note with the given GER (Global Exit Root) data.
77 ///
78 /// The note storage contains 8 felts: GER[0..7]
79 ///
80 /// # Parameters
81 /// - `ger`: The Global Exit Root data
82 /// - `sender_account_id`: The account ID of the note creator
83 /// - `target_account_id`: The account ID that will consume this note (bridge account)
84 /// - `rng`: Random number generator for creating the note serial number
85 ///
86 /// # Errors
87 /// Returns an error if note creation fails.
88 pub fn create<R: FeltRng>(
89 ger: ExitRoot,
90 sender_account_id: AccountId,
91 target_account_id: AccountId,
92 rng: &mut R,
93 ) -> Result<Note, NoteError> {
94 // Create note storage with 8 felts: GER[0..7]
95 let storage_values = ger.to_elements().to_vec();
96
97 let note_storage = NoteStorage::new(storage_values)?;
98
99 // Generate a serial number for the note
100 let serial_num = rng.draw_word();
101
102 let recipient = NoteRecipient::new(serial_num, Self::script(), note_storage);
103
104 let attachment = NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always)
105 .map_err(|e| NoteError::other(e.to_string()))?;
106 let attachments = NoteAttachments::from(NoteAttachment::from(attachment));
107 let metadata = PartialNoteMetadata::new(sender_account_id, NoteType::Public);
108
109 // UPDATE_GER notes don't carry assets
110 let assets = NoteAssets::new(vec![])?;
111
112 Ok(Note::with_attachments(assets, metadata, recipient, attachments))
113 }
114}