Skip to content

Commit

Permalink
restore cairo1-run
Browse files Browse the repository at this point in the history
  • Loading branch information
Pedro Fontana authored and Pedro Fontana committed Feb 9, 2024
1 parent 9cce025 commit ac35900
Show file tree
Hide file tree
Showing 2 changed files with 240 additions and 317 deletions.
318 changes: 1 addition & 317 deletions cairo1-run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,323 +323,7 @@ fn main() -> Result<(), Error> {
}
}

#[allow(clippy::type_complexity)]
fn build_hints_vec<'b>(
instructions: impl Iterator<Item = &'b Instruction>,
) -> (Vec<(usize, Vec<Hint>)>, HashMap<usize, Vec<HintParams>>) {
let mut hints: Vec<(usize, Vec<Hint>)> = Vec::new();
let mut program_hints: HashMap<usize, Vec<HintParams>> = HashMap::new();

let mut hint_offset = 0;

for instruction in instructions {
if !instruction.hints.is_empty() {
hints.push((hint_offset, instruction.hints.clone()));
program_hints.insert(
hint_offset,
vec![HintParams {
code: hint_offset.to_string(),
accessible_scopes: Vec::new(),
flow_tracking_data: FlowTrackingData {
ap_tracking: ApTracking::default(),
reference_ids: HashMap::new(),
},
}],
);
}
hint_offset += instruction.body.op_size();
}
(hints, program_hints)
}

/// Finds first function ending with `name_suffix`.
fn find_function<'a>(
sierra_program: &'a SierraProgram,
name_suffix: &'a str,
) -> Result<&'a Function, RunnerError> {
sierra_program
.funcs
.iter()
.find(|f| {
if let Some(name) = &f.id.debug_name {
name.ends_with(name_suffix)
} else {
false
}
})
.ok_or_else(|| RunnerError::MissingMain)
}

/// Creates a list of instructions that will be appended to the program's bytecode.
fn create_code_footer() -> Vec<Instruction> {
casm! {
// Add a `ret` instruction used in libfuncs that retrieve the current value of the `fp`
// and `pc` registers.
ret;
}
.instructions
}

/// Returns the instructions to add to the beginning of the code to successfully call the main
/// function, as well as the builtins required to execute the program.
fn create_entry_code(
sierra_program_registry: &ProgramRegistry<CoreType, CoreLibfunc>,
casm_program: &CairoProgram,
type_sizes: &UnorderedHashMap<ConcreteTypeId, i16>,
func: &Function,
initial_gas: usize,
proof_mode: bool,
args: &Vec<FuncArg>,
) -> Result<(Vec<Instruction>, Vec<BuiltinName>), Error> {
let mut ctx = casm! {};
// The builtins in the formatting expected by the runner.
let (builtins, builtin_offset) = get_function_builtins(func, proof_mode);

// Load all vecs to memory.
// Load all array args content to memory.
let mut array_args_data = vec![];
let mut ap_offset: i16 = 0;
for arg in args {
let FuncArg::Array(values) = arg else {
continue;
};
array_args_data.push(ap_offset);
casm_extend! {ctx,
%{ memory[ap + 0] = segments.add() %}
ap += 1;
}
for (i, v) in values.iter().enumerate() {
let arr_at = (i + 1) as i16;
casm_extend! {ctx,
[ap + 0] = (v.to_bigint());
[ap + 0] = [[ap - arr_at] + (i as i16)], ap++;
};
}
ap_offset += (1 + values.len()) as i16;
}
let mut array_args_data_iter = array_args_data.iter();
let after_arrays_data_offset = ap_offset;
let mut arg_iter = args.iter().enumerate();
let mut param_index = 0;
let mut expected_arguments_size = 0;
if func.signature.param_types.iter().any(|ty| {
get_info(sierra_program_registry, ty)
.map(|x| x.long_id.generic_id == SegmentArenaType::ID)
.unwrap_or_default()
}) {
casm_extend! {ctx,
// SegmentArena segment.
%{ memory[ap + 0] = segments.add() %}
// Infos segment.
%{ memory[ap + 1] = segments.add() %}
ap += 2;
[ap + 0] = 0, ap++;
// Write Infos segment, n_constructed (0), and n_destructed (0) to the segment.
[ap - 2] = [[ap - 3]];
[ap - 1] = [[ap - 3] + 1];
[ap - 1] = [[ap - 3] + 2];
}
ap_offset += 3;
}
for ty in func.signature.param_types.iter() {
let info = get_info(sierra_program_registry, ty)
.ok_or_else(|| Error::NoInfoForType(ty.clone()))?;
let generic_ty = &info.long_id.generic_id;
if let Some(offset) = builtin_offset.get(generic_ty) {
let mut offset = *offset;
if proof_mode {
// Everything is off by 2 due to the proof mode header
offset += 2;
}
casm_extend! {ctx,
[ap + 0] = [fp - offset], ap++;
}
ap_offset += 1;
} else if generic_ty == &SystemType::ID {
casm_extend! {ctx,
%{ memory[ap + 0] = segments.add() %}
ap += 1;
}
ap_offset += 1;
} else if generic_ty == &GasBuiltinType::ID {
casm_extend! {ctx,
[ap + 0] = initial_gas, ap++;
}
ap_offset += 1;
} else if generic_ty == &SegmentArenaType::ID {
let offset = -ap_offset + after_arrays_data_offset;
casm_extend! {ctx,
[ap + 0] = [ap + offset] + 3, ap++;
}
ap_offset += 1;
} else {
let ty_size = type_sizes[ty];
let param_ap_offset_end = ap_offset + ty_size;
expected_arguments_size += ty_size;
while ap_offset < param_ap_offset_end {
let Some((arg_index, arg)) = arg_iter.next() else {
break;
};
match arg {
FuncArg::Single(value) => {
casm_extend! {ctx,
[ap + 0] = (value.to_bigint()), ap++;
}
ap_offset += 1;
}
FuncArg::Array(values) => {
let offset = -ap_offset + array_args_data_iter.next().unwrap();
casm_extend! {ctx,
[ap + 0] = [ap + (offset)], ap++;
[ap + 0] = [ap - 1] + (values.len()), ap++;
}
ap_offset += 2;
if ap_offset > param_ap_offset_end {
return Err(Error::ArgumentUnaligned {
param_index,
arg_index,
});
}
}
}
}
param_index += 1;
};
}
let actual_args_size = args
.iter()
.map(|arg| match arg {
FuncArg::Single(_) => 1,
FuncArg::Array(_) => 2,
})
.sum::<i16>();
if expected_arguments_size != actual_args_size {
return Err(Error::ArgumentsSizeMismatch {
expected: expected_arguments_size,
actual: actual_args_size,
});
}

let before_final_call = ctx.current_code_offset;
let final_call_size = 3;
let offset = final_call_size
+ casm_program.debug_info.sierra_statement_info[func.entry_point.0].code_offset;

casm_extend! {ctx,
call rel offset;
ret;
}
assert_eq!(before_final_call + final_call_size, ctx.current_code_offset);

Ok((ctx.instructions, builtins))
}

fn get_info<'a>(
sierra_program_registry: &'a ProgramRegistry<CoreType, CoreLibfunc>,
ty: &'a cairo_lang_sierra::ids::ConcreteTypeId,
) -> Option<&'a cairo_lang_sierra::extensions::types::TypeInfo> {
sierra_program_registry
.get_type(ty)
.ok()
.map(|ctc| ctc.info())
}

/// Creates the metadata required for a Sierra program lowering to casm.
fn create_metadata(
sierra_program: &cairo_lang_sierra::program::Program,
metadata_config: Option<MetadataComputationConfig>,
) -> Result<Metadata, VirtualMachineError> {
if let Some(metadata_config) = metadata_config {
calc_metadata(sierra_program, metadata_config).map_err(|err| match err {
MetadataError::ApChangeError(_) => VirtualMachineError::Unexpected,
MetadataError::CostError(_) => VirtualMachineError::Unexpected,
})
} else {
Ok(Metadata {
ap_change_info: calc_ap_changes(sierra_program, |_, _| 0)
.map_err(|_| VirtualMachineError::Unexpected)?,
gas_info: GasInfo {
variable_values: Default::default(),
function_costs: Default::default(),
},
})
}
}

/// Type representing the Output builtin.
#[derive(Default)]
pub struct OutputType {}
impl cairo_lang_sierra::extensions::NoGenericArgsGenericType for OutputType {
const ID: cairo_lang_sierra::ids::GenericTypeId =
cairo_lang_sierra::ids::GenericTypeId::new_inline("Output");
const STORABLE: bool = true;
const DUPLICATABLE: bool = false;
const DROPPABLE: bool = false;
const ZERO_SIZED: bool = false;
}

fn get_function_builtins(
func: &Function,
proof_mode: bool,
) -> (
Vec<BuiltinName>,
HashMap<cairo_lang_sierra::ids::GenericTypeId, i16>,
) {
let entry_params = &func.signature.param_types;
let mut builtins = Vec::new();
let mut builtin_offset: HashMap<cairo_lang_sierra::ids::GenericTypeId, i16> = HashMap::new();
let mut current_offset = 3;
// Fetch builtins from the entry_params in the standard order
if entry_params
.iter()
.any(|ti| ti.debug_name == Some("Poseidon".into()))
{
builtins.push(BuiltinName::poseidon);
builtin_offset.insert(PoseidonType::ID, current_offset);
current_offset += 1;
}
if entry_params
.iter()
.any(|ti| ti.debug_name == Some("EcOp".into()))
{
builtins.push(BuiltinName::ec_op);
builtin_offset.insert(EcOpType::ID, current_offset);
current_offset += 1
}
if entry_params
.iter()
.any(|ti| ti.debug_name == Some("Bitwise".into()))
{
builtins.push(BuiltinName::bitwise);
builtin_offset.insert(BitwiseType::ID, current_offset);
current_offset += 1;
}
if entry_params
.iter()
.any(|ti| ti.debug_name == Some("RangeCheck".into()))
{
builtins.push(BuiltinName::range_check);
builtin_offset.insert(RangeCheckType::ID, current_offset);
current_offset += 1;
}
if entry_params
.iter()
.any(|ti| ti.debug_name == Some("Pedersen".into()))
{
builtins.push(BuiltinName::pedersen);
builtin_offset.insert(PedersenType::ID, current_offset);
current_offset += 1;
}
// Force an output builtin so that we can write the program output into it's segment
if proof_mode {
builtins.push(BuiltinName::output);
builtin_offset.insert(OutputType::ID, current_offset);
}
builtins.reverse();
(builtins, builtin_offset)
}

fn serialize_output(vm: &VirtualMachine, return_values: &[MaybeRelocatable]) -> String {
pub fn serialize_output(vm: &VirtualMachine, return_values: &[MaybeRelocatable]) -> String {
let mut output_string = String::new();
let mut return_values_iter: Peekable<Iter<MaybeRelocatable>> = return_values.iter().peekable();
serialize_output_inner(&mut return_values_iter, &mut output_string, vm);
Expand Down
Loading

0 comments on commit ac35900

Please sign in to comment.