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

refactor(katana-messaging): remove message execution and fix hashing #2884

Merged
merged 5 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
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.

102 changes: 39 additions & 63 deletions crates/katana/contracts/messaging/cairo/src/appchain_messaging.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,6 @@
//! listen for those events. When an event with a message is gathered
//! by katana, a L1 handler transaction is then created and added to the pool.
//!
//! For the appchain to send a message to starknet, the process can be done in two
//! fashions:
//!
//! 1. The appchain register messages hashes exactly as starknet does. And then
//! a transaction on starknet must be issued to consume the message.
//!
//! 2. The sequencer (katana in that case) has also the capability of directly send
//! send a transaction to "execute" the content of the message. In the appchain
//! context this is a very effective manner to have a more dynamic and real-time
//! messaging than manual consuming of a message.
//!

/// Trait for Appchain messaging. For now, the messaging only whitelist one
/// appchain.
Expand Down Expand Up @@ -46,17 +35,6 @@ trait IAppchainMessaging<T> {
fn consume_message_from_appchain(
ref self: T, from_address: starknet::ContractAddress, payload: Span<felt252>,
) -> felt252;

/// Executes a message sent from the appchain. A message to execute
/// does not need to be registered as consumable. It is automatically
/// consumed while executed.
fn execute_message_from_appchain(
ref self: T,
from_address: starknet::ContractAddress,
to_address: starknet::ContractAddress,
selector: felt252,
payload: Span<felt252>,
);
}

#[starknet::interface]
Expand All @@ -76,7 +54,7 @@ mod appchain_messaging {
// Owner of this contract.
owner: ContractAddress,
// The account on Starknet (or the chain where this contract is deployed)
// used by the appchain sequencer to register messages hashes / execute messages.
// used by the appchain sequencer to register messages hashes.
appchain_account: ContractAddress,
// The nonce for messages sent from Starknet.
sn_to_appc_nonce: felt252,
Expand All @@ -93,7 +71,6 @@ mod appchain_messaging {
MessageSentToAppchain: MessageSentToAppchain,
MessagesRegisteredFromAppchain: MessagesRegisteredFromAppchain,
MessageConsumed: MessageConsumed,
MessageExecuted: MessageExecuted,
Upgraded: Upgraded,
}

Expand Down Expand Up @@ -126,17 +103,6 @@ mod appchain_messaging {
payload: Span<felt252>,
}

#[derive(Drop, starknet::Event)]
struct MessageExecuted {
#[key]
from_address: ContractAddress,
#[key]
to_address: ContractAddress,
#[key]
selector: felt252,
payload: Span<felt252>,
}

#[derive(Drop, starknet::Event)]
struct Upgraded {
class_hash: ClassHash,
Expand Down Expand Up @@ -171,8 +137,19 @@ mod appchain_messaging {
hash.try_into().expect('starknet keccak overflow')
}

/// Computes message hash to consume messages from appchain.
/// starknet_keccak(from_address, to_address, payload_len, payload).
/// Computes the hash of a message that is sent from the Appchain to Starknet.
///
/// <https://github.com/starkware-libs/cairo-lang/blob/caba294d82eeeccc3d86a158adb8ba209bf2d8fc/src/starkware/starknet/solidity/StarknetMessaging.sol#L137>
///
/// # Arguments
///
/// * `from_address` - Contract address of the message sender on the Appchain.
/// * `to_address` - Contract address to send the message to on the Appchain.
/// * `payload` - The message payload.
///
/// # Returns
///
/// The hash of the message from the Appchain to Starknet.
fn compute_hash_appc_to_sn(
from_address: ContractAddress, to_address: ContractAddress, payload: Span<felt252>
) -> felt252 {
Expand All @@ -192,12 +169,32 @@ mod appchain_messaging {
starknet_keccak(hash_data.span())
}

/// Computes message hash to send messages to appchain.
/// starknet_keccak(nonce, to_address, selector, payload).
/// Computes the hash of a message that is sent from Starknet to the Appchain.
///
/// <https://github.com/starkware-libs/cairo-lang/blob/caba294d82eeeccc3d86a158adb8ba209bf2d8fc/src/starkware/starknet/solidity/StarknetMessaging.sol#L88>
///
/// # Arguments
///
/// * `from_address` - Contract address of the message sender on the Appchain.
/// * `to_address` - Contract address to send the message to on the Appchain.
/// * `selector` - The `l1_handler` function selector of the contract on the Appchain
/// to execute.
/// * `payload` - The message payload.
/// * `nonce` - Nonce of the message.
///
/// # Returns
///
/// The hash of the message from Starknet to the Appchain.
fn compute_hash_sn_to_appc(
nonce: felt252, to_address: ContractAddress, selector: felt252, payload: Span<felt252>
from_address: ContractAddress,
to_address: ContractAddress,
selector: felt252,
payload: Span<felt252>,
nonce: felt252
) -> felt252 {
let mut hash_data = array![nonce, to_address.into(), selector,];
let mut hash_data = array![
from_address.into(), to_address.into(), nonce, selector, payload.len().into(),
];

let mut i = 0_usize;
loop {
Expand All @@ -208,7 +205,7 @@ mod appchain_messaging {
i += 1;
};

starknet_keccak(hash_data.span())
core::poseidon::poseidon_hash_span(hash_data.span())
}

#[abi(embed_v0)]
Expand Down Expand Up @@ -308,26 +305,5 @@ mod appchain_messaging {

msg_hash
}

fn execute_message_from_appchain(
ref self: ContractState,
from_address: ContractAddress,
to_address: ContractAddress,
selector: felt252,
payload: Span<felt252>,
) {
assert(
self.appchain_account.read() == starknet::get_caller_address(),
'Unauthorized executor',
);

match starknet::call_contract_syscall(to_address, selector, payload) {
Result::Ok(_) => self
.emit(MessageExecuted { from_address, to_address, selector, payload, }),
Result::Err(e) => {
panic(e)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
//! This contract can sends messages using the send message to l1
//! syscall as we normally do for messaging.
//!
//! If the message contains a `to_address` that is not zero, the message
//! hash will be sent to starknet to be registered.
//! If the `to_address` is zero, then the message will then fire a transaction
//! on the starknet to directly execute the message content.
//! However, the `to_address` is set to the `MSG` magic value since
//! this field is restricted to a valid Ethereum address, too small to
//! be a valid Starknet address.
use starknet::ContractAddress;

#[starknet::interface]
Expand All @@ -21,20 +20,6 @@ trait IContractAppchain<T> {
/// * `to_address` - Contract address on Starknet.
/// * `value` - Value to be sent in the payload.
fn send_message(ref self: T, to_address: ContractAddress, value: felt252);

/// Executes a message on Starknet. When the Katana will see this message
/// with `to_address` set to 0, an invoke transaction will be fired.
/// So basically this function can invoke any contract on Starknet, the fees on starknet
/// being paid by the sequencer. We can here imagine several scenarios. :)
/// The invoke though is not directly done to the destination contract, but the
/// app messaging contract that will forward the execution.
///
/// # Arguments
///
/// * `to_address` - Contract address on Starknet.
/// * `selector` - Selector.
/// * `value` - Value to be sent as argument to the contract being executed on starknet.
fn execute_message(ref self: T, to_address: ContractAddress, selector: felt252, value: felt252);
}

#[starknet::contract]
Expand Down Expand Up @@ -67,12 +52,5 @@ mod contract_msg_starknet {
let buf: Array<felt252> = array![to_address.into(), value];
starknet::send_message_to_l1_syscall('MSG', buf.span()).unwrap_syscall();
}

fn execute_message(
ref self: ContractState, to_address: ContractAddress, selector: felt252, value: felt252,
) {
let buf: Array<felt252> = array![to_address.into(), selector, value];
starknet::send_message_to_l1_syscall('EXE', buf.span()).unwrap_syscall();
}
}
}
1 change: 1 addition & 0 deletions crates/katana/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
starknet.workspace = true
starknet-crypto.workspace = true
starknet-types-core.workspace = true
thiserror.workspace = true
tokio.workspace = true
Expand Down
14 changes: 11 additions & 3 deletions crates/katana/core/src/service/messaging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use katana_executor::ExecutorFactory;
use katana_primitives::chain::ChainId;
use katana_primitives::receipt::MessageToL1;
use serde::{Deserialize, Serialize};
use tracing::{error, info};
use tracing::{error, info, trace};

pub use self::service::{MessagingOutcome, MessagingService};
#[cfg(feature = "starknet-messaging")]
Expand Down Expand Up @@ -229,11 +229,19 @@ impl<EF: ExecutorFactory> Future for MessagingTask<EF> {
while let Poll::Ready(Some(outcome)) = this.messaging.poll_next_unpin(cx) {
match outcome {
MessagingOutcome::Gather { msg_count, .. } => {
info!(target: LOG_TARGET, %msg_count, "Collected messages from settlement chain.");
if msg_count > 0 {
info!(target: LOG_TARGET, %msg_count, "Collected messages from settlement chain.");
}

trace!(target: LOG_TARGET, %msg_count, "Collected messages from settlement chain.");
}

MessagingOutcome::Send { msg_count, .. } => {
info!(target: LOG_TARGET, %msg_count, "Sent messages to the settlement chain.");
if msg_count > 0 {
info!(target: LOG_TARGET, %msg_count, "Sent messages to the settlement chain.");
}

trace!(target: LOG_TARGET, %msg_count, "Sent messages to the settlement chain.");
}
}
}
Expand Down
22 changes: 0 additions & 22 deletions crates/katana/core/src/service/messaging/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,33 +265,11 @@ fn interval_from_seconds(secs: u64) -> Interval {
fn trace_msg_to_l1_sent(messages: &[MessageToL1], hashes: &[String]) {
assert_eq!(messages.len(), hashes.len());

#[cfg(feature = "starknet-messaging")]
let hash_exec_str = format!("{:#064x}", super::starknet::HASH_EXEC);

for (i, m) in messages.iter().enumerate() {
let payload_str: Vec<String> = m.payload.iter().map(|f| format!("{:#x}", *f)).collect();

let hash = &hashes[i];

#[cfg(feature = "starknet-messaging")]
if hash == &hash_exec_str {
let to_address = &payload_str[0];
let selector = &payload_str[1];
let payload_str = &payload_str[2..];

#[rustfmt::skip]
info!(
target: LOG_TARGET,
from_address = %m.from_address,
to_address = %to_address,
selector = %selector,
payload = %payload_str.join(", "),
"Message executed on settlement layer.",
);

continue;
}

// We check for magic value 'MSG' used only when we are doing L3-L2 messaging.
let (to_address, payload_str) = if format!("{}", m.to_address) == "0x4d5347" {
(payload_str[0].clone(), &payload_str[1..])
Expand Down
Loading
Loading