use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use miden_objects::account::AccountId;
use miden_objects::assembly::debuginfo::{SourceLanguage, SourceManagerSync, Uri};
use miden_objects::assembly::{DefaultSourceManager, Library};
use miden_objects::asset::Asset;
use miden_objects::note::{
Note,
NoteAssets,
NoteExecutionHint,
NoteInputs,
NoteMetadata,
NoteRecipient,
NoteScript,
NoteTag,
NoteType,
};
use miden_objects::testing::note::DEFAULT_NOTE_CODE;
use miden_objects::{Felt, NoteError, Word, ZERO};
use rand::Rng;
use crate::transaction::TransactionKernel;
#[derive(Debug, Clone)]
pub struct NoteBuilder {
sender: AccountId,
inputs: Vec<Felt>,
assets: Vec<Asset>,
note_type: NoteType,
note_execution_hint: NoteExecutionHint,
serial_num: Word,
tag: NoteTag,
code: String,
aux: Felt,
dyn_libraries: Vec<Library>,
source_manager: Arc<dyn SourceManagerSync>,
}
impl NoteBuilder {
pub fn new<T: Rng>(sender: AccountId, mut rng: T) -> Self {
let serial_num = Word::from([
Felt::new(rng.random()),
Felt::new(rng.random()),
Felt::new(rng.random()),
Felt::new(rng.random()),
]);
Self {
sender,
inputs: vec![],
assets: vec![],
note_type: NoteType::Public,
note_execution_hint: NoteExecutionHint::None,
serial_num,
tag: NoteTag::from_account_id(sender),
code: DEFAULT_NOTE_CODE.to_string(),
aux: ZERO,
dyn_libraries: Vec::new(),
source_manager: Arc::new(DefaultSourceManager::default()),
}
}
pub fn note_inputs(
mut self,
inputs: impl IntoIterator<Item = Felt>,
) -> Result<Self, NoteError> {
let validate = NoteInputs::new(inputs.into_iter().collect())?;
self.inputs = validate.into();
Ok(self)
}
pub fn add_assets(mut self, assets: impl IntoIterator<Item = Asset>) -> Self {
self.assets.extend(assets);
self
}
pub fn note_execution_hint(mut self, note_execution_hint: NoteExecutionHint) -> Self {
self.note_execution_hint = note_execution_hint;
self
}
pub fn tag(mut self, tag: u32) -> Self {
self.tag = tag.into();
self
}
pub fn note_type(mut self, note_type: NoteType) -> Self {
self.note_type = note_type;
self
}
pub fn code<S: AsRef<str>>(mut self, code: S) -> Self {
self.code = code.as_ref().to_string();
self
}
pub fn serial_number(mut self, serial_number: Word) -> Self {
self.serial_num = serial_number;
self
}
pub fn aux(mut self, aux: Felt) -> Self {
self.aux = aux;
self
}
pub fn dynamically_linked_libraries(
mut self,
dyn_libraries: impl IntoIterator<Item = Library>,
) -> Self {
self.dyn_libraries.extend(dyn_libraries);
self
}
pub fn source_manager(mut self, source_manager: Arc<dyn SourceManagerSync>) -> Self {
self.source_manager = source_manager;
self
}
pub fn build(self) -> Result<Note, NoteError> {
let virtual_source_file = self.source_manager.load(
SourceLanguage::Masm,
Uri::new(format!(
"note_{:x}{:x}",
self.serial_num[0].as_int(),
self.serial_num[1].as_int()
)),
self.code,
);
let mut assembler = TransactionKernel::assembler_with_source_manager(self.source_manager)
.with_debug_mode(true);
for dyn_library in self.dyn_libraries {
assembler
.link_dynamic_library(dyn_library)
.expect("library should link successfully");
}
let code = assembler
.clone()
.with_debug_mode(true)
.assemble_program(virtual_source_file)
.unwrap();
let note_script = NoteScript::new(code);
let vault = NoteAssets::new(self.assets)?;
let metadata = NoteMetadata::new(
self.sender,
self.note_type,
self.tag,
self.note_execution_hint,
self.aux,
)?;
let inputs = NoteInputs::new(self.inputs)?;
let recipient = NoteRecipient::new(self.serial_num, note_script, inputs);
Ok(Note::new(vault, metadata, recipient))
}
}