Skip to content

Commit

Permalink
refactor(katana-messaging): remove message execution and fix hashing (#…
Browse files Browse the repository at this point in the history
…2884)

* refactor: remove the hash functionnality to only have conventional messaging

* fix: use poseidon for appchain message hash computation

* fix: match piltover message hash computation

* tests: update tests db
  • Loading branch information
glihm authored Jan 9, 2025
1 parent 7718099 commit 1829ce5
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 248 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.

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

0 comments on commit 1829ce5

Please sign in to comment.