1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
use assembly::ast::AstSerdeOptions;
use super::{Assembler, AssemblyContext, CodeBlock, Digest, NoteError, ProgramAst};
use crate::utils::serde::{
ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
};
// CONSTANTS
// ================================================================================================
/// Default serialization options for script code AST.
const CODE_SERDE_OPTIONS: AstSerdeOptions = AstSerdeOptions::new(true);
// NOTE SCRIPT
// ================================================================================================
/// An executable program of a note.
///
/// A note's script represents a program which must be executed for a note to be consumed. As such
/// it defines the rules and side effects of consuming a given note.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NoteScript {
hash: Digest,
code: ProgramAst,
}
impl NoteScript {
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------
/// Returns a new [NoteScript] instantiated from the provided program and compiled with the
/// provided assembler. The compiled code block is also returned.
///
/// # Errors
/// Returns an error if the compilation of the provided program fails.
pub fn new(code: ProgramAst, assembler: &Assembler) -> Result<(Self, CodeBlock), NoteError> {
let code_block = assembler
.compile_in_context(&code, &mut AssemblyContext::for_program(Some(&code)))
.map_err(NoteError::ScriptCompilationError)?;
Ok((Self { hash: code_block.hash(), code }, code_block))
}
/// Returns a new [NoteScript] instantiated from the provided components.
///
/// **Note**: this function assumes that the specified hash results from the compilation of the
/// provided program, but this is not checked.
pub fn from_parts(code: ProgramAst, hash: Digest) -> Self {
Self { code, hash }
}
// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------
/// Returns MAST root of this note script.
pub fn hash(&self) -> Digest {
self.hash
}
/// Returns the AST of this note script.
pub fn code(&self) -> &ProgramAst {
&self.code
}
}
// SERIALIZATION
// ================================================================================================
impl Serializable for NoteScript {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.hash.write_into(target);
self.code.write_into(target, CODE_SERDE_OPTIONS);
}
}
impl Deserializable for NoteScript {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let hash = Digest::read_from(source)?;
let code = ProgramAst::read_from(source)?;
Ok(Self::from_parts(code, hash))
}
}