Skip to content

Commit

Permalink
self.signer, self.caller, and block.height
Browse files Browse the repository at this point in the history
  • Loading branch information
mikebenfield committed Nov 18, 2024
1 parent 01f3127 commit 0a68aa4
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 12 deletions.
66 changes: 61 additions & 5 deletions interpreter/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ use leo_ast::{
Variant,
};
use leo_errors::{InterpreterHalt, Result};
use leo_span::{Span, Symbol};
use leo_span::{Span, Symbol, sym};

use snarkvm::prelude::{
CastLossy as _,
Double as _,
Inverse as _,
Network as _,
Pow as _,
ProgramID,
Square as _,
SquareRoot as _,
TestnetV0,
Expand All @@ -51,12 +52,13 @@ use snarkvm::prelude::{
use indexmap::IndexSet;
use rand::Rng as _;
use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
use std::{cmp::Ordering, collections::HashMap, fmt, mem};
use std::{cmp::Ordering, collections::HashMap, fmt, mem, str::FromStr as _};

/// Names associated to values in a function being executed.
#[derive(Clone, Debug)]
struct FunctionContext {
program: Symbol,
caller: SvmAddress,
names: HashMap<Symbol, Value>,
accumulated_futures: Future,
is_async: bool,
Expand All @@ -74,17 +76,19 @@ impl ContextStack {
self.current_len
}

fn push(&mut self, program: Symbol, is_async: bool) {
fn push(&mut self, program: Symbol, caller: SvmAddress, is_async: bool) {
if self.current_len == self.contexts.len() {
self.contexts.push(FunctionContext {
program,
caller,
names: HashMap::new(),
accumulated_futures: Default::default(),
is_async,
});
}
self.contexts[self.current_len].accumulated_futures.0.clear();
self.contexts[self.current_len].names.clear();
self.contexts[self.current_len].caller = caller;
self.contexts[self.current_len].program = program;
self.contexts[self.current_len].is_async = is_async;
self.current_len += 1;
Expand Down Expand Up @@ -223,14 +227,18 @@ pub struct Cursor<'a> {

pub contexts: ContextStack,

signer: SvmAddress,

rng: ChaCha20Rng,

block_height: u32,

really_async: bool,
}

impl<'a> Cursor<'a> {
/// `really_async` indicates we should really delay execution of async function calls until the user runs them.
pub fn new(really_async: bool) -> Self {
pub fn new(really_async: bool, signer: SvmAddress, block_height: u32) -> Self {
Cursor {
frames: Default::default(),
values: Default::default(),
Expand All @@ -241,6 +249,8 @@ impl<'a> Cursor<'a> {
contexts: Default::default(),
futures: Default::default(),
rng: ChaCha20Rng::from_entropy(),
signer,
block_height,
really_async,
}
}
Expand Down Expand Up @@ -582,6 +592,40 @@ impl<'a> Cursor<'a> {
CoreConstant::GroupGenerator => Some(Value::generator()),
}
}
Expression::Access(AccessExpression::Member(access)) => match &*access.inner {
Expression::Identifier(identifier) if identifier.name == sym::SelfLower => match access.name.name {
sym::signer => Some(Value::Address(self.signer)),
sym::caller => {
if let Some(function_context) = self.contexts.last() {
Some(Value::Address(function_context.caller))
} else {
Some(Value::Address(self.signer))
}
}
_ => halt!(access.span(), "unknown member of self"),
},
Expression::Identifier(identifier) if identifier.name == sym::block => match access.name.name {
sym::height => Some(Value::U32(self.block_height)),
_ => halt!(access.span(), "unknown member of block"),
},

// Otherwise, we just have a normal struct member access.
_ if step == 0 => {
push!()(&*access.inner);
None
}
_ if step == 1 => {
let Some(Value::Struct(struct_)) = self.values.pop() else {
tc_fail!();
};
let value = struct_.contents.get(&access.name.name).cloned();
if value.is_none() {
tc_fail!();
}
value
}
_ => unreachable!("we've actually covered all possible patterns above"),
},
Expression::Access(AccessExpression::AssociatedFunction(function)) if step == 0 => {
let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
tc_fail!();
Expand Down Expand Up @@ -1704,7 +1748,18 @@ impl<'a> Cursor<'a> {
self.values.push(Value::Future(Future(vec![async_ex])));
} else {
let is_async = function.variant == Variant::AsyncFunction;
self.contexts.push(program, is_async);
let caller = if matches!(function.variant, Variant::Transition | Variant::AsyncTransition) {
if let Some(function_context) = self.contexts.last() {
let program_id = ProgramID::<TestnetV0>::from_str(&format!("{}", function_context.program))
.expect("should be able to create ProgramID");
program_id.to_address().expect("should be able to convert to address")
} else {
self.signer
}
} else {
self.signer
};
self.contexts.push(program, caller, is_async);
let param_names = function.input.iter().map(|input| input.identifier.name);
for (name, value) in param_names.zip(values_iter) {
self.contexts.set(name, value);
Expand Down Expand Up @@ -1874,6 +1929,7 @@ impl<'a> Cursor<'a> {
let values_iter = self.values.drain(len - function.input.len()..);
self.contexts.push(
gid.program,
self.signer,
true, // is_async
);
let param_names = function.input.iter().map(|input| input.identifier.name);
Expand Down
16 changes: 11 additions & 5 deletions interpreter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,12 @@ enum InterpreterAction {
}

impl Interpreter {
fn new<'a, P: 'a + AsRef<Path>>(source_files: impl IntoIterator<Item = &'a P>) -> Result<Self> {
Self::new_impl(&mut source_files.into_iter().map(|p| p.as_ref()))
fn new<'a, P: 'a + AsRef<Path>>(
source_files: impl IntoIterator<Item = &'a P>,
signer: SvmAddress,
block_height: u32,
) -> Result<Self> {
Self::new_impl(&mut source_files.into_iter().map(|p| p.as_ref()), signer, block_height)
}

fn get_ast(path: &Path, handler: &Handler, node_builder: &NodeBuilder) -> Result<Ast> {
Expand All @@ -79,11 +83,13 @@ impl Interpreter {
leo_parser::parse_ast::<TestnetV0>(handler, node_builder, &text, source_file.start_pos)
}

fn new_impl(source_files: &mut dyn Iterator<Item = &Path>) -> Result<Self> {
fn new_impl(source_files: &mut dyn Iterator<Item = &Path>, signer: SvmAddress, block_height: u32) -> Result<Self> {
let handler = Handler::default();
let node_builder = Default::default();
let mut cursor: Cursor<'_> = Cursor::new(
true, // really_async
signer,
block_height,
);
let mut filename_to_program = HashMap::new();
for path in source_files {
Expand Down Expand Up @@ -390,8 +396,8 @@ fn kill_span_expression(expression: &mut Expression) {

/// Load all the Leo source files indicated and open the interpreter
/// to commands from the user.
pub fn interpret(filenames: &[PathBuf]) -> Result<()> {
let mut interpreter = Interpreter::new(filenames.iter())?;
pub fn interpret(filenames: &[PathBuf], signer: SvmAddress, block_height: u32) -> Result<()> {
let mut interpreter = Interpreter::new(filenames.iter(), signer, block_height)?;
let mut buffer = String::new();
println!("{}", INSTRUCTIONS);
loop {
Expand Down
2 changes: 1 addition & 1 deletion interpreter/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use std::{
str::FromStr as _,
};

type SvmAddress = SvmAddressParam<TestnetV0>;
pub type SvmAddress = SvmAddressParam<TestnetV0>;
type SvmBoolean = SvmBooleanParam<TestnetV0>;
type SvmField = SvmFieldParam<TestnetV0>;
type SvmGroup = SvmGroupParam<TestnetV0>;
Expand Down
9 changes: 8 additions & 1 deletion leo/cli/commands/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ use super::*;
/// Debugs an Aleo program through the interpreter.
#[derive(Parser, Debug)]
pub struct LeoDebug {
#[arg(long, help = "The block height, accessible via block.height.", default_value = "0")]
pub(crate) block_height: u32,

#[clap(flatten)]
pub(crate) compiler_options: BuildOptions,
}
Expand Down Expand Up @@ -76,6 +79,10 @@ fn handle_debug<N: Network>(command: &LeoDebug, context: Context) -> Result<()>
let manifest = Manifest::read_from_dir(&package_path)?;
let program_id = ProgramID::<N>::from_str(manifest.program())?;

// Get the private key.
let private_key = context.get_private_key(&None)?;
let address = Address::try_from(&private_key)?;

// Retrieve all local dependencies in post order
let main_sym = Symbol::intern(&program_id.name().to_string());
let mut retriever = Retriever::<N>::new(
Expand All @@ -99,5 +106,5 @@ fn handle_debug<N: Network>(command: &LeoDebug, context: Context) -> Result<()>
})
.collect();

leo_interpreter::interpret(&paths)
leo_interpreter::interpret(&paths, address, command.block_height)
}

0 comments on commit 0a68aa4

Please sign in to comment.