diff --git a/src/kernel_sequencer/Cargo.lock b/src/kernel_sequencer/Cargo.lock index 8cf1fc043b1952fda413e93f6f1e744f8a14d989..ec9b9d95b25b33bd6587ae5b7f5187a9d9049a50 100644 --- a/src/kernel_sequencer/Cargo.lock +++ b/src/kernel_sequencer/Cargo.lock @@ -346,11 +346,14 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" name = "kernel-sequencer" version = "0.1.0" dependencies = [ + "nom", "tezos-smart-rollup-core", "tezos-smart-rollup-encoding", "tezos-smart-rollup-host", "tezos-smart-rollup-mock", "tezos_crypto_rs", + "tezos_data_encoding", + "tezos_data_encoding_derive", ] [[package]] diff --git a/src/kernel_sequencer/Cargo.toml b/src/kernel_sequencer/Cargo.toml index df8606dadd14aa0dd5df6015bff757a51a3000ac..6a9a8784a239f0ca32fb1d8d436aaa98c46607b5 100644 --- a/src/kernel_sequencer/Cargo.toml +++ b/src/kernel_sequencer/Cargo.toml @@ -25,7 +25,20 @@ version = "0.2.0" path = "../kernel_sdk/mock" version = "0.2.0" -[dev-dependencies.tezos-smart-rollup-encoding] +[dependencies.tezos_data_encoding] +version = "0.5" + +[dependencies.tezos_data_encoding_derive] +version = "0.5" + +[dependencies.nom] +version = "7.1" + +[dependencies.tezos_crypto_rs] +version = "0.5.0" +default-features = false + +[dependencies.tezos-smart-rollup-encoding] path = "../kernel_sdk/encoding" version = "0.2.0" diff --git a/src/kernel_sequencer/src/delayed_inbox.rs b/src/kernel_sequencer/src/delayed_inbox.rs index 43a3c1f3ae2ee9ac4ff9c9650ed27d942f537c3a..c545cda2befdaeb026c88fc7da5ef056718df0bc 100644 --- a/src/kernel_sequencer/src/delayed_inbox.rs +++ b/src/kernel_sequencer/src/delayed_inbox.rs @@ -3,13 +3,18 @@ // // SPDX-License-Identifier: MIT +use tezos_data_encoding::nom::NomReader; +use tezos_smart_rollup_encoding::smart_rollup::SmartRollupAddress; use tezos_smart_rollup_host::{ input::Message, - metadata::RollupMetadata, + metadata::{RollupMetadata, RAW_ROLLUP_ADDRESS_SIZE}, runtime::{Runtime, RuntimeError}, }; -use crate::routing::FilterBehavior; +use crate::{ + message::{Framed, KernelMessage, Sequence, SequencerMsg, SetSequencer}, + routing::FilterBehavior, +}; /// Return a message from the inbox /// @@ -30,10 +35,61 @@ pub fn read_input( None => return Ok(None), // No more messages to be processed Some(msg) => { let payload = msg.as_ref(); - if filter_behavior.predicate(payload, &raw_rollup_address) { - return Ok(Some(msg)); // The message is needed by the kernel so it's returned + let message = KernelMessage::nom_read(payload); + match message { + Err(_) => {} + Ok((_, message)) => match message { + KernelMessage::Sequencer(Framed { + destination, + payload: SequencerMsg::Sequence(sequence), + }) => handle_sequence_message(sequence, destination, &raw_rollup_address), + KernelMessage::Sequencer(Framed { + destination, + payload: SequencerMsg::SetSequencer(set_sequence), + }) => handle_set_sequencer_message( + set_sequence, + destination, + &raw_rollup_address, + ), + KernelMessage::DelayedMessage(user_message) => { + handle_message(user_message, filter_behavior, &raw_rollup_address) + } + }, } } } } } + +/// Handle Sequence message +fn handle_sequence_message( + _sequence: Sequence, + destination: SmartRollupAddress, + rollup_address: &[u8; RAW_ROLLUP_ADDRESS_SIZE], +) { + if destination.hash().as_ref() == rollup_address { + // process the sequence + } +} + +fn handle_set_sequencer_message( + _set_sequencer: SetSequencer, + destination: SmartRollupAddress, + rollup_address: &[u8; RAW_ROLLUP_ADDRESS_SIZE], +) { + if destination.hash().as_ref() == rollup_address { + // process the set sequencer message + } +} + +/// Handle messages +fn handle_message( + user_message: Vec, + filter_behavior: FilterBehavior, + rollup_address: &[u8; RAW_ROLLUP_ADDRESS_SIZE], +) { + // Check if the message should be included in the delayed inbox + if filter_behavior.predicate(user_message.as_ref(), rollup_address) { + // add the message to the delayed inbox + } +} diff --git a/src/kernel_sequencer/src/lib.rs b/src/kernel_sequencer/src/lib.rs index d3dbac3fdb126bd47f42b3c895bfedca90c04546..1ed998f3d2c3471d688cc36b4685e64516b956ee 100644 --- a/src/kernel_sequencer/src/lib.rs +++ b/src/kernel_sequencer/src/lib.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MIT mod delayed_inbox; +mod message; pub mod routing; mod sequencer_macro; pub mod sequencer_runtime; diff --git a/src/kernel_sequencer/src/message.rs b/src/kernel_sequencer/src/message.rs new file mode 100644 index 0000000000000000000000000000000000000000..18e96a878090225413b16c0af80dc280ed4a4fe9 --- /dev/null +++ b/src/kernel_sequencer/src/message.rs @@ -0,0 +1,269 @@ +// SPDX-FileCopyrightText: 2023 Marigold +// +// SPDX-License-Identifier: MIT + +use nom::{ + branch::alt, + bytes::complete::tag, + combinator::{all_consuming, map}, + sequence::preceded, +}; +use tezos_crypto_rs::hash::Signature; +use tezos_data_encoding::{ + enc::{self, BinResult, BinWriter}, + nom::{NomReader, NomResult}, +}; +use tezos_smart_rollup_encoding::public_key::PublicKey; +use tezos_smart_rollup_encoding::smart_rollup::SmartRollupAddress; + +/// Framing protocol v0 +/// +/// The framing protocol starts with a 0, then the address of the rollup, then the message +/// The message should start by a tag, provided by the Tag trait +/// +/// [0x00, smart rollup address, tag, message] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Framed

{ + pub destination: SmartRollupAddress, + pub payload: P, +} + +/// Messages sent by the user to the sequencer +#[derive(NomReader, BinWriter, Clone, Debug, PartialEq, Eq)] +pub struct Bytes { + #[encoding(dynamic, list)] + inner: Vec, +} + +/// Sequence of messages sent by the sequencer +/// +/// The sequence contains the number of messages +/// that should be processed from the delayed inbox +/// and the messages from the sequencer +/// +/// The delayed messages will be processed first +/// And then the messages will be processed +#[derive(NomReader, BinWriter, Clone, Debug, PartialEq, Eq)] +pub struct Sequence { + nonce: u32, + delayed_messages: u32, + #[encoding(dynamic, list)] + messages: Vec, + signature: Signature, +} + +/// Message to set the appropriate sequencer +/// +/// This message should be sent by the admin public key +/// This admin key should sign the new sequencer public key +#[derive(NomReader, BinWriter, Clone, Debug, PartialEq, Eq)] +pub struct SetSequencer { + nonce: u32, + admin_public_key: PublicKey, + sequencer_public_key: PublicKey, + signature: Signature, +} + +#[derive(NomReader, BinWriter, Debug, Clone, Eq, PartialEq)] +pub enum SequencerMsg { + Sequence(Sequence), + SetSequencer(SetSequencer), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum KernelMessage { + Sequencer(Framed), + DelayedMessage(Vec), +} + +impl

NomReader for Framed

+where + P: NomReader, +{ + fn nom_read(input: &[u8]) -> NomResult { + // Extract the rollup address from the framing protocol + // 0x00 is the version of the framing protocol + let (input, destination) = preceded(tag([0]), SmartRollupAddress::nom_read)(input)?; + + // Extract the payload + let (remaining, payload) = P::nom_read(input)?; + + Ok(( + remaining, + Framed { + destination, + payload, + }, + )) + } +} + +impl

BinWriter for Framed

+where + P: BinWriter, +{ + fn bin_write(&self, output: &mut Vec) -> BinResult { + // bytes of the framing protocol + // 0x00 is the version of the framing protocol + enc::put_byte(&0x00, output); + + // bytes of the rollup address + self.destination.bin_write(output)?; + + // bytes of the payload + self.payload.bin_write(output) + } +} + +impl NomReader for KernelMessage { + fn nom_read(input: &[u8]) -> NomResult { + all_consuming(alt(( + all_consuming(map( + preceded(tag([1]), Framed::::nom_read), + KernelMessage::Sequencer, + )), + map( + |bytes: &[u8]| Ok(([].as_slice(), bytes.to_vec())), + KernelMessage::DelayedMessage, + ), + )))(input) + } +} + +impl BinWriter for KernelMessage { + fn bin_write(&self, output: &mut Vec) -> enc::BinResult { + match self { + KernelMessage::Sequencer(sequencer_framed_msg) => { + // external message tag + enc::put_byte(&0x01, output); + sequencer_framed_msg.bin_write(output)?; + } + KernelMessage::DelayedMessage(message) => enc::put_bytes(message, output), + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::message::{Framed, SequencerMsg}; + + use super::{KernelMessage, Sequence}; + use crate::message::SetSequencer; + use tezos_crypto_rs::hash::{SecretKeyEd25519, SeedEd25519}; + use tezos_data_encoding::enc::{self, BinWriter}; + use tezos_data_encoding::nom::NomReader; + use tezos_smart_rollup_encoding::public_key::PublicKey; + use tezos_smart_rollup_encoding::smart_rollup::SmartRollupAddress; + + /// Generate a public key and a secret key + fn key_pair(seed: &str) -> (PublicKey, SecretKeyEd25519) { + let (public_key, secret) = SeedEd25519::from_base58_check(seed) + .expect("seed parsing should work") + .keypair() + .expect("make key pair should work"); + + let public_key = PublicKey::Ed25519(public_key); + (public_key, secret) + } + + #[test] + fn test_sequence_serialization() { + let (_, secret) = key_pair("edsk3a5SDDdMWw3Q5hPiJwDXUosmZMTuKQkriPqY6UqtSfdLifpZbB"); + let signature = secret.sign([0x0]).expect("sign should work"); + + let sequence = KernelMessage::Sequencer(Framed { + destination: SmartRollupAddress::from_b58check("sr1EzLeJYWrvch2Mhvrk1nUVYrnjGQ8A4qdb") + .expect("decoding should work"), + payload: SequencerMsg::Sequence(Sequence { + nonce: 0, + delayed_messages: 0, + messages: Vec::default(), + signature, + }), + }); + + // Serializing + let mut bin: Vec = Vec::new(); + sequence.bin_write(&mut bin).unwrap(); + + // Deserializing + let (_, msg_read) = KernelMessage::nom_read(&bin).expect("deserialization should work"); + + assert_eq!(msg_read, sequence); + } + + #[test] + fn test_set_sequencer_serialization() { + let (public_key, secret) = + key_pair("edsk3a5SDDdMWw3Q5hPiJwDXUosmZMTuKQkriPqY6UqtSfdLifpZbB"); + let signature = secret.sign([0x0]).expect("sign should work"); + + let sequence = KernelMessage::Sequencer(Framed { + destination: SmartRollupAddress::from_b58check("sr1EzLeJYWrvch2Mhvrk1nUVYrnjGQ8A4qdb") + .expect("decoding should work"), + payload: SequencerMsg::SetSequencer(SetSequencer { + nonce: 0, + admin_public_key: public_key.clone(), + sequencer_public_key: public_key, + signature, + }), + }); + + // Serializing + let mut bin: Vec = Vec::new(); + sequence.bin_write(&mut bin).unwrap(); + + println!("{:?}", bin); + + // Deserializing + let (_, msg_read) = KernelMessage::nom_read(&bin).expect("deserialization should work"); + + assert_eq!(msg_read, sequence); + } + + #[test] + fn test_user_message_serialization() { + let sequence = KernelMessage::DelayedMessage(vec![0x01, 0x0, 0x01, 0x02, 0x02]); + + // Serializing + let mut bin: Vec = Vec::new(); + sequence.bin_write(&mut bin).unwrap(); + + // Deserializing + let (_, msg_read) = KernelMessage::nom_read(&bin).expect("deserialization should work"); + + assert_eq!(msg_read, sequence); + } + + #[test] + fn test_message_default() { + let (_, secret) = key_pair("edsk3a5SDDdMWw3Q5hPiJwDXUosmZMTuKQkriPqY6UqtSfdLifpZbB"); + let signature = secret.sign([0x0]).expect("sign should work"); + + let sequence = KernelMessage::Sequencer(Framed { + destination: SmartRollupAddress::from_b58check("sr1EzLeJYWrvch2Mhvrk1nUVYrnjGQ8A4qdb") + .expect("decoding should work"), + payload: SequencerMsg::Sequence(Sequence { + nonce: 0, + signature, + delayed_messages: 5, + messages: Vec::default(), + }), + }); + + // Serializing + let mut bin: Vec = Vec::new(); + sequence.bin_write(&mut bin).unwrap(); + enc::put_bytes(&[0x01, 0x02, 0x03, 0x04], &mut bin); + + println!("{:?}", bin); + + // Deserializing + let (remaining, msg_read) = + KernelMessage::nom_read(&bin).expect("deserialization should work"); + + assert!(remaining.is_empty()); + assert_eq!(msg_read, KernelMessage::DelayedMessage(bin)) + } +}