Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: load_hints #6

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ thiserror-no-std = "2.0.2"
assert_matches = "1.5.0"
rstest = "0.19.0"

[patch."https://github.com/lambdaclass/cairo-vm"]
cairo-vm = { path = "../cairo-vm/vm" }
12 changes: 9 additions & 3 deletions src/hints/execute_task_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::HashMap;
use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{
get_ptr_from_var_name, get_relocatable_from_var_name, insert_value_from_var_name,
};
use cairo_vm::hint_processor::hint_processor_definition::HintReference;
use cairo_vm::hint_processor::hint_processor_definition::{HintExtension, HintReference};
use cairo_vm::serde::deserialize_program::{ApTracking, Identifier};
use cairo_vm::types::builtin_name::BuiltinName;
use cairo_vm::types::exec_scope::ExecutionScopes;
Expand Down Expand Up @@ -70,7 +70,7 @@ pub fn load_program_hint(
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
) -> Result<HintExtension, HintError> {
let program_data_base: Relocatable = exec_scopes.get(vars::PROGRAM_DATA_BASE)?;
let task: Task = exec_scopes.get(vars::TASK)?;
let program = get_program_from_task(&task)?;
Expand All @@ -85,6 +85,12 @@ pub fn load_program_hint(
.load_program(program_header_ptr, &program, Some(bootloader_version))
.map_err(Into::<HintError>::into)?;

// if task is a Program, attempt to load hints from it
let mut hint_extension = HintExtension::new();
if let Task::Program(program) = task {
hint_extension.extend(program_loader.load_hints(&program, program_header_ptr, ap_tracking)?);
}

vm.segments.finalize(
Some(loaded_program.size),
program_data_base.segment_index as usize,
Expand All @@ -93,7 +99,7 @@ pub fn load_program_hint(

exec_scopes.insert_value(vars::PROGRAM_ADDRESS, loaded_program.code_address);

Ok(())
Ok(hint_extension)
}

/// Implements
Expand Down
24 changes: 23 additions & 1 deletion src/hints/hint_processors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ impl HintProcessorLogic for MinimalBootloaderHintProcessor {
EXECUTE_TASK_ALLOCATE_PROGRAM_DATA_SEGMENT => {
allocate_program_data_segment(vm, exec_scopes, ids_data, ap_tracking)
}
EXECUTE_TASK_LOAD_PROGRAM => load_program_hint(vm, exec_scopes, ids_data, ap_tracking),
EXECUTE_TASK_VALIDATE_HASH => validate_hash(vm, exec_scopes, ids_data, ap_tracking),
EXECUTE_TASK_ASSERT_PROGRAM_ADDRESS => {
assert_program_address(vm, exec_scopes, ids_data, ap_tracking)
Expand All @@ -131,6 +130,29 @@ impl HintProcessorLogic for MinimalBootloaderHintProcessor {
)),
}
}

/// Executes extensive hints as appropriate, then falls back to non-extensive hints.
fn execute_hint_extensive(
&mut self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
hint_data_any: &Box<dyn Any>,
constants: &HashMap<String, Felt252>,
) -> Result<HintExtension, HintError> {
let hint_data = hint_data_any
.downcast_ref::<HintProcessorData>()
.ok_or(HintError::WrongHintData)?;

let ids_data = &hint_data.ids_data;
let ap_tracking = &hint_data.ap_tracking;

let mut hint_extensions = HintExtension::default();
match hint_data.code.as_str() {
EXECUTE_TASK_LOAD_PROGRAM => hint_extensions.extend(load_program_hint(vm, exec_scopes, ids_data, ap_tracking)?),
_ => self.execute_hint(vm, exec_scopes, hint_data_any, constants)?,
}
Ok(hint_extensions)
}
}

impl ResourceTracker for MinimalBootloaderHintProcessor {}
Expand Down
57 changes: 56 additions & 1 deletion src/hints/program_loader.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use std::collections::HashMap;

use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{BuiltinHintProcessor, HintProcessorData};
use cairo_vm::hint_processor::hint_processor_definition::{HintExtension, HintProcessorLogic};
use cairo_vm::serde::deserialize_program::ApTracking;
use cairo_vm::types::builtin_name::BuiltinName;
use cairo_vm::types::errors::math_errors::MathError;
use cairo_vm::types::program::Program;
use cairo_vm::types::relocatable::Relocatable;
use cairo_vm::vm::errors::hint_errors::HintError;
use cairo_vm::vm::errors::memory_errors::MemoryError;
use cairo_vm::vm::runners::cairo_pie::StrippedProgram;
use cairo_vm::vm::vm_core::VirtualMachine;
use cairo_vm::Felt252;
use cairo_vm::{any_box, Felt252};

use crate::hints::types::BootloaderVersion;

Expand Down Expand Up @@ -161,6 +167,54 @@ impl<'vm> ProgramLoader<'vm> {
size: header_size + program.data.len(),
})
}

/// Extracts and relocates the hints found in the given program and returns the result in a way
/// that is suitable to be used in cairo-vm's "extensive hints" feature.
pub fn load_hints(
&self,
program: &Program,
program_base: Relocatable,
ap_tracking: &ApTracking,
) -> Result<HintExtension, ProgramLoaderError> {
// TODO: these structs are private (pub(crate))
let hints_collection = program.shared_program_data.hints_collection;
let mut hint_extension = HintExtension::new();
for (pc, hint_range) in hints_collection.hints_ranges {
let relocated_pc = pc + program_base;
let hint_code = "FIXME"; // TODO
let hint_processor_data = HintProcessorData {
code: hint_code.to_string(),
ap_tracking: ap_tracking.clone(),
ids_data: Default::default(), // TODO
};
// TODO: more expressive way to do this
if !hint_extension.contains_key(relocated_pc) {
hint_extension.insert(relocated_pc.clone(), Vec::new());
}
hint_extension
.get(relocated_pc)
.expect("value inserted if missing abev, QED")
.push(any_box!(hint_processor_data));
}

// TODO: we ultimately want these remapped_hints to be part of the hints map used during
// execution, and it should use the extensive hints feature added in
// https://github.com/lambdaclass/cairo-vm/pull/1491
//
// this could either work with self.vm directly (?) or could return something that is used
// by the caller to initialize the hint processor.
// cairo-lang's load_hints works differently: it is called from load_program and stores
// the remapped results as a private member for later use. (our load_program() takes a
// StrippedProgram instead of a Program which makes this pattern impossible currently)
//
// Note: we are already in a hint (by nature of not being in cairo code), so we can use the hint extension
// feature of blockifier (where a hint returns the hint extensions), so that just means we need to
// propagate the remapped hints back to to caller until we return from a hint

// load program hint is where we are

Ok(hint_extension)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -312,6 +366,7 @@ mod tests {

#[rstest]
fn test_load_program(fibonacci: Program) {

let program = fibonacci.get_stripped_program().unwrap();

let mut vm = VirtualMachine::new(false);
Expand Down
Loading