From 2aafb50afd4c5f43782b47e677700262845694ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Cauderlier?= Date: Tue, 8 Jul 2025 18:42:47 +0200 Subject: [PATCH 1/6] Tezlink/Kernel/Receipts : Get rid of `Empty` --- etherlink/kernel_latest/tezos/src/operation_result.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index bb2c0bedadd9..ab5361c76de6 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -217,7 +217,7 @@ pub struct TransferSuccess { pub paid_storage_size_diff: Narith, pub allocated_destination_contract: bool, // TODO: Placeholder for lazy storage diff issue : #8018 - pub lazy_storage_diff: Option, + pub lazy_storage_diff: Option<()>, } // Inspired from `operation_result` in `src/proto_alpha/lib_protocol/apply_operation_result.ml` -- GitLab From 44a9059c56af41931bf4b32040fad8760b18befe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Cauderlier?= Date: Tue, 8 Jul 2025 18:47:47 +0200 Subject: [PATCH 2/6] Tezlink/Kernel/Receipts : Get rid of `VecEmpty` --- etherlink/kernel_latest/tezos/src/block.rs | 4 +-- .../tezos/src/operation_result.rs | 34 ++++++------------- .../kernel_latest/tezos_execution/src/lib.rs | 34 +++++++++---------- 3 files changed, 29 insertions(+), 43 deletions(-) diff --git a/etherlink/kernel_latest/tezos/src/block.rs b/etherlink/kernel_latest/tezos/src/block.rs index 390a21052129..4ce43a3f22a5 100644 --- a/etherlink/kernel_latest/tezos/src/block.rs +++ b/etherlink/kernel_latest/tezos/src/block.rs @@ -189,7 +189,7 @@ mod tests { use crate::operation_result::{ OperationBatchWithMetadata, OperationDataAndMetadata, OperationResult, - OperationResultSum, OperationWithMetadata, RevealSuccess, VecEmpty, + OperationResultSum, OperationWithMetadata, RevealSuccess, }; use super::{AppliedOperation, TezBlock}; @@ -211,7 +211,7 @@ mod tests { result: crate::operation_result::ContentResult::Applied(RevealSuccess { consumed_gas: 0u64.into(), }), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); AppliedOperation { hash, diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index ab5361c76de6..aed627fd5369 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -186,32 +186,17 @@ impl NomReader<'_> for Empty { } } -// PlaceHolder Type for temporary unused fields that encode as vectors -#[derive(PartialEq, Debug)] -pub struct VecEmpty; - -impl BinWriter for VecEmpty { - fn bin_write(&self, output: &mut Vec) -> tezos_enc::BinResult { - tezos_enc::u32(&0, output) - } -} -impl NomReader<'_> for VecEmpty { - fn nom_read(input: &'_ [u8]) -> tezos_nom::NomResult<'_, Self> { - // We expect an empty vector, so we just consume the size of the vector - let (input, _) = tezos_nom::size(input)?; - Ok((input, Self)) - } -} - #[derive(PartialEq, Debug, BinWriter, NomReader)] pub struct TransferSuccess { pub storage: Option>, #[encoding(dynamic, list)] pub balance_updates: Vec, // TODO: Placeholder for ticket receipt issue : #8018 - pub ticket_receipt: VecEmpty, + #[encoding(dynamic, bytes)] + pub ticket_receipt: Vec, // TODO: Placeholder for originated contracts issue : #8018 - pub originated_contracts: VecEmpty, + #[encoding(dynamic, bytes)] + pub originated_contracts: Vec, pub consumed_gas: Narith, pub storage_size: Narith, pub paid_storage_size_diff: Narith, @@ -259,7 +244,8 @@ pub struct OperationResult { pub balance_updates: Vec, pub result: ContentResult, //TODO Placeholder for internal operations : #8018 - pub internal_operation_results: VecEmpty, + #[encoding(dynamic, bytes)] + pub internal_operation_results: Vec, } #[derive(PartialEq, Debug)] pub enum OperationResultSum { @@ -274,12 +260,12 @@ pub fn produce_operation_result( Ok(success) => OperationResult { balance_updates: vec![], result: ContentResult::Applied(success), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }, Err(operation_error) => OperationResult { balance_updates: vec![], result: ContentResult::Failed(vec![operation_error]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }, } } @@ -349,10 +335,10 @@ mod tests { TransferSuccess { storage: None, lazy_storage_diff: None, balance_updates: vec![ BalanceUpdate { balance: Balance::Account(Contract::Implicit(PublicKeyHash::from_b58check("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx").unwrap())), changes: -42000000,update_origin : UpdateOrigin::BlockApplication }, BalanceUpdate { balance: Balance::Account(Contract::Implicit(PublicKeyHash::from_b58check("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN").unwrap())), changes: 42000000,update_origin : UpdateOrigin::BlockApplication} - ], ticket_receipt: VecEmpty, originated_contracts: VecEmpty, consumed_gas: 2169000.into(), storage_size: 0.into(), paid_storage_size_diff: 0.into(), allocated_destination_contract: false } + ], ticket_receipt: vec![], originated_contracts: vec![], consumed_gas: 2169000.into(), storage_size: 0.into(), paid_storage_size_diff: 0.into(), allocated_destination_contract: false } )) - , internal_operation_results: VecEmpty }) + , internal_operation_results: vec![] }) }], signature: UnknownSignature::from_base58_check( "sigPc9gwEse2o5nsicnNeWLjLgoMbEGumXw7PErAkMMa1asXVKRq43RPd7TnUKYwuHmejxEu15XTyV1iKGiaa8akFHK7CCEF" diff --git a/etherlink/kernel_latest/tezos_execution/src/lib.rs b/etherlink/kernel_latest/tezos_execution/src/lib.rs index 0df0d7511f26..90ef1d8360bd 100644 --- a/etherlink/kernel_latest/tezos_execution/src/lib.rs +++ b/etherlink/kernel_latest/tezos_execution/src/lib.rs @@ -16,7 +16,7 @@ use tezos_data_encoding::types::Narith; use tezos_evm_logging::{log, Level::*}; use tezos_evm_runtime::runtime::Runtime; use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; -use tezos_tezlink::operation_result::{TransferTarget, UpdateOrigin, VecEmpty}; +use tezos_tezlink::operation_result::{TransferTarget, UpdateOrigin}; use tezos_tezlink::{ operation::{ ManagerOperation, OperationContent, Parameter, RevealContent, TransferContent, @@ -217,8 +217,8 @@ pub fn transfer( storage: None, lazy_storage_diff: None, balance_updates: vec![src_update, dest_update], - ticket_receipt: VecEmpty, - originated_contracts: VecEmpty, + ticket_receipt: vec![], + originated_contracts: vec![], consumed_gas: 0_u64.into(), storage_size: 0_u64.into(), paid_storage_size_diff: 0_u64.into(), @@ -244,8 +244,8 @@ pub fn transfer( storage: Some(new_storage), lazy_storage_diff: None, balance_updates: vec![src_update, dest_update], - ticket_receipt: VecEmpty, - originated_contracts: VecEmpty, + ticket_receipt: vec![], + originated_contracts: vec![], consumed_gas: 0_u64.into(), storage_size: 0_u64.into(), paid_storage_size_diff: 0_u64.into(), @@ -416,7 +416,7 @@ mod tests { operation_result::{ Balance, BalanceUpdate, ContentResult, OperationResult, OperationResultSum, RevealError, RevealSuccess, TransferError, TransferSuccess, TransferTarget, - UpdateOrigin, VecEmpty, + UpdateOrigin, }, }; @@ -552,7 +552,7 @@ mod tests { result: ContentResult::Failed(vec![OperationError::Validation( ValidityError::EmptyImplicitContract, )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); @@ -588,7 +588,7 @@ mod tests { result: ContentResult::Failed(vec![OperationError::Validation( ValidityError::CantPayFees(50_u64.into()), )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); @@ -624,7 +624,7 @@ mod tests { result: ContentResult::Failed(vec![OperationError::Validation( ValidityError::InvalidCounter(0_u64.into()), )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); } @@ -666,7 +666,7 @@ mod tests { result: ContentResult::Failed(vec![OperationError::Apply( RevealError::PreviouslyRevealedKey(pk).into(), )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); } @@ -710,7 +710,7 @@ mod tests { result: ContentResult::Failed(vec![OperationError::Apply( RevealError::InconsistentHash(inconsistent_pkh).into(), )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); @@ -747,7 +747,7 @@ mod tests { result: ContentResult::Failed(vec![OperationError::Apply( RevealError::InconsistentPublicKey(src).into(), )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); @@ -788,7 +788,7 @@ mod tests { result: ContentResult::Applied(RevealSuccess { consumed_gas: 0_u64.into(), }), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); assert_eq!(receipt, expected_receipt); @@ -843,7 +843,7 @@ mod tests { } .into(), )]), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); // Verify that source and destination balances are unchanged @@ -907,14 +907,14 @@ mod tests { update_origin: UpdateOrigin::BlockApplication, }, ], - ticket_receipt: VecEmpty, - originated_contracts: VecEmpty, + ticket_receipt: vec![], + originated_contracts: vec![], consumed_gas: 0_u64.into(), storage_size: 0_u64.into(), paid_storage_size_diff: 0_u64.into(), allocated_destination_contract: true, })), - internal_operation_results: VecEmpty, + internal_operation_results: vec![], }); // Verify that source and destination balances changed -- GitLab From 943158dc02c66298c19519f28e5781ab033bf4b8 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Tue, 1 Jul 2025 11:49:25 +0200 Subject: [PATCH 3/6] Tezlink/Kernel/Receipts : Creation of enc_wrappers file for encoding struct's BlockNumber, BlockHash, OperationHash --- etherlink/kernel_latest/Cargo.lock | 1 + etherlink/kernel_latest/tezos/Cargo.toml | 1 + .../kernel_latest/tezos/src/enc_wrappers.rs | 128 ++++++++++++++++++ etherlink/kernel_latest/tezos/src/lib.rs | 1 + 4 files changed, 131 insertions(+) create mode 100644 etherlink/kernel_latest/tezos/src/enc_wrappers.rs diff --git a/etherlink/kernel_latest/Cargo.lock b/etherlink/kernel_latest/Cargo.lock index a7dfcdec2dd3..15ecab840432 100644 --- a/etherlink/kernel_latest/Cargo.lock +++ b/etherlink/kernel_latest/Cargo.lock @@ -3470,6 +3470,7 @@ dependencies = [ "tezos-smart-rollup", "tezos_crypto_rs", "tezos_data_encoding", + "thiserror 1.0.69", ] [[package]] diff --git a/etherlink/kernel_latest/tezos/Cargo.toml b/etherlink/kernel_latest/tezos/Cargo.toml index 1a080fa2c009..3be4c3f9b90c 100644 --- a/etherlink/kernel_latest/tezos/Cargo.toml +++ b/etherlink/kernel_latest/tezos/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" license = "MIT" [dependencies] +thiserror.workspace = true tezos_crypto_rs.workspace = true hex.workspace = true diff --git a/etherlink/kernel_latest/tezos/src/enc_wrappers.rs b/etherlink/kernel_latest/tezos/src/enc_wrappers.rs new file mode 100644 index 000000000000..551cd8165ded --- /dev/null +++ b/etherlink/kernel_latest/tezos/src/enc_wrappers.rs @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: 2025 Nomadic Labs +// +// SPDX-License-Identifier: MIT + +//! Encoding wrappers for Tezos data types used in Tezlink. + +/// Wrapper types over used in Tezlink, implementing +/// `NomReader` and `BinWriter` to enable derivation for more complex encodings in a tezos compatible way. +use nom::{bytes::complete::take, combinator::map}; +use primitive_types::{H256, U256}; +use std::fmt::Display; +use tezos_data_encoding::enc as tezos_enc; +use tezos_data_encoding::{ + enc::{BinResult, BinWriter}, + nom::{NomError, NomReader, NomResult}, +}; +use thiserror::Error; + +#[derive(PartialEq, Debug, NomReader, BinWriter, Clone, Copy)] +pub struct BlockNumber { + pub block_number: u32, +} + +impl Display for BlockNumber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + u32::fmt(&self.block_number, f) + } +} + +impl From for BlockNumber { + fn from(block_number: u32) -> Self { + Self { block_number } + } +} + +impl From for u32 { + fn from(block_number: BlockNumber) -> Self { + block_number.block_number + } +} + +impl From for U256 { + fn from(block_number: BlockNumber) -> Self { + block_number.block_number.into() + } +} + +#[derive(Error, Debug)] +pub struct BlockNumberOverflowError; + +impl Display for BlockNumberOverflowError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Overflow during conversion of block number from U256 to u32" + ) + } +} + +impl TryFrom for BlockNumber { + type Error = BlockNumberOverflowError; + + fn try_from(number: U256) -> Result { + if number < U256::from(u32::MAX) { + Ok(Self::from(number.as_u32())) + } else { + Err(BlockNumberOverflowError) + } + } +} + +#[derive(PartialEq, Debug)] +pub struct OperationHash(pub H256); + +impl NomReader<'_> for OperationHash { + fn nom_read(bytes: &[u8]) -> NomResult<'_, Self> { + let (remaining, hash) = + map(take::(32_usize), H256::from_slice)(bytes)?; + Ok((remaining, OperationHash(hash))) + } +} + +impl BinWriter for OperationHash { + fn bin_write(&self, data: &mut Vec) -> BinResult { + tezos_enc::put_bytes(&self.0.to_fixed_bytes(), data); + Ok(()) + } +} + +impl From for OperationHash { + fn from(hash: H256) -> Self { + Self(hash) + } +} + +impl From for H256 { + fn from(hash: OperationHash) -> Self { + hash.0 + } +} + +#[derive(PartialEq, Debug)] +pub struct BlockHash(pub H256); +impl NomReader<'_> for BlockHash { + fn nom_read(bytes: &[u8]) -> NomResult<'_, Self> { + let (remaining, hash) = + map(take::(32_usize), H256::from_slice)(bytes)?; + Ok((remaining, BlockHash(hash))) + } +} + +impl BinWriter for BlockHash { + fn bin_write(&self, data: &mut Vec) -> BinResult { + tezos_enc::put_bytes(&self.0.to_fixed_bytes(), data); + Ok(()) + } +} + +impl From for BlockHash { + fn from(hash: H256) -> Self { + Self(hash) + } +} +impl From for H256 { + fn from(hash: BlockHash) -> Self { + hash.0 + } +} diff --git a/etherlink/kernel_latest/tezos/src/lib.rs b/etherlink/kernel_latest/tezos/src/lib.rs index c8c241be5437..48e1e958967e 100644 --- a/etherlink/kernel_latest/tezos/src/lib.rs +++ b/etherlink/kernel_latest/tezos/src/lib.rs @@ -3,5 +3,6 @@ // SPDX-License-Identifier: MIT pub mod block; +pub mod enc_wrappers; pub mod operation; pub mod operation_result; -- GitLab From dbff8f939b90447388a3a7c9f278806120d751b4 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Tue, 1 Jul 2025 15:46:02 +0200 Subject: [PATCH 4/6] Tezlink/Kernel/Receipts : Swap H256 usage for the appropriate wrapper --- etherlink/kernel_latest/kernel/src/block.rs | 2 +- .../kernel/src/blueprint_storage.rs | 2 +- etherlink/kernel_latest/kernel/src/l2block.rs | 2 +- etherlink/kernel_latest/tezos/src/block.rs | 55 +++++++------------ .../kernel_latest/tezos/src/operation.rs | 38 ++----------- .../kernel_latest/tezos_execution/src/lib.rs | 5 +- 6 files changed, 33 insertions(+), 71 deletions(-) diff --git a/etherlink/kernel_latest/kernel/src/block.rs b/etherlink/kernel_latest/kernel/src/block.rs index 1b4801ca7e81..bc12d807e7fd 100644 --- a/etherlink/kernel_latest/kernel/src/block.rs +++ b/etherlink/kernel_latest/kernel/src/block.rs @@ -586,6 +586,7 @@ pub fn produce( mod tests { use super::*; use tezos_execution::account_storage::TezlinkAccount; + use tezos_tezlink::enc_wrappers::BlockHash; use tezos_tezlink::operation::Parameter; use crate::block_storage; @@ -640,7 +641,6 @@ mod tests { use tezos_smart_rollup_host::runtime::Runtime as SdkRuntime; use tezos_tezlink::block::TezBlock; - use tezos_tezlink::operation::BlockHash; use tezos_tezlink::operation::ManagerOperation; use tezos_tezlink::operation::Operation; use tezos_tezlink::operation::OperationContent; diff --git a/etherlink/kernel_latest/kernel/src/blueprint_storage.rs b/etherlink/kernel_latest/kernel/src/blueprint_storage.rs index 34d713a1338f..a4f0ae8e9fb2 100644 --- a/etherlink/kernel_latest/kernel/src/blueprint_storage.rs +++ b/etherlink/kernel_latest/kernel/src/blueprint_storage.rs @@ -155,7 +155,7 @@ impl From for BlockHeader { number: block.number, timestamp: block.timestamp, }, - chain_header: ChainHeader::Tez(TezBlockHeader { hash: block.hash }), + chain_header: ChainHeader::Tez(TezBlockHeader { hash: block.hash.0 }), } } } diff --git a/etherlink/kernel_latest/kernel/src/l2block.rs b/etherlink/kernel_latest/kernel/src/l2block.rs index c53f0b706f11..3635dba4e544 100644 --- a/etherlink/kernel_latest/kernel/src/l2block.rs +++ b/etherlink/kernel_latest/kernel/src/l2block.rs @@ -58,7 +58,7 @@ impl L2Block { pub fn hash(&self) -> H256 { match self { Self::Etherlink(block) => block.hash, - Self::Tezlink(block) => block.hash, + Self::Tezlink(block) => block.hash.0, } } diff --git a/etherlink/kernel_latest/tezos/src/block.rs b/etherlink/kernel_latest/tezos/src/block.rs index 4ce43a3f22a5..017c82c55f3c 100644 --- a/etherlink/kernel_latest/tezos/src/block.rs +++ b/etherlink/kernel_latest/tezos/src/block.rs @@ -2,18 +2,15 @@ // // SPDX-License-Identifier: MIT -use crate::operation::BlockHash; +use crate::enc_wrappers::{BlockHash, OperationHash}; use crate::operation_result::OperationDataAndMetadata; -use nom::bytes::complete::take; -use nom::combinator::map; use nom::error::ParseError; use nom::Finish; use primitive_types::{H256, U256}; use tezos_crypto_rs::blake2b::digest_256; use tezos_data_encoding::enc as tezos_enc; -use tezos_data_encoding::nom as tezos_nom; use tezos_data_encoding::nom::error::DecodeError; -use tezos_data_encoding::nom::NomError; +use tezos_data_encoding::nom::{self as tezos_nom}; use tezos_enc::{BinError, BinWriter}; use tezos_nom::{NomReader, NomResult}; use tezos_smart_rollup::types::Timestamp; @@ -21,16 +18,13 @@ use tezos_smart_rollup::types::Timestamp; #[derive(PartialEq, Debug)] pub struct AppliedOperation { // OperationHash are 32 bytes long - pub hash: H256, + pub hash: OperationHash, pub branch: BlockHash, pub op_and_receipt: OperationDataAndMetadata, } - impl NomReader<'_> for AppliedOperation { fn nom_read(input: &'_ [u8]) -> NomResult<'_, Self> { - let (remaining, hash) = - map(take::(32_usize), H256::from_slice)(input)?; - + let (remaining, hash) = OperationHash::nom_read(input)?; let (remaining, branch) = BlockHash::nom_read(remaining)?; let (remaining, op_and_receipt) = tezos_nom::dynamic(OperationDataAndMetadata::nom_read)(remaining)?; @@ -48,15 +42,12 @@ impl NomReader<'_> for AppliedOperation { impl BinWriter for AppliedOperation { fn bin_write(&self, output: &mut Vec) -> Result<(), BinError> { - let Self { - hash, - branch, - op_and_receipt, - } = self; - // Encode all fields of the AppliedOperation - tezos_enc::put_bytes(&hash.to_fixed_bytes(), output); - branch.bin_write(output)?; - tezos_enc::dynamic(OperationDataAndMetadata::bin_write)(op_and_receipt, output)?; + self.hash.bin_write(output)?; + self.branch.bin_write(output)?; + tezos_enc::dynamic(OperationDataAndMetadata::bin_write)( + &self.op_and_receipt, + output, + )?; Ok(()) } } @@ -64,23 +55,19 @@ impl BinWriter for AppliedOperation { // WIP: This structure will evolve to look like Tezos block #[derive(PartialEq, Debug)] pub struct TezBlock { - pub hash: H256, + pub hash: BlockHash, pub number: U256, pub timestamp: Timestamp, - pub previous_hash: H256, + pub previous_hash: BlockHash, pub operations: Vec, } impl NomReader<'_> for TezBlock { fn nom_read(input: &'_ [u8]) -> NomResult<'_, Self> { - let (remaining, hash) = - map(take::(32_usize), H256::from_slice)(input)?; - + let (remaining, hash) = BlockHash::nom_read(input)?; let (remaining, number) = nom::number::complete::be_u32(remaining)?; let number = U256::from(number); - - let (remaining, previous_hash) = - map(take::(32_usize), H256::from_slice)(remaining)?; + let (remaining, previous_hash) = BlockHash::nom_read(remaining)?; // Decode the timestamp let (remaining, timestamp) = nom::number::complete::be_i64(remaining)?; @@ -114,9 +101,9 @@ impl BinWriter for TezBlock { operations, } = self; // Encode all block fields - tezos_enc::put_bytes(&hash.to_fixed_bytes(), output); + hash.bin_write(output)?; tezos_enc::u32(&number.as_u32(), output)?; - tezos_enc::put_bytes(&previous_hash.to_fixed_bytes(), output); + previous_hash.bin_write(output)?; tezos_enc::i64(×tamp.i64(), output)?; tezos_enc::dynamic(tezos_enc::list(AppliedOperation::bin_write))( operations, output, @@ -138,11 +125,11 @@ impl TezBlock { } // This function must be used on a TezBlock whose hash field is H256::zero() - fn hash(&self) -> Result { + fn hash(&self) -> Result { let mut encoded_data = vec![]; self.bin_write(&mut encoded_data)?; let hashed_data = digest_256(&encoded_data); - Ok(H256::from_slice(&hashed_data)) + Ok(BlockHash(H256::from_slice(&hashed_data))) } pub fn new( @@ -152,10 +139,10 @@ impl TezBlock { operations: Vec, ) -> Result { let block = Self { - hash: H256::zero(), + hash: BlockHash(H256::zero()), // Placeholder, will be computed number, timestamp, - previous_hash, + previous_hash: BlockHash(previous_hash), operations, }; Ok(Self { @@ -204,7 +191,7 @@ mod tests { } fn dummy_applied_operation() -> AppliedOperation { - let hash = H256::random(); + let hash = H256::random().into(); let data = crate::operation::make_dummy_reveal_operation(); let receipt = OperationResultSum::Reveal(OperationResult { balance_updates: vec![], diff --git a/etherlink/kernel_latest/tezos/src/operation.rs b/etherlink/kernel_latest/tezos/src/operation.rs index 6c9fb03e3e94..861ddd3f87d9 100644 --- a/etherlink/kernel_latest/tezos/src/operation.rs +++ b/etherlink/kernel_latest/tezos/src/operation.rs @@ -3,19 +3,18 @@ // SPDX-License-Identifier: MIT //! Tezos operations: this module defines the fragment of Tezos operations supported by Tezlink and how to serialize them. - -use mir::ast::michelson_address::entrypoint; /// The whole module is inspired of `src/proto_alpha/lib_protocol/operation_repr.ml` to represent the operation -use nom::combinator::map; +use crate::enc_wrappers::{BlockHash, OperationHash}; +use mir::ast::michelson_address::entrypoint; use nom::error::{ErrorKind, ParseError}; -use nom::{bytes::complete::take, Finish}; +use nom::Finish; use primitive_types::H256; use rlp::Decodable; use tezos_crypto_rs::blake2b::digest_256; use tezos_crypto_rs::hash::UnknownSignature; use tezos_data_encoding::types::Narith; use tezos_data_encoding::{ - enc::{BinError, BinResult, BinWriter}, + enc::{BinError, BinWriter}, nom::{error::DecodeError, NomError, NomReader}, }; use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; @@ -93,10 +92,10 @@ impl Operation { Ok(()) } - pub fn hash(&self) -> Result { + pub fn hash(&self) -> Result { let serialized_op = self.to_bytes()?; let op_hash = digest_256(&serialized_op); - Ok(H256::from_slice(&op_hash)) + Ok(OperationHash(H256::from_slice(&op_hash))) } } @@ -108,25 +107,6 @@ impl Decodable for Operation { } } -#[derive(PartialEq, Debug)] -pub struct BlockHash(H256); - -impl NomReader<'_> for BlockHash { - fn nom_read(bytes: &[u8]) -> tezos_data_encoding::nom::NomResult { - let (bytes, hash) = - map(take::(32_usize), H256::from_slice)(bytes)?; - Ok((bytes, Self(hash))) - } -} - -impl BinWriter for BlockHash { - fn bin_write(&self, data: &mut Vec) -> BinResult { - let hash: [u8; 32] = self.0.to_fixed_bytes(); - data.extend_from_slice(&hash); - Ok(()) - } -} - /** There is a distance between the binary format of manager operations @@ -226,12 +206,6 @@ impl From for ManagerOperation { } } -impl From for BlockHash { - fn from(hash: H256) -> Self { - Self(hash) - } -} - #[cfg(test)] fn make_dummy_operation( operation: OperationContent, diff --git a/etherlink/kernel_latest/tezos_execution/src/lib.rs b/etherlink/kernel_latest/tezos_execution/src/lib.rs index 90ef1d8360bd..771cda5cd7c0 100644 --- a/etherlink/kernel_latest/tezos_execution/src/lib.rs +++ b/etherlink/kernel_latest/tezos_execution/src/lib.rs @@ -409,9 +409,10 @@ mod tests { use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; use tezos_tezlink::{ block::TezBlock, + enc_wrappers::BlockHash, operation::{ - BlockHash, ManagerOperation, Operation, OperationContent, Parameter, - RevealContent, TransferContent, + ManagerOperation, Operation, OperationContent, Parameter, RevealContent, + TransferContent, }, operation_result::{ Balance, BalanceUpdate, ContentResult, OperationResult, OperationResultSum, -- GitLab From 583634541ded251a23bf04fd6c5e79decbd9151e Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Tue, 1 Jul 2025 17:44:03 +0200 Subject: [PATCH 5/6] Tezlink/Kernel/Receipts : Swap U256 usage for BlockNumber --- etherlink/kernel_latest/kernel/src/block.rs | 2 +- .../kernel/src/blueprint_storage.rs | 2 +- etherlink/kernel_latest/kernel/src/chains.rs | 20 ++++++++++--------- etherlink/kernel_latest/kernel/src/l2block.rs | 2 +- etherlink/kernel_latest/tezos/src/block.rs | 17 ++++++++-------- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/etherlink/kernel_latest/kernel/src/block.rs b/etherlink/kernel_latest/kernel/src/block.rs index bc12d807e7fd..e2968f578c46 100644 --- a/etherlink/kernel_latest/kernel/src/block.rs +++ b/etherlink/kernel_latest/kernel/src/block.rs @@ -303,7 +303,7 @@ fn next_bip_from_blueprints( next_bip_number, chain_header, blueprint, - ); + )?; Ok(BlueprintParsing::Next(Box::new(bip))) } None => Ok(BlueprintParsing::None), diff --git a/etherlink/kernel_latest/kernel/src/blueprint_storage.rs b/etherlink/kernel_latest/kernel/src/blueprint_storage.rs index a4f0ae8e9fb2..0dfa1ddb35ed 100644 --- a/etherlink/kernel_latest/kernel/src/blueprint_storage.rs +++ b/etherlink/kernel_latest/kernel/src/blueprint_storage.rs @@ -152,7 +152,7 @@ impl From for BlockHeader { fn from(block: TezBlock) -> Self { Self { blueprint_header: BlueprintHeader { - number: block.number, + number: block.number.into(), timestamp: block.timestamp, }, chain_header: ChainHeader::Tez(TezBlockHeader { hash: block.hash.0 }), diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index fa748566306e..4659d2e608b6 100644 --- a/etherlink/kernel_latest/kernel/src/chains.rs +++ b/etherlink/kernel_latest/kernel/src/chains.rs @@ -37,6 +37,7 @@ use tezos_smart_rollup::{outbox::OutboxQueue, types::Timestamp}; use tezos_smart_rollup_host::path::{Path, RefPath}; use tezos_tezlink::{ block::{AppliedOperation, TezBlock}, + enc_wrappers::BlockNumber, operation::Operation, operation_result::{ OperationBatchWithMetadata, OperationDataAndMetadata, OperationWithMetadata, @@ -93,7 +94,7 @@ impl BlockInProgressTrait for EthBlockInProgress { } pub struct TezBlockInProgress { - number: U256, + number: BlockNumber, timestamp: Timestamp, previous_hash: H256, applied: Vec, @@ -102,7 +103,7 @@ pub struct TezBlockInProgress { impl BlockInProgressTrait for TezBlockInProgress { fn number(&self) -> U256 { - self.number + self.number.into() } } @@ -236,7 +237,7 @@ pub trait ChainConfigTrait: Debug { current_block_number: U256, previous_chain_header: Self::ChainHeader, blueprint: Blueprint, - ) -> Self::BlockInProgress; + ) -> anyhow::Result; fn read_block_in_progress( host: &impl Runtime, @@ -291,15 +292,15 @@ impl ChainConfigTrait for EvmChainConfig { current_block_number: U256, header: Self::ChainHeader, blueprint: Blueprint, - ) -> Self::BlockInProgress { - eth_bip_from_blueprint( + ) -> anyhow::Result { + Ok(eth_bip_from_blueprint( host, self, tick_counter, current_block_number, header, blueprint, - ) + )) } fn transactions_from_bytes( @@ -428,15 +429,16 @@ impl ChainConfigTrait for MichelsonChainConfig { current_block_number: U256, header: Self::ChainHeader, blueprint: Blueprint, - ) -> Self::BlockInProgress { + ) -> anyhow::Result { let TezTransactions(operations) = blueprint.transactions; - TezBlockInProgress { + let current_block_number: BlockNumber = current_block_number.try_into()?; + Ok(TezBlockInProgress { number: current_block_number, timestamp: blueprint.timestamp, previous_hash: header.hash, applied: vec![], operations: VecDeque::from(operations), - } + }) } fn fetch_hashes_from_delayed_inbox( diff --git a/etherlink/kernel_latest/kernel/src/l2block.rs b/etherlink/kernel_latest/kernel/src/l2block.rs index 3635dba4e544..100c4477223a 100644 --- a/etherlink/kernel_latest/kernel/src/l2block.rs +++ b/etherlink/kernel_latest/kernel/src/l2block.rs @@ -23,7 +23,7 @@ impl L2Block { pub fn number(&self) -> U256 { match self { Self::Etherlink(block) => block.number, - Self::Tezlink(block) => block.number, + Self::Tezlink(block) => block.number.into(), } } diff --git a/etherlink/kernel_latest/tezos/src/block.rs b/etherlink/kernel_latest/tezos/src/block.rs index 017c82c55f3c..a193b84a4a88 100644 --- a/etherlink/kernel_latest/tezos/src/block.rs +++ b/etherlink/kernel_latest/tezos/src/block.rs @@ -2,11 +2,11 @@ // // SPDX-License-Identifier: MIT -use crate::enc_wrappers::{BlockHash, OperationHash}; +use crate::enc_wrappers::{BlockHash, BlockNumber, OperationHash}; use crate::operation_result::OperationDataAndMetadata; use nom::error::ParseError; use nom::Finish; -use primitive_types::{H256, U256}; +use primitive_types::H256; use tezos_crypto_rs::blake2b::digest_256; use tezos_data_encoding::enc as tezos_enc; use tezos_data_encoding::nom::error::DecodeError; @@ -56,7 +56,7 @@ impl BinWriter for AppliedOperation { #[derive(PartialEq, Debug)] pub struct TezBlock { pub hash: BlockHash, - pub number: U256, + pub number: BlockNumber, pub timestamp: Timestamp, pub previous_hash: BlockHash, pub operations: Vec, @@ -65,8 +65,7 @@ pub struct TezBlock { impl NomReader<'_> for TezBlock { fn nom_read(input: &'_ [u8]) -> NomResult<'_, Self> { let (remaining, hash) = BlockHash::nom_read(input)?; - let (remaining, number) = nom::number::complete::be_u32(remaining)?; - let number = U256::from(number); + let (remaining, number) = BlockNumber::nom_read(remaining)?; let (remaining, previous_hash) = BlockHash::nom_read(remaining)?; // Decode the timestamp @@ -102,7 +101,7 @@ impl BinWriter for TezBlock { } = self; // Encode all block fields hash.bin_write(output)?; - tezos_enc::u32(&number.as_u32(), output)?; + number.bin_write(output)?; previous_hash.bin_write(output)?; tezos_enc::i64(×tamp.i64(), output)?; tezos_enc::dynamic(tezos_enc::list(AppliedOperation::bin_write))( @@ -133,7 +132,7 @@ impl TezBlock { } pub fn new( - number: U256, + number: BlockNumber, timestamp: Timestamp, previous_hash: H256, operations: Vec, @@ -171,7 +170,7 @@ impl TezBlock { #[cfg(test)] mod tests { - use primitive_types::{H256, U256}; + use primitive_types::H256; use tezos_smart_rollup::types::Timestamp; use crate::operation_result::{ @@ -216,7 +215,7 @@ mod tests { } fn dummy_tezblock(operations: Vec) -> TezBlock { - let number = U256::one(); + let number = 1u32.into(); let timestamp = Timestamp::from(0); let previous_hash = TezBlock::genesis_block_hash(); TezBlock::new(number, timestamp, previous_hash, operations) -- GitLab From 9c13a1d59a6ce95f770f49aa9bb7463dec270b49 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Tue, 1 Jul 2025 17:51:27 +0200 Subject: [PATCH 6/6] Tezlink/Kernel/Receipts : Derive NomReader and BinWriter for (AppliedOperation,TezBlock,BalanceTooLow) --- etherlink/kernel_latest/tezos/src/block.rs | 88 ++----------------- .../tezos/src/operation_result.rs | 66 +++----------- .../kernel_latest/tezos_execution/src/lib.rs | 16 ++-- 3 files changed, 24 insertions(+), 146 deletions(-) diff --git a/etherlink/kernel_latest/tezos/src/block.rs b/etherlink/kernel_latest/tezos/src/block.rs index a193b84a4a88..d0e7dd3b852b 100644 --- a/etherlink/kernel_latest/tezos/src/block.rs +++ b/etherlink/kernel_latest/tezos/src/block.rs @@ -12,105 +12,29 @@ use tezos_data_encoding::enc as tezos_enc; use tezos_data_encoding::nom::error::DecodeError; use tezos_data_encoding::nom::{self as tezos_nom}; use tezos_enc::{BinError, BinWriter}; -use tezos_nom::{NomReader, NomResult}; +use tezos_nom::NomReader; use tezos_smart_rollup::types::Timestamp; -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Debug, BinWriter, NomReader)] pub struct AppliedOperation { // OperationHash are 32 bytes long pub hash: OperationHash, pub branch: BlockHash, + #[encoding(dynamic)] pub op_and_receipt: OperationDataAndMetadata, } -impl NomReader<'_> for AppliedOperation { - fn nom_read(input: &'_ [u8]) -> NomResult<'_, Self> { - let (remaining, hash) = OperationHash::nom_read(input)?; - let (remaining, branch) = BlockHash::nom_read(remaining)?; - let (remaining, op_and_receipt) = - tezos_nom::dynamic(OperationDataAndMetadata::nom_read)(remaining)?; - - Ok(( - remaining, - Self { - hash, - branch, - op_and_receipt, - }, - )) - } -} - -impl BinWriter for AppliedOperation { - fn bin_write(&self, output: &mut Vec) -> Result<(), BinError> { - self.hash.bin_write(output)?; - self.branch.bin_write(output)?; - tezos_enc::dynamic(OperationDataAndMetadata::bin_write)( - &self.op_and_receipt, - output, - )?; - Ok(()) - } -} // WIP: This structure will evolve to look like Tezos block -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Debug, BinWriter, NomReader)] pub struct TezBlock { pub hash: BlockHash, pub number: BlockNumber, - pub timestamp: Timestamp, pub previous_hash: BlockHash, + pub timestamp: Timestamp, + #[encoding(dynamic, list)] pub operations: Vec, } -impl NomReader<'_> for TezBlock { - fn nom_read(input: &'_ [u8]) -> NomResult<'_, Self> { - let (remaining, hash) = BlockHash::nom_read(input)?; - let (remaining, number) = BlockNumber::nom_read(remaining)?; - let (remaining, previous_hash) = BlockHash::nom_read(remaining)?; - - // Decode the timestamp - let (remaining, timestamp) = nom::number::complete::be_i64(remaining)?; - let timestamp = Timestamp::from(timestamp); - - let (remaining, operations) = - tezos_nom::dynamic(tezos_nom::list(AppliedOperation::nom_read))(remaining)?; - - Ok(( - remaining, - Self { - hash, - number, - timestamp, - previous_hash, - operations, - }, - )) - } -} - -impl BinWriter for TezBlock { - // Encoded size for parameter were taken from this command: - // `octez-codec describe block_header binary schema` - fn bin_write(&self, output: &mut Vec) -> Result<(), BinError> { - let Self { - hash, - number, - timestamp, - previous_hash, - operations, - } = self; - // Encode all block fields - hash.bin_write(output)?; - number.bin_write(output)?; - previous_hash.bin_write(output)?; - tezos_enc::i64(×tamp.i64(), output)?; - tezos_enc::dynamic(tezos_enc::list(AppliedOperation::bin_write))( - operations, output, - )?; - Ok(()) - } -} - impl TezBlock { pub fn genesis_block_hash() -> H256 { // This H256 comes from this b58 hash 'BLockGenesisGenesisGenesisGenesisGenesis1db77eJNeJ9' diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index aed627fd5369..f20d766ed388 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -6,12 +6,9 @@ /// The whole module is inspired of `src/proto_alpha/lib_protocol/apply_result.ml` to represent the result of an operation /// In Tezlink, operation is equivalent to manager operation because there is no other type of operation that interests us. -use nom::branch::alt; -use nom::bytes::complete::tag; -use nom::sequence::preceded; use std::fmt::Debug; use tezos_crypto_rs::hash::UnknownSignature; -use tezos_data_encoding::enc::{self as tezos_enc, u8}; +use tezos_data_encoding::enc as tezos_enc; use tezos_data_encoding::nom as tezos_nom; use tezos_data_encoding::types::Narith; use tezos_enc::BinWriter; @@ -35,60 +32,17 @@ pub enum RevealError { InconsistentPublicKey(PublicKeyHash), } -#[derive(Debug, PartialEq, Eq)] -pub enum TransferError { - BalanceTooLow { - contract: Contract, - balance: Narith, - amount: Narith, - }, - UnspendableContract(Contract), +#[derive(Debug, PartialEq, Eq, BinWriter, NomReader)] +pub struct BalanceTooLow { + pub contract: Contract, + pub balance: Narith, + pub amount: Narith, } -impl BinWriter for TransferError { - fn bin_write(&self, output: &mut Vec) -> tezos_enc::BinResult { - match self { - Self::BalanceTooLow { - contract, - balance, - amount, - } => { - u8(&0_u8, output)?; - contract.bin_write(output)?; - balance.bin_write(output)?; - amount.bin_write(output)?; - Ok(()) - } - Self::UnspendableContract(contract) => { - u8(&1_u8, output)?; - contract.bin_write(output)?; - Ok(()) - } - } - } -} - -impl NomReader<'_> for TransferError { - fn nom_read(input: &'_ [u8]) -> tezos_nom::NomResult<'_, Self> { - let balance_too_low_parser = preceded(tag(0_u8.to_be_bytes()), |input| { - let (input, contract) = Contract::nom_read(input)?; - let (input, balance) = Narith::nom_read(input)?; - let (input, amount) = Narith::nom_read(input)?; - Ok(( - input, - Self::BalanceTooLow { - contract, - balance, - amount, - }, - )) - }); - let unspendable_contract_parser = preceded(tag(1_u8.to_be_bytes()), |input| { - let (input, contract) = Contract::nom_read(input)?; - Ok((input, Self::UnspendableContract(contract))) - }); - alt((balance_too_low_parser, unspendable_contract_parser))(input) - } +#[derive(Debug, PartialEq, Eq, BinWriter, NomReader)] +pub enum TransferError { + BalanceTooLow(BalanceTooLow), + UnspendableContract(Contract), } #[derive(Debug, PartialEq, Eq, NomReader, BinWriter)] diff --git a/etherlink/kernel_latest/tezos_execution/src/lib.rs b/etherlink/kernel_latest/tezos_execution/src/lib.rs index 771cda5cd7c0..609e75556424 100644 --- a/etherlink/kernel_latest/tezos_execution/src/lib.rs +++ b/etherlink/kernel_latest/tezos_execution/src/lib.rs @@ -16,7 +16,7 @@ use tezos_data_encoding::types::Narith; use tezos_evm_logging::{log, Level::*}; use tezos_evm_runtime::runtime::Runtime; use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; -use tezos_tezlink::operation_result::{TransferTarget, UpdateOrigin}; +use tezos_tezlink::operation_result::{BalanceTooLow, TransferTarget, UpdateOrigin}; use tezos_tezlink::{ operation::{ ManagerOperation, OperationContent, Parameter, RevealContent, TransferContent, @@ -186,11 +186,11 @@ pub fn transfer( let new_source_balance = match current_src_balance.checked_sub(&amount.0) { None => { log!(host, Debug, "Balance is too low"); - let error = TransferError::BalanceTooLow { + let error = TransferError::BalanceTooLow(BalanceTooLow { contract: src_contract.clone(), balance: current_src_balance.into(), amount: amount.clone(), - }; + }); return Ok(Err(error.into())); } Some(new_source_balance) => new_source_balance, @@ -415,9 +415,9 @@ mod tests { TransferContent, }, operation_result::{ - Balance, BalanceUpdate, ContentResult, OperationResult, OperationResultSum, - RevealError, RevealSuccess, TransferError, TransferSuccess, TransferTarget, - UpdateOrigin, + Balance, BalanceTooLow, BalanceUpdate, ContentResult, OperationResult, + OperationResultSum, RevealError, RevealSuccess, TransferError, + TransferSuccess, TransferTarget, UpdateOrigin, }, }; @@ -837,11 +837,11 @@ mod tests { let expected_receipt = OperationResultSum::Transfer(OperationResult { balance_updates: vec![], result: ContentResult::Failed(vec![OperationError::Apply( - TransferError::BalanceTooLow { + TransferError::BalanceTooLow(BalanceTooLow { contract: Contract::from_b58check(BOOTSTRAP_1).unwrap(), balance: 50_u64.into(), amount: 100_u64.into(), - } + }) .into(), )]), internal_operation_results: vec![], -- GitLab