Skip to content

Commit

Permalink
Merge pull request #134 from HerodotusDev/feat/debug_syscalls
Browse files Browse the repository at this point in the history
Adds debug prints to HDP modules
  • Loading branch information
petscheit authored Feb 3, 2025
2 parents 589a890 + 9217abf commit c5b02db
Show file tree
Hide file tree
Showing 18 changed files with 268 additions and 22 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ futures = "0.3.31"
hex = "0.4.3"
http-body-util = "=0.1.0"
indicatif = "0.17.9"
keccak = "0.1.5"
lazy_static = "1.5.0"
num-bigint = "0.4.6"
num-integer = "0.1.46"
num-traits = "0.2.19"
rand = "0.8"
reqwest = "0.12.9"
Expand All @@ -53,8 +56,6 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
utoipa = { version = "5.3.1", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "9", features = ["axum"] }
version-compare = "=0.0.11"
num-integer = "0.1.46"
keccak = "0.1.5"

dry_hint_processor = { path = "crates/dry_hint_processor" }
eth_essentials_cairo_vm_hints = { path = "packages/eth_essentials/cairo_vm_hints" }
Expand Down
24 changes: 16 additions & 8 deletions crates/dry_hint_processor/src/syscall_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use hints::vars;
use serde::{Deserialize, Serialize};
use starknet::CallContractHandler as StarknetCallContractHandler;
use syscall_handler::{
felt_from_ptr, keccak::KeccakHandler, run_handler, traits, SyscallExecutionError, SyscallResult, SyscallSelector, WriteResponseResult,
call_contract, call_contract::debug::DebugCallContractHandler, felt_from_ptr, keccak::KeccakHandler, run_handler, traits,
SyscallExecutionError, SyscallResult, SyscallSelector, WriteResponseResult,
};
use tokio::{sync::RwLock, task};
use types::{
Expand Down Expand Up @@ -80,6 +81,8 @@ impl SyscallHandlerWrapper {
pub struct CallContractHandlerRelay {
pub evm_call_contract_handler: EvmCallContractHandler,
pub starknet_call_contract_handler: StarknetCallContractHandler,
#[serde(skip)]
pub debug_call_contract_handler: DebugCallContractHandler,
}

impl traits::SyscallHandler for CallContractHandlerRelay {
Expand All @@ -93,13 +96,18 @@ impl traits::SyscallHandler for CallContractHandlerRelay {
}

async fn execute(&mut self, request: Self::Request, vm: &mut VirtualMachine) -> SyscallResult<Self::Response> {
let chain_id = <Felt252 as TryInto<u128>>::try_into(*vm.get_integer((request.calldata_start + 2)?)?)
.map_err(|e| SyscallExecutionError::InternalError(e.to_string().into()))?;

match chain_id {
ETHEREUM_MAINNET_CHAIN_ID | ETHEREUM_TESTNET_CHAIN_ID => self.evm_call_contract_handler.execute(request, vm).await,
STARKNET_MAINNET_CHAIN_ID | STARKNET_TESTNET_CHAIN_ID => self.starknet_call_contract_handler.execute(request, vm).await,
_ => Err(SyscallExecutionError::InternalError(Box::from("Unknown chain id"))),
match request.contract_address {
v if v == call_contract::debug::CONTRACT_ADDRESS => self.debug_call_contract_handler.execute(request, vm).await,
_ => {
let chain_id = <Felt252 as TryInto<u128>>::try_into(*vm.get_integer((request.calldata_start + 2)?)?)
.map_err(|e| SyscallExecutionError::InternalError(e.to_string().into()))?;

match chain_id {
ETHEREUM_MAINNET_CHAIN_ID | ETHEREUM_TESTNET_CHAIN_ID => self.evm_call_contract_handler.execute(request, vm).await,
STARKNET_MAINNET_CHAIN_ID | STARKNET_TESTNET_CHAIN_ID => self.starknet_call_contract_handler.execute(request, vm).await,
_ => Err(SyscallExecutionError::InternalError(Box::from("Unknown chain id"))),
}
}
}
}

Expand Down
25 changes: 17 additions & 8 deletions crates/sound_hint_processor/src/syscall_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use cairo_vm::{
use hints::vars;
use serde::{Deserialize, Serialize};
use syscall_handler::{
felt_from_ptr, keccak::KeccakHandler, run_handler, traits, SyscallExecutionError, SyscallResult, SyscallSelector, WriteResponseResult,
call_contract, call_contract::debug::DebugCallContractHandler, felt_from_ptr, keccak::KeccakHandler, run_handler, traits,
SyscallExecutionError, SyscallResult, SyscallSelector, WriteResponseResult,
};
use tokio::{sync::RwLock, task};
use types::{
Expand Down Expand Up @@ -85,13 +86,15 @@ impl CairoType for Memorizer {
pub struct CallContractHandlerRelay {
pub evm_call_contract_handler: EvmCallContractHandler,
pub starknet_call_contract_handler: StarknetCallContractHandler,
pub debug_call_contract_handler: DebugCallContractHandler,
}

impl CallContractHandlerRelay {
pub fn new(dict_manager: Rc<RefCell<DictManager>>) -> Self {
Self {
evm_call_contract_handler: EvmCallContractHandler::new(dict_manager.clone()),
starknet_call_contract_handler: StarknetCallContractHandler::new(dict_manager),
debug_call_contract_handler: DebugCallContractHandler,
}
}
}
Expand All @@ -107,13 +110,18 @@ impl traits::SyscallHandler for CallContractHandlerRelay {
}

async fn execute(&mut self, request: Self::Request, vm: &mut VirtualMachine) -> SyscallResult<Self::Response> {
let chain_id = <Felt252 as TryInto<u128>>::try_into(*vm.get_integer((request.calldata_start + 2)?)?)
.map_err(|e| SyscallExecutionError::InternalError(e.to_string().into()))?;

match chain_id {
ETHEREUM_MAINNET_CHAIN_ID | ETHEREUM_TESTNET_CHAIN_ID => self.evm_call_contract_handler.execute(request, vm).await,
STARKNET_MAINNET_CHAIN_ID | STARKNET_TESTNET_CHAIN_ID => self.starknet_call_contract_handler.execute(request, vm).await,
_ => Err(SyscallExecutionError::InternalError(Box::from("Unknown chain id"))),
match request.contract_address {
v if v == call_contract::debug::CONTRACT_ADDRESS => self.debug_call_contract_handler.execute(request, vm).await,
_ => {
let chain_id = <Felt252 as TryInto<u128>>::try_into(*vm.get_integer((request.calldata_start + 2)?)?)
.map_err(|e| SyscallExecutionError::InternalError(e.to_string().into()))?;

match chain_id {
ETHEREUM_MAINNET_CHAIN_ID | ETHEREUM_TESTNET_CHAIN_ID => self.evm_call_contract_handler.execute(request, vm).await,
STARKNET_MAINNET_CHAIN_ID | STARKNET_TESTNET_CHAIN_ID => self.starknet_call_contract_handler.execute(request, vm).await,
_ => Err(SyscallExecutionError::InternalError(Box::from("Unknown chain id"))),
}
}
}
}

Expand All @@ -129,6 +137,7 @@ pub struct SyscallHandler {
#[serde(skip)]
pub syscall_ptr: Option<Relocatable>,
pub call_contract_handler: CallContractHandlerRelay,
// pub debug_handler: DebugHandler,
#[serde(skip)]
pub keccak_handler: KeccakHandler,
}
Expand Down
9 changes: 5 additions & 4 deletions crates/syscall_handler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ edition = "2021"

[dependencies]
cairo-vm.workspace = true
thiserror.workspace = true
types.workspace = true
num-integer.workspace = true
keccak.workspace = true
num-bigint.workspace = true
num-integer.workspace = true
num-traits.workspace = true
serde.workspace = true
serde.workspace = true
strum_macros.workspace = true
thiserror.workspace = true
types.workspace = true
141 changes: 141 additions & 0 deletions crates/syscall_handler/src/call_contract/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use cairo_vm::{types::relocatable::Relocatable, vm::vm_core::VirtualMachine, Felt252};
use serde::{Deserialize, Serialize};
use strum_macros::FromRepr;
use types::cairo::{
new_syscalls::{CallContractRequest, CallContractResponse},
traits::CairoType,
};

use crate::{traits, SyscallExecutionError, SyscallResult, WriteResponseResult};

pub const CONTRACT_ADDRESS: Felt252 = Felt252::from_hex_unchecked("0x6465627567"); // 'debug' in hex

#[derive(FromRepr)]
pub enum CallHandlerId {
Print = 0,
PrintArray = 1,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct DebugCallContractHandler;

impl traits::SyscallHandler for DebugCallContractHandler {
type Request = CallContractRequest;
type Response = CallContractResponse;

fn read_request(&mut self, vm: &VirtualMachine, ptr: &mut Relocatable) -> SyscallResult<Self::Request> {
let ret = Self::Request::from_memory(vm, *ptr)?;
*ptr = (*ptr + Self::Request::cairo_size())?;
Ok(ret)
}

async fn execute(&mut self, request: Self::Request, vm: &mut VirtualMachine) -> SyscallResult<Self::Response> {
let call_handler_id = CallHandlerId::try_from(request.selector)?;
match call_handler_id {
CallHandlerId::Print => {
let field_len = (request.calldata_end - request.calldata_start)?;
let fields = vm
.get_integer_range(request.calldata_start, field_len)?
.into_iter()
.map(|f| (*f.as_ref()))
.collect::<Vec<Felt252>>();

let str = decode_byte_array_felts(fields);
println!("{}", str);
Ok(Self::Response {
retdata_start: request.calldata_end,
retdata_end: request.calldata_end,
})
}
CallHandlerId::PrintArray => {
let field_len = (request.calldata_end - request.calldata_start)?;
let fields = vm
.get_integer_range(request.calldata_start, field_len)?
.into_iter()
.map(|f| (*f.as_ref()))
.collect::<Vec<Felt252>>();

println!("{:?}", fields);

Ok(Self::Response {
retdata_start: request.calldata_end,
retdata_end: request.calldata_end,
})
}
}
}

fn write_response(&mut self, _response: Self::Response, _vm: &mut VirtualMachine, _ptr: &mut Relocatable) -> WriteResponseResult {
Ok(())
}
}

// Decodes a serialized byte array of felts into a ascii string
fn decode_byte_array_felts(felts: Vec<Felt252>) -> String {
// 1) Parse how many full 31-byte chunks we have.
let n_full: usize = felts[0].try_into().expect("n_full not convertible");

// 2) Read each 31-byte chunk in big-endian order.
let mut bytes = Vec::new();
for i in 0..n_full {
let chunk = &felts[1 + i];
let chunk_be: Vec<u8> = chunk.to_bytes_be().to_vec();

// Convert if chain to match
match chunk_be.len().cmp(&31) {
std::cmp::Ordering::Less => {
// Prepend leading zeros if needed
let mut padded = vec![0u8; 31 - chunk_be.len()];
padded.extend_from_slice(&chunk_be);
bytes.extend_from_slice(&padded);
}
std::cmp::Ordering::Greater => {
// If somehow bigger, take the last 31 bytes
bytes.extend_from_slice(&chunk_be[chunk_be.len() - 31..]);
}
std::cmp::Ordering::Equal => {
bytes.extend_from_slice(&chunk_be);
}
}
}

// 3) The next felt is the pending word, followed by the pending length.
let pending_word = &felts[1 + n_full];
let pending_len: usize = felts[1 + n_full + 1].try_into().unwrap();

if pending_len > 0 {
let pending_be: Vec<u8> = pending_word.to_bytes_be().to_vec();
// Convert if chain to match
match pending_be.len().cmp(&pending_len) {
std::cmp::Ordering::Less => {
// Again pad if needed
let mut padded = vec![0u8; pending_len - pending_be.len()];
padded.extend_from_slice(&pending_be);
bytes.extend_from_slice(&padded);
}
std::cmp::Ordering::Greater => {
bytes.extend_from_slice(&pending_be[pending_be.len() - pending_len..]);
}
std::cmp::Ordering::Equal => {
bytes.extend_from_slice(&pending_be);
}
}
}

// 4) Convert raw bytes to a UTF-8 string (or ASCII if you know it is ASCII).
String::from_utf8(bytes).expect("Invalid UTF-8")
}

impl TryFrom<Felt252> for CallHandlerId {
type Error = SyscallExecutionError;
fn try_from(value: Felt252) -> Result<Self, Self::Error> {
Self::from_repr(value.try_into().map_err(|e| Self::Error::InvalidSyscallInput {
input: value,
info: format!("{}", e),
})?)
.ok_or(Self::Error::InvalidSyscallInput {
input: value,
info: "Invalid function identifier".to_string(),
})
}
}
1 change: 1 addition & 0 deletions crates/syscall_handler/src/call_contract/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod debug;
1 change: 1 addition & 0 deletions crates/syscall_handler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![warn(unused_crate_dependencies)]
#![forbid(unsafe_code)]

pub mod call_contract;
pub mod keccak;
pub mod traits;

Expand Down
2 changes: 2 additions & 0 deletions hdp_cairo/src/debug.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod printer;
pub use printer::{print, print_array};
25 changes: 25 additions & 0 deletions hdp_cairo/src/debug/printer.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use starknet::syscalls::call_contract_syscall;
use starknet::SyscallResultTrait;
use core::fmt::Display;


const DEBUG_CONTRACT_ADDRESS: felt252 = 'debug';
const PRINT: felt252 = 0;
const PRINT_ARRAY: felt252 = 1;

pub fn print<T, +Display<T>, +Drop<T>>(value: T) {
let msg: ByteArray = format!("{}", value);
let mut output_array = array![];
msg.serialize(ref output_array);
call_contract_syscall(DEBUG_CONTRACT_ADDRESS.try_into().unwrap(), PRINT, output_array.span())
.unwrap_syscall();
}

pub fn print_array(array: Array<felt252>) {
call_contract_syscall(
DEBUG_CONTRACT_ADDRESS.try_into().unwrap(),
PRINT_ARRAY,
array.span()
)
.unwrap_syscall();
}
1 change: 1 addition & 0 deletions hdp_cairo/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod evm;
pub mod starknet;
pub mod debug;

#[derive(Serde, Drop)]
pub struct HDP {
Expand Down
5 changes: 5 additions & 0 deletions src/contract_bootloader/execute_syscalls.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ func execute_call_contract{
let state_access_type = request.contract_address;
let field = request.selector;

// Debug Contract does not need to be executed
if (request.contract_address == 'debug') {
return ();
}

let layout = chain_id_to_layout(request.calldata_start[2]);
let output_ptr = response.retdata_start;

Expand Down
1 change: 1 addition & 0 deletions tests/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod evm;
pub mod starknet;
pub mod utils;
3 changes: 3 additions & 0 deletions tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pub mod evm;
#[cfg(test)]
pub mod starknet;

#[cfg(test)]
pub mod utils;

#[cfg(test)]
mod test_utils {
use std::{env, path::PathBuf};
Expand Down
1 change: 1 addition & 0 deletions tests/src/utils.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod debug;
Loading

0 comments on commit c5b02db

Please sign in to comment.