Skip to content

Commit

Permalink
implement block_info_hint (#26)
Browse files Browse the repository at this point in the history
* implement block_info_hint

* fmt

* fix clippy

* fix comments

* use poetry

* rm useless fields in hint processor
  • Loading branch information
tcoratger authored Sep 16, 2024
1 parent 2b566ae commit 7fc4dd8
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

13 changes: 1 addition & 12 deletions cairo_programs/get_env.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,7 @@ func get_env() -> Environment* {
tempvar env = cast(nondet %{ segments.add() %}, Environment*);
// The hint should populate env.
%{
ids.env.origin=1
ids.env.gas_price=2
ids.env.chain_id=3
ids.env.prev_randao.low=4
ids.env.prev_randao.high=4
ids.env.block_number=5
ids.env.block_gas_limit=6
ids.env.block_timestamp=7
ids.env.coinbase=8
ids.env.base_fee=9
%}
%{ block_info %}

return env;
}
Expand Down
4 changes: 2 additions & 2 deletions cairo_programs/get_env.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"attributes": [],
"builtins": ["output"],
"compiler_version": "0.13.1",
"compiler_version": "0.13.2",
"data": [
"0x40780017fff7fff",
"0x1",
Expand Down Expand Up @@ -56,7 +56,7 @@
"8": [
{
"accessible_scopes": ["__main__", "__main__.get_env"],
"code": "ids.env.origin=1\nids.env.gas_price=2\nids.env.chain_id=3\nids.env.prev_randao.low=4\nids.env.prev_randao.high=4\nids.env.block_number=5\nids.env.block_gas_limit=6\nids.env.block_timestamp=7\nids.env.coinbase=8\nids.env.base_fee=9",
"code": "block_info",
"flow_tracking_data": {
"ap_tracking": {
"group": 2,
Expand Down
11 changes: 6 additions & 5 deletions crates/exex/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use reth_node_api::{ConfigureEvm, ConfigureEvmEnv};
use reth_node_ethereum::EthEvmConfig;
use reth_primitives::{
revm_primitives::{CfgEnvWithHandlerCfg, EVMError, ExecutionResult, ResultAndState},
Address, Block, BlockWithSenders, EthereumHardfork, Header, Receipt, SealedBlockWithSenders,
TransactionSigned, U256,
Block, BlockWithSenders, EthereumHardfork, Header, Receipt, SealedBlockWithSenders,
TransactionSigned, TransactionSignedEcRecovered, U256,
};
use reth_revm::{
db::{states::bundle_state::BundleRetention, BundleState},
Expand All @@ -18,7 +18,7 @@ use reth_tracing::tracing::debug;
pub async fn execute_block(
db: &mut Database,
block: &SealedBlockWithSenders,
txs: Vec<(TransactionSigned, Address)>,
txs: Vec<TransactionSignedEcRecovered>,
) -> eyre::Result<(BlockWithSenders, BundleState, Vec<Receipt>, Vec<ExecutionResult>)> {
// Extract the header from the provided block.
let header = block.header();
Expand Down Expand Up @@ -81,7 +81,7 @@ pub fn configure_evm<'a>(
pub fn execute_transactions(
evm: &mut Evm<'_, (), StateDBBox<'_, eyre::Report>>,
header: &Header,
transactions: Vec<(TransactionSigned, Address)>,
transactions: Vec<TransactionSignedEcRecovered>,
) -> eyre::Result<(Vec<TransactionSigned>, Vec<Receipt>, Vec<ExecutionResult>)> {
// Initializationof vectors and variables
let mut receipts = Vec::with_capacity(transactions.len());
Expand All @@ -90,7 +90,8 @@ pub fn execute_transactions(
let mut cumulative_gas_used = 0;

// Iterates through each transaction and sender in the list.
for (transaction, sender) in transactions {
for transaction in transactions {
let (transaction, sender) = transaction.to_components();
// Calculates the available gas in the block after previous transactions.
let block_available_gas = header.gas_limit - cumulative_gas_used;
// Ensures that the current transaction does not exceed the block's available gas.
Expand Down
86 changes: 82 additions & 4 deletions crates/exex/src/exex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use reth_chainspec::{ChainSpec, ChainSpecBuilder};
use reth_execution_types::Chain;
use reth_exex::{ExExContext, ExExEvent};
use reth_node_api::FullNodeComponents;
use reth_primitives::{Address, Genesis};
use reth_primitives::{Address, Genesis, SealedBlock, TransactionSignedEcRecovered};
use reth_tracing::tracing::{error, info};
use rusqlite::Connection;
use std::{path::PathBuf, sync::Arc};
Expand Down Expand Up @@ -137,7 +137,12 @@ impl<Node: FullNodeComponents> KakarotRollup<Node> {
.iter()
.map(|tx| {
tx.recover_signer()
.map(|sender| (tx.clone(), sender))
.map(|sender| {
TransactionSignedEcRecovered::from_signed_transaction(
tx.clone(),
sender,
)
})
.ok_or_else(|| eyre::eyre!("failed to recover signer"))
})
.collect::<eyre::Result<Vec<_>>>()
Expand All @@ -148,10 +153,16 @@ impl<Node: FullNodeComponents> KakarotRollup<Node> {
// Process each block and its transactions.
for (block, txs, _) in blocks {
// Execute the block and handle the result.
match execute_block(&mut self.db, block, txs).await {
match execute_block(&mut self.db, block, txs.clone()).await {
Ok((block, bundle, _, _)) => {
// Seal the block and insert it into the database.
// Seal the block.
let block = block.seal_slow();
// After the block is executed, we want to run the get_env program
//
// The goal is to store in a Cairo program, via hint, all the information about
// the block
self.execute_get_env(block.block.clone(), txs, chain.tip().number)?;
// Insert the block into the database.
self.db.insert_block_with_bundle(&block, bundle)?;
info!(
block_hash = %block.hash(),
Expand Down Expand Up @@ -185,6 +196,73 @@ impl<Node: FullNodeComponents> KakarotRollup<Node> {
) -> eyre::Result<()> {
self.db.insert_execution_trace(number, trace, memory, air_public_input, air_private_input)
}

/// Executes the Cairo program to retrieve and process the environment (block and transaction)
/// data.
///
/// This function takes a sealed block and a list of signed transactions, executes a Cairo
/// program to retrieve environment data via a hint.
fn execute_get_env(
&mut self,
block: SealedBlock,
txs: Vec<TransactionSignedEcRecovered>,
chain_tip: u64,
) -> eyre::Result<()> {
// Initialize the Cairo runtime configuration with various settings.
let config = CairoRunConfig {
layout: LayoutName::all_cairo,
trace_enabled: true,
relocate_mem: true,
proof_mode: true,
allow_missing_builtins: Some(false), // Ensures no missing built-in hints are allowed.
..Default::default()
};

// Loop through each transaction in the block to run the Cairo program.
for tx in &txs {
// Create the Kakarot hint processor with the block and transaction context.
let mut hint_processor = KakarotHintProcessor::default()
.with_block_and_transaction(block.clone(), tx.clone())
.build();

// Load the toy Cairo program from the file.
let program = std::fs::read(PathBuf::from("../../cairo_programs/get_env.json"))?;

// Execute the Cairo program with the specified configuration and hint processor.
//
// This runs the Cairo VM to test our hint processor and the associated Cairo program.
let mut res = cairo_run(&program, &config, &mut hint_processor)?;

// As we use the output builtin, we can print the block information to the console.
let mut output_buffer = String::new();
res.vm.write_output(&mut output_buffer).unwrap();
println!("Block information: \n{}", output_buffer);

// Extract the execution trace from the result.
let trace = res.relocated_trace.clone().unwrap_or_default();

// Extract the relocated memory from the VM execution result.
let memory =
res.relocated_memory.clone().into_iter().map(|x| x.unwrap_or_default()).collect();

// Retrieve the public and private inputs from the program execution.
let public_input = res.get_air_public_input()?;
let private_input = res.get_air_private_input();

// Store the execution trace, relocated memory, and inputs in the database.
//
// These will be used later to verify the execution and generate proofs.
self.commit_cairo_execution_traces(
chain_tip, // The current chain tip.
trace, // The extracted execution trace.
memory, // The relocated memory.
public_input, // The public input for proving.
private_input, // The private input for proving.
)?;
}

Ok(())
}
}

#[cfg(test)]
Expand Down
97 changes: 93 additions & 4 deletions crates/exex/src/hints.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use crate::{db::Database, exex::DATABASE_PATH};
use cairo_vm::{
hint_processor::{
builtin_hint_processor::builtin_hint_processor_definition::{
BuiltinHintProcessor, HintFunc,
builtin_hint_processor::{
builtin_hint_processor_definition::{BuiltinHintProcessor, HintFunc},
hint_utils::get_ptr_from_var_name,
memcpy_hint_utils::add_segment,
},
hint_processor_definition::HintReference,
},
serde::deserialize_program::ApTracking,
types::exec_scope::ExecutionScopes,
types::{exec_scope::ExecutionScopes, relocatable::MaybeRelocatable},
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
Felt252,
};
use reth_primitives::{SealedBlock, TransactionSignedEcRecovered};
use rusqlite::Connection;
use std::{collections::HashMap, fmt, rc::Rc};

Expand All @@ -32,7 +35,7 @@ impl fmt::Debug for KakarotHintProcessor {

impl Default for KakarotHintProcessor {
fn default() -> Self {
Self::new_empty().with_hint(print_tx_hint())
Self::new_empty().with_hint(print_tx_hint()).with_hint(add_segment_hint())
}
}

Expand All @@ -50,6 +53,18 @@ impl KakarotHintProcessor {
self
}

/// Adds a block to the [`KakarotHintProcessor`].
///
/// This method allows you to register a block by providing a [`SealedBlockWithSenders`]
/// instance.
pub fn with_block_and_transaction(
self,
block: SealedBlock,
transaction: TransactionSignedEcRecovered,
) -> Self {
self.with_hint(block_info_hint(block, transaction))
}

/// Returns the underlying [`BuiltinHintProcessor`].
///
/// This allows the processor to be used elsewhere.
Expand Down Expand Up @@ -128,3 +143,77 @@ pub fn print_tx_hint() -> Hint {
},
)
}

/// Generates a hint to store block information in the `Environment` model.
pub fn block_info_hint(block: SealedBlock, transaction: TransactionSignedEcRecovered) -> Hint {
Hint::new(
String::from("block_info"),
move |vm: &mut VirtualMachine,
_exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
_constants: &HashMap<String, Felt252>|
-> Result<(), HintError> {
// We retrieve the `env` pointer from the `ids_data` hashmap.
// This pointer is used to store the block-related values in the VM.
let env_ptr = get_ptr_from_var_name("env", vm, ids_data, ap_tracking)?;

// We load the block-related values into the VM.
//
// The values are loaded in the order they are defined in the `Environment` model.
// We start at the `env` pointer.
let _ = vm
.load_data(
env_ptr,
&[
MaybeRelocatable::from(Felt252::from_bytes_be_slice(
&transaction.signer().0 .0,
)),
MaybeRelocatable::from(Felt252::from(
transaction.effective_gas_price(block.base_fee_per_gas),
)),
MaybeRelocatable::from(Felt252::from(
transaction.chain_id().unwrap_or_default(),
)),
MaybeRelocatable::from(Felt252::from_bytes_be_slice(
&block.mix_hash.0[16..],
)),
MaybeRelocatable::from(Felt252::from_bytes_be_slice(
&block.mix_hash.0[0..16],
)),
MaybeRelocatable::from(Felt252::from(block.number)),
MaybeRelocatable::from(Felt252::from(block.gas_limit)),
MaybeRelocatable::from(Felt252::from(block.timestamp)),
MaybeRelocatable::from(Felt252::from_bytes_be_slice(
&block.beneficiary.0 .0,
)),
MaybeRelocatable::from(Felt252::from(
block.base_fee_per_gas.unwrap_or_default(),
)),
],
)
.map_err(HintError::Memory)?;

Ok(())
},
)
}

/// Generates a hint to add a new memory segment.
///
/// This function adds a hint to the `HintProcessor` that creates a new memory segment in the
/// virtual machine. It maps the current memory pointer (`ap`) to the newly added segment.
pub fn add_segment_hint() -> Hint {
Hint::new(
String::from("memory[ap] = to_felt_or_relocatable(segments.add())"),
|vm: &mut VirtualMachine,
_exec_scopes: &mut ExecutionScopes,
_ids_data: &HashMap<String, HintReference>,
_ap_tracking: &ApTracking,
_constants: &HashMap<String, Felt252>|
-> Result<(), HintError> {
// Calls the function to add a new memory segment to the VM.
add_segment(vm)
},
)
}

0 comments on commit 7fc4dd8

Please sign in to comment.