From cffd53a8c5c095f438ac069b577fecf0a3ab5aeb Mon Sep 17 00:00:00 2001 From: Luciano Freitas Date: Fri, 1 Aug 2025 08:48:07 +0200 Subject: [PATCH 1/8] Tezlink/Kernel/Errors: RuntimeError is operation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Raphaƫl Cauderlier --- etherlink/kernel_latest/Cargo.lock | 1 + etherlink/kernel_latest/tezos/Cargo.toml | 1 + etherlink/kernel_latest/tezos/src/operation_result.rs | 2 ++ 3 files changed, 4 insertions(+) diff --git a/etherlink/kernel_latest/Cargo.lock b/etherlink/kernel_latest/Cargo.lock index 7072378f9a58..60dfe780c446 100644 --- a/etherlink/kernel_latest/Cargo.lock +++ b/etherlink/kernel_latest/Cargo.lock @@ -3340,6 +3340,7 @@ dependencies = [ "rand 0.9.1", "rlp", "tezos-smart-rollup", + "tezos-smart-rollup-host", "tezos_crypto_rs", "tezos_data_encoding", "thiserror 1.0.69", diff --git a/etherlink/kernel_latest/tezos/Cargo.toml b/etherlink/kernel_latest/tezos/Cargo.toml index 3be4c3f9b90c..de302cabbffa 100644 --- a/etherlink/kernel_latest/tezos/Cargo.toml +++ b/etherlink/kernel_latest/tezos/Cargo.toml @@ -16,6 +16,7 @@ hex.workspace = true primitive-types.workspace = true tezos-smart-rollup.workspace = true +tezos-smart-rollup-host.workspace = true num-bigint.workspace = true tezos_data_encoding.workspace = true nom.workspace = true diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index 2b6c819578ca..48626580375f 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -17,6 +17,7 @@ use tezos_enc::BinWriter; use tezos_nom::NomReader; use tezos_smart_rollup::types::Contract; use tezos_smart_rollup::types::{PublicKey, PublicKeyHash}; +use tezos_smart_rollup_host::runtime::RuntimeError; use thiserror::Error; use crate::operation::ManagerOperationContent; @@ -160,6 +161,7 @@ impl From for OperationError { pub enum OperationError { Validation(ValidityError), Apply(ApplyOperationError), + RuntimeError(RuntimeError), } // In Tezos data encoding, errors are encoded as bson (binary json). Unfortunately, -- GitLab From 64060af19bf6f739c0a1355a6108d5ca93fe971d Mon Sep 17 00:00:00 2001 From: Luciano Freitas Date: Fri, 1 Aug 2025 09:10:17 +0200 Subject: [PATCH 2/8] Tezlink/Kernel/Error: derive Error for ValidityError --- .../kernel_latest/tezos/src/operation_result.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index 48626580375f..1bc5718adc66 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -28,22 +28,37 @@ pub struct CounterError { pub found: Narith, } -#[derive(Debug, PartialEq, Eq, NomReader, BinWriter)] +#[derive(Error, Debug, PartialEq, Eq, NomReader, BinWriter)] pub enum ValidityError { + #[error("Counter in the past: {0:?}.")] CounterInThePast(CounterError), + #[error("Counter in the future: {0:?}.")] CounterInTheFuture(CounterError), + #[error("Missing manager contract.")] MissingManagerContract, + #[error("The manager key for {0} has not been revealed yet.")] UnrevealedManagerKey(PublicKeyHash), + #[error("Cannot pay {0:?} in fees.")] CantPayFees(Narith), + #[error("Empty implicit contract.")] EmptyImplicitContract, + #[error("Gas limit is too high.")] GasLimitTooHigh, + #[error("Storage limit is too high.")] StorageLimitTooHigh, + #[error("Invalid signature.")] InvalidSignature, + #[error("Failed to fetch account")] FailedToFetchAccount, + #[error("Failed to compute fee balance update")] FailedToComputeFeeBalanceUpdate, + #[error("Failed to fetch counter")] FailedToFetchCounter, + #[error("Failed to fetch manager key")] FailedToFetchManagerKey, + #[error("Failed to fetch balance")] FailedToFetchBalance, + #[error("Failed to update balance")] FailedToUpdateBalance, } -- GitLab From 4ffb5cdab08c7e8f430876a77781ebda8ab1321d Mon Sep 17 00:00:00 2001 From: Luciano Freitas Date: Fri, 1 Aug 2025 09:21:37 +0200 Subject: [PATCH 3/8] Tezlink/Kernel/Error: derive Error for RevealError --- etherlink/kernel_latest/tezos/src/operation_result.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index 1bc5718adc66..32ed575eadc0 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -62,13 +62,19 @@ pub enum ValidityError { FailedToUpdateBalance, } -#[derive(Debug, PartialEq, Eq, NomReader, BinWriter)] +#[derive(Error, Debug, PartialEq, Eq, NomReader, BinWriter)] pub enum RevealError { + #[error("Revelation failed because the public key {0} was already revealed.")] PreviouslyRevealedKey(PublicKey), + #[error("The public key hash {0} is inconsistent.")] InconsistentHash(PublicKeyHash), + #[error("The public key hash {0} is inconsistent with the public key provided.")] InconsistentPublicKey(PublicKeyHash), + #[error("Could not retrieve manager.")] UnretrievableManager, + #[error("Failed to increment counter.")] FailedToIncrementCounter, + #[error("Failed to write manager.")] FailedToWriteManager, } -- GitLab From c7442e77043573c12624c08f1fe9a2eaa0a52a31 Mon Sep 17 00:00:00 2001 From: Luciano Freitas Date: Fri, 1 Aug 2025 09:23:22 +0200 Subject: [PATCH 4/8] Tezlink/Kernel/Error: derive Error for ApplyOperationError Co-authored-by: Arnaud Bihan --- .../tezos/src/operation_result.rs | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index 32ed575eadc0..7a8bb7012c76 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -147,25 +147,16 @@ impl From for TransferError { } } -#[derive(Debug, PartialEq, Eq, NomReader, BinWriter)] +#[derive(Error, Debug, PartialEq, Eq, NomReader, BinWriter)] pub enum ApplyOperationError { - Reveal(RevealError), - Transfer(TransferError), + #[error("Reveal error: {0}")] + Reveal(#[from] RevealError), + #[error("Transfer error: {0}")] + Transfer(#[from] TransferError), + #[error("Unsupported operation: {0}")] UnSupportedOperation(String), } -impl From for ApplyOperationError { - fn from(value: RevealError) -> Self { - Self::Reveal(value) - } -} - -impl From for ApplyOperationError { - fn from(value: TransferError) -> Self { - Self::Transfer(value) - } -} - impl From for OperationError { fn from(value: RevealError) -> Self { Self::Apply(value.into()) -- GitLab From b21bd510324671bb6e9dcc2d947db5eaab02ff7c Mon Sep 17 00:00:00 2001 From: Luciano Freitas Date: Fri, 1 Aug 2025 09:27:06 +0200 Subject: [PATCH 5/8] Tezlink/Kernel/Error: derive Error for OperationError --- .../tezos/src/operation_result.rs | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index 7a8bb7012c76..fa5d9f9a61c1 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -169,11 +169,14 @@ impl From for OperationError { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Error, Debug, PartialEq, Eq)] pub enum OperationError { - Validation(ValidityError), - Apply(ApplyOperationError), - RuntimeError(RuntimeError), + #[error("Validation error: {0}")] + Validation(#[from] ValidityError), + #[error("Application error: {0}")] + Apply(#[from] ApplyOperationError), + #[error("Runtime error: {0}")] + RuntimeError(#[from] RuntimeError), } // In Tezos data encoding, errors are encoded as bson (binary json). Unfortunately, @@ -242,18 +245,6 @@ impl NomReader<'_> for OperationError { } } -impl From for OperationError { - fn from(value: ValidityError) -> Self { - Self::Validation(value) - } -} - -impl From for OperationError { - fn from(value: ApplyOperationError) -> Self { - Self::Apply(value) - } -} - pub trait OperationKind { type Success: PartialEq + Debug + BinWriter + for<'a> NomReader<'a>; } -- GitLab From 02aa6d5a3751c2091443fd6a470e7e39c853f05f Mon Sep 17 00:00:00 2001 From: Luciano Freitas Date: Fri, 1 Aug 2025 09:28:55 +0200 Subject: [PATCH 6/8] Tezlink/Kernel/Transfer: validate_and_apply returns OperationError --- etherlink/kernel_latest/tezos_execution/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/etherlink/kernel_latest/tezos_execution/src/lib.rs b/etherlink/kernel_latest/tezos_execution/src/lib.rs index a80e6e1f8dab..caedf91aa356 100644 --- a/etherlink/kernel_latest/tezos_execution/src/lib.rs +++ b/etherlink/kernel_latest/tezos_execution/src/lib.rs @@ -18,7 +18,6 @@ use tezos_data_encoding::types::Narith; use tezos_evm_logging::{log, Level::*, Verbosity}; use tezos_evm_runtime::{runtime::Runtime, safe_storage::SafeStorage}; use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; -use tezos_smart_rollup_host::runtime::RuntimeError; use tezos_tezlink::operation::Operation; use tezos_tezlink::operation_result::TransferTarget; use tezos_tezlink::{ @@ -457,7 +456,7 @@ pub fn validate_and_apply_operation( host: &mut Host, context: &context::Context, operation: Operation, -) -> Result { +) -> Result { let manager_operation: ManagerOperation = operation.content.clone().into(); -- GitLab From 182778bebb2c48543fbd0c3449ed677377da5001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Cauderlier?= Date: Fri, 1 Aug 2025 11:24:01 +0200 Subject: [PATCH 7/8] Tezlink/Kernel/Execution: remove Apply case in OperationError --- .../tezos/src/operation_result.rs | 75 ++++------ .../kernel_latest/tezos_execution/src/lib.rs | 134 +++++------------- 2 files changed, 66 insertions(+), 143 deletions(-) diff --git a/etherlink/kernel_latest/tezos/src/operation_result.rs b/etherlink/kernel_latest/tezos/src/operation_result.rs index fa5d9f9a61c1..0a96626bae0b 100644 --- a/etherlink/kernel_latest/tezos/src/operation_result.rs +++ b/etherlink/kernel_latest/tezos/src/operation_result.rs @@ -147,7 +147,7 @@ impl From for TransferError { } } -#[derive(Error, Debug, PartialEq, Eq, NomReader, BinWriter)] +#[derive(Error, Debug, PartialEq, Eq, NomReader)] pub enum ApplyOperationError { #[error("Reveal error: {0}")] Reveal(#[from] RevealError), @@ -157,24 +157,10 @@ pub enum ApplyOperationError { UnSupportedOperation(String), } -impl From for OperationError { - fn from(value: RevealError) -> Self { - Self::Apply(value.into()) - } -} - -impl From for OperationError { - fn from(value: TransferError) -> Self { - Self::Apply(value.into()) - } -} - #[derive(Error, Debug, PartialEq, Eq)] pub enum OperationError { #[error("Validation error: {0}")] Validation(#[from] ValidityError), - #[error("Application error: {0}")] - Apply(#[from] ApplyOperationError), #[error("Runtime error: {0}")] RuntimeError(#[from] RuntimeError), } @@ -185,7 +171,7 @@ pub enum OperationError { // To avoid reimplementing full bson support, we convert errors to strings and // manually encode them in bson. This gives us error which can be decoded using // Tezos data encoding but with less structure than what Tezos L1 produces. -impl BinWriter for OperationError { +impl BinWriter for ApplyOperationError { fn bin_write(&self, output: &mut Vec) -> tezos_enc::BinResult { tezos_enc::dynamic(|error, out: &mut Vec| { // Convert the error to a String @@ -315,14 +301,14 @@ pub struct TransferSuccess { // It should just be encoded as a JSON, so we can't derive // NomReader and BinWriter if we want to be Tezos compatible #[derive(PartialEq, Debug, BinWriter, NomReader)] -pub struct OperationErrors { +pub struct ApplyOperationErrors { #[encoding(dynamic, list)] - pub errors: Vec, + pub errors: Vec, } -impl From> for OperationErrors { - fn from(value: Vec) -> Self { - OperationErrors { errors: value } +impl From> for ApplyOperationErrors { + fn from(value: Vec) -> Self { + ApplyOperationErrors { errors: value } } } @@ -331,7 +317,7 @@ impl From> for OperationErrors { #[derive(PartialEq, Debug, BinWriter, NomReader)] pub enum ContentResult { Applied(M::Success), - Failed(OperationErrors), + Failed(ApplyOperationErrors), } /// A [Balance] updates can be triggered on different target @@ -393,7 +379,7 @@ pub fn is_applied(res: &OperationResultSum) -> bool { pub fn produce_operation_result( balance_updates: Vec, - result: Result, + result: Result, ) -> OperationResult { match result { Ok(success) => OperationResult { @@ -482,26 +468,22 @@ mod tests { balance_updates: vec![], result: ContentResult::Failed( vec![ - OperationError::Apply( - ApplyOperationError::Transfer( - TransferError::BalanceTooLow( - BalanceTooLow { - contract: Contract::from_b58check("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx").unwrap(), - balance: 10_u64.into(), - amount: 21_u64.into() - } - ) + ApplyOperationError::Transfer( + TransferError::BalanceTooLow( + BalanceTooLow { + contract: Contract::from_b58check("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx").unwrap(), + balance: 10_u64.into(), + amount: 21_u64.into() + } ) ), - OperationError::Apply( - ApplyOperationError::Transfer( - TransferError::BalanceTooLow( - BalanceTooLow { - contract: Contract::from_b58check("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN").unwrap(), - balance: 55_u64.into(), - amount: 1111_u64.into() - } - ) + ApplyOperationError::Transfer( + TransferError::BalanceTooLow( + BalanceTooLow { + contract: Contract::from_b58check("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN").unwrap(), + balance: 55_u64.into(), + amount: 1111_u64.into() + } ) ) ].into()), @@ -596,19 +578,18 @@ mod tests { { "operation_result": { "status": "failed", "errors": - [ "Apply(Transfer(BalanceTooLow(BalanceTooLow { contract: \"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx\", balance: Narith(10), amount: Narith(21) })))", - "Apply(Transfer(BalanceTooLow(BalanceTooLow { contract: \"tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN\", balance: Narith(55), amount: Narith(1111) })))" ] } } } ], + [ "Transfer(BalanceTooLow(BalanceTooLow { contract: Implicit(Ed25519(ContractTz1Hash(\"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx\"))), balance: Narith(10), amount: Narith(21) }))", + "Transfer(BalanceTooLow(BalanceTooLow { contract: Implicit(Ed25519(ContractTz1Hash(\"tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN\"))), balance: Narith(55), amount: Narith(1111) }))" ] } } } ], "signature": "sigvVF2FguUHvZHytQ4AoRn4R6tSMteAt4nEHfYEbwQi3nXa3xvsgE93V1XYL99FYFUAH83iSpcAe7KxGaAeE1tLJ3M2jGJT" }' */ #[test] fn tezos_compatibility_for_failed_operation_with_metadata() { let operation = dummy_failed_operation(); - let mut output = vec![]; - operation - .bin_write(output.as_mut()) + let output = operation + .to_bytes() .expect("Operation with metadata should be encodable"); - let operation_and_receipt_bytes = "00000001c56c0002298c03ed7d454a101eb7022bc95f7e5f41ac78ff010100008080a8ec85afd1310000e7670f32038107a59a2b9cfefae36ea21f5aa63c0000000000010000017e000000baba00000082b00000004170706c79285472616e736665722842616c616e6365546f6f4c6f772842616c616e6365546f6f4c6f77207b20636f6e74726163743a20496d706c69636974284564323535313928436f6e7472616374547a31486173682822747a314b715470455a37596f62375162504534487934576f38664847384c684b785a5378222929292c2062616c616e63653a204e6172697468283130292c20616d6f756e743a204e617269746828323129207d2929290000000000bcbc00000082b20000004170706c79285472616e736665722842616c616e6365546f6f4c6f772842616c616e6365546f6f4c6f77207b20636f6e74726163743a20496d706c69636974284564323535313928436f6e7472616374547a31486173682822747a31676a614638315a525276647a6a6f627966564e7341655343365053636a6651774e222929292c2062616c616e63653a204e6172697468283535292c20616d6f756e743a204e6172697468283131313129207d292929000000000000f868f45f51a0c7a5733ab2c7f29781303904d9ef5b8fbf7b96429f00fe487c1d0f174c205b49c7393e5436b9522b88d3951113c32115e518465e029439874306"; + let operation_and_receipt_bytes = "00000001b76c0002298c03ed7d454a101eb7022bc95f7e5f41ac78ff010100008080a8ec85afd1310000e7670f32038107a59a2b9cfefae36ea21f5aa63c00000000000100000170000000b3b300000082a90000005472616e736665722842616c616e6365546f6f4c6f772842616c616e6365546f6f4c6f77207b20636f6e74726163743a20496d706c69636974284564323535313928436f6e7472616374547a31486173682822747a314b715470455a37596f62375162504534487934576f38664847384c684b785a5378222929292c2062616c616e63653a204e6172697468283130292c20616d6f756e743a204e617269746828323129207d29290000000000b5b500000082ab0000005472616e736665722842616c616e6365546f6f4c6f772842616c616e6365546f6f4c6f77207b20636f6e74726163743a20496d706c69636974284564323535313928436f6e7472616374547a31486173682822747a31676a614638315a525276647a6a6f627966564e7341655343365053636a6651774e222929292c2062616c616e63653a204e6172697468283535292c20616d6f756e743a204e6172697468283131313129207d2929000000000000f868f45f51a0c7a5733ab2c7f29781303904d9ef5b8fbf7b96429f00fe487c1d0f174c205b49c7393e5436b9522b88d3951113c32115e518465e029439874306"; assert_eq!(hex::encode(output), operation_and_receipt_bytes); } diff --git a/etherlink/kernel_latest/tezos_execution/src/lib.rs b/etherlink/kernel_latest/tezos_execution/src/lib.rs index caedf91aa356..8207384089c7 100644 --- a/etherlink/kernel_latest/tezos_execution/src/lib.rs +++ b/etherlink/kernel_latest/tezos_execution/src/lib.rs @@ -26,8 +26,8 @@ use tezos_tezlink::{ }, operation_result::{ is_applied, produce_operation_result, Balance, BalanceTooLow, BalanceUpdate, - OperationError, OperationResultSum, Reveal, RevealError, RevealSuccess, - TransferError, TransferSuccess, UpdateOrigin, ValidityError, + OperationError, OperationResultSum, RevealError, RevealSuccess, TransferError, + TransferSuccess, UpdateOrigin, ValidityError, }, }; use validate::ValidationInfo; @@ -483,13 +483,8 @@ pub fn validate_and_apply_operation( Ok(validation_info) => validation_info, Err(validity_err) => { log!(safe_host, Debug, "Operation is invalid: {:?}", validity_err); - // TODO: Don't force the receipt to a reveal receipt - let receipt = produce_operation_result::( - vec![], - Err(OperationError::Validation(validity_err)), - ); safe_host.revert()?; - return Ok(OperationResultSum::Reveal(receipt)); + return Err(OperationError::Validation(validity_err)); } }; @@ -502,13 +497,10 @@ pub fn validate_and_apply_operation( .is_err() { log!(safe_host, Debug, "Could not update balance!"); - // TODO: Don't force the receipt to a reveal receipt - let receipt = produce_operation_result::( - vec![], - Err(ValidityError::FailedToUpdateBalance.into()), - ); safe_host.revert()?; - return Ok(OperationResultSum::Reveal(receipt)); + return Err(OperationError::Validation( + ValidityError::FailedToUpdateBalance, + )); }; safe_host.promote()?; @@ -817,27 +809,16 @@ mod tests { let operation = make_reveal_operation(15, 1, 4, 5, source); - let receipt = validate_and_apply_operation( + let result = validate_and_apply_operation( &mut host, &context::Context::init_context(), operation, - ) - .expect( - "validate_and_apply_operation should not have failed with a kernel error", ); - let expected_receipt = OperationResultSum::Reveal(OperationResult { - balance_updates: vec![], - result: ContentResult::Failed( - vec![OperationError::Validation( - ValidityError::EmptyImplicitContract, - )] - .into(), - ), - internal_operation_results: vec![], - }); + let expected_error = + OperationError::Validation(ValidityError::EmptyImplicitContract); - assert_eq!(receipt, expected_receipt); + assert_eq!(result, Err(expected_error)); } // Test that increasing the fees makes the operation fails @@ -852,27 +833,16 @@ mod tests { // Fees are too high for source's balance let operation = make_reveal_operation(100, 1, 4, 5, source); - let receipt = validate_and_apply_operation( + let result = validate_and_apply_operation( &mut host, &context::Context::init_context(), operation, - ) - .expect( - "validate_and_apply_operation should not have failed with a kernel error", ); - let expected_receipt = OperationResultSum::Reveal(OperationResult { - balance_updates: vec![], - result: ContentResult::Failed( - vec![OperationError::Validation(ValidityError::CantPayFees( - 100_u64.into(), - ))] - .into(), - ), - internal_operation_results: vec![], - }); + let expected_error = + OperationError::Validation(ValidityError::CantPayFees(100_u64.into())); - assert_eq!(receipt, expected_receipt); + assert_eq!(result, Err(expected_error)); } // Test that a wrong counter should make the operation fails @@ -887,29 +857,18 @@ mod tests { // Counter is incoherent for source's counter let operation = make_reveal_operation(15, 15, 4, 5, source); - let receipt = validate_and_apply_operation( + let result = validate_and_apply_operation( &mut host, &context::Context::init_context(), operation, - ) - .expect( - "validate_and_apply_operation should not have failed with a kernel error", ); - let expected_receipt = OperationResultSum::Reveal(OperationResult { - balance_updates: vec![], - result: ContentResult::Failed( - vec![OperationError::Validation( - ValidityError::CounterInTheFuture(CounterError { - expected: 1_u64.into(), - found: 15_u64.into(), - }), - )] - .into(), - ), - internal_operation_results: vec![], - }); - assert_eq!(receipt, expected_receipt); + let expected_error = + OperationError::Validation(ValidityError::CounterInTheFuture(CounterError { + expected: 1_u64.into(), + found: 15_u64.into(), + })); + assert_eq!(result, Err(expected_error)); } // At this point, tests are focused on the content of the operation. We should not revert with ValidityError anymore. @@ -959,10 +918,7 @@ mod tests { }, ], result: ContentResult::Failed( - vec![OperationError::Apply( - RevealError::PreviouslyRevealedKey(pk).into(), - )] - .into(), + vec![RevealError::PreviouslyRevealedKey(pk).into()].into(), ), internal_operation_results: vec![], }); @@ -1013,10 +969,7 @@ mod tests { }, ], result: ContentResult::Failed( - vec![OperationError::Apply( - RevealError::InconsistentHash(inconsistent_pkh).into(), - )] - .into(), + vec![RevealError::InconsistentHash(inconsistent_pkh).into()].into(), ), internal_operation_results: vec![], }); @@ -1047,24 +1000,15 @@ mod tests { let operation = make_reveal_operation(15, 1, 4, 5, source.clone()); - let receipt = validate_and_apply_operation( + let result = validate_and_apply_operation( &mut host, &context::Context::init_context(), operation, - ) - .expect( - "validate_and_apply_operation should not have failed with a kernel error", ); - let expected_receipt = OperationResultSum::Reveal(OperationResult { - balance_updates: vec![], - result: ContentResult::Failed( - vec![OperationError::Validation(ValidityError::InvalidSignature)].into(), - ), - internal_operation_results: vec![], - }); + let expected_error = OperationError::Validation(ValidityError::InvalidSignature); - assert_eq!(receipt, expected_receipt); + assert_eq!(result, Err(expected_error)); } // Test a valid reveal operation, the manager should go from NotRevealed to Revealed @@ -1175,14 +1119,12 @@ mod tests { }, ], result: ContentResult::Failed( - vec![OperationError::Apply( - TransferError::BalanceTooLow(BalanceTooLow { - contract: Contract::Implicit(source.pkh), - balance: 35_u64.into(), - amount: 100_u64.into(), - }) - .into(), - )] + vec![TransferError::BalanceTooLow(BalanceTooLow { + contract: Contract::Implicit(source.pkh), + balance: 35_u64.into(), + amount: 100_u64.into(), + }) + .into()] .into(), ), internal_operation_results: vec![], @@ -1572,11 +1514,11 @@ mod tests { }, ], result: ContentResult::Failed(vec![ - OperationError::Apply(ApplyOperationError::Transfer( + ApplyOperationError::Transfer( TransferError::MichelsonContractInterpretError( "runtime failure while running the script: failed with: String(\"This contract always fails\") of type String".into() ) - ))].into()), + )].into()), internal_operation_results: vec![], }); @@ -1642,9 +1584,9 @@ mod tests { }, ], result: ContentResult::Failed( - vec![OperationError::Apply(ApplyOperationError::Transfer( + vec![ApplyOperationError::Transfer( TransferError::NonSmartContractExecutionCall, - ))] + )] .into(), ), internal_operation_results: vec![], @@ -1703,9 +1645,9 @@ mod tests { }, ], result: ContentResult::Failed( - vec![OperationError::Apply(ApplyOperationError::Transfer( + vec![ApplyOperationError::Transfer( TransferError::NonSmartContractExecutionCall, - ))] + )] .into(), ), internal_operation_results: vec![], -- GitLab From b6ff4be6c77ad65a754884d0505736149cb228dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Cauderlier?= Date: Fri, 1 Aug 2025 10:44:05 +0200 Subject: [PATCH 8/8] Tezlink/Kernel: drop invalid operations --- etherlink/kernel_latest/kernel/src/chains.rs | 21 +++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index ce24fcd3b551..cd5b9f646355 100644 --- a/etherlink/kernel_latest/kernel/src/chains.rs +++ b/etherlink/kernel_latest/kernel/src/chains.rs @@ -41,7 +41,8 @@ use tezos_tezlink::{ enc_wrappers::BlockNumber, operation::Operation, operation_result::{ - OperationBatchWithMetadata, OperationDataAndMetadata, OperationWithMetadata, + OperationBatchWithMetadata, OperationDataAndMetadata, OperationError, + OperationWithMetadata, }, }; @@ -511,11 +512,25 @@ impl ChainConfigTrait for MichelsonChainConfig { // Try to apply the operation with the tezos_execution crate, return a receipt // on whether it failed or not - let receipt = tezos_execution::validate_and_apply_operation( + let receipt = match tezos_execution::validate_and_apply_operation( host, &context, operation.clone(), - )?; + ) { + Ok(receipt) => receipt, + Err(OperationError::Validation(err)) => { + log!( + host, + Error, + "Found an invalid operation, dropping it: {:?}", + err + ); + continue; + } + Err(OperationError::RuntimeError(err)) => { + return Err(err.into()); + } + }; // Compute the hash of the operation let hash = operation.hash()?; -- GitLab