From 1fb6b00f6a4f7d8c989d88440f5a22d7586a79b7 Mon Sep 17 00:00:00 2001 From: Andreas Fackler Date: Sat, 9 Nov 2024 13:16:29 +0100 Subject: [PATCH] In prepare_chain, ensure validate_incoming_bundles is OK. (#2835) * In prepare_chain, ensure validate_incoming_bundles is OK. * Add two epochs in CI before starting the faucet. * Box the largest error variants. --- .github/workflows/rust.yml | 6 +- linera-chain/src/chain.rs | 70 ++++++++----------- linera-chain/src/inbox.rs | 8 +-- linera-chain/src/lib.rs | 25 +++++-- linera-chain/src/unit_tests/chain_tests.rs | 4 +- .../chain_worker/state/attempted_changes.rs | 4 +- linera-core/src/client/mod.rs | 21 ++++-- linera-core/src/data_types.rs | 1 - linera-core/src/local_node.rs | 17 +++-- linera-core/src/node.rs | 23 +++--- linera-core/src/unit_tests/client_tests.rs | 34 +++++---- linera-core/src/unit_tests/worker_tests.rs | 38 ++++------ linera-core/src/worker.rs | 4 +- linera-sdk/src/test/chain.rs | 5 +- 14 files changed, 138 insertions(+), 122 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 73d58ad0047..571aca02999 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -59,10 +59,12 @@ jobs: cargo build --features storage-service mkdir /tmp/local-linera-net cargo run --features storage-service --bin linera -- net up --storage service:tcp:localhost:1235:table --policy-config devnet --path /tmp/local-linera-net --validators 4 --shards 4 & - - name: Run the faucet + - name: Create two epochs and run the faucet run: | cargo build --bin linera - cargo run --bin linera -- faucet --amount 1000 --port 8079 & + cargo run --bin linera -- resource-control-policy --block 0.0000001 + cargo run --bin linera -- resource-control-policy --block 0.000000 + cargo run --bin linera -- faucet --amount 1000 --port 8079 69705f85ac4c9fef6c02b4d83426aaaf05154c645ec1c61665f8e450f0468bc0 & - name: Run the remote-net tests run: | cargo test -p linera-service remote_net_grpc --features remote-net diff --git a/linera-chain/src/chain.rs b/linera-chain/src/chain.rs index 9bc4cde820d..f247f69261d 100644 --- a/linera-chain/src/chain.rs +++ b/linera-chain/src/chain.rs @@ -22,10 +22,10 @@ use linera_base::{ }, }; use linera_execution::{ - system::OpenChainConfig, ExecutionError, ExecutionOutcome, ExecutionRuntimeContext, - ExecutionStateView, Message, MessageContext, Operation, OperationContext, Query, QueryContext, - RawExecutionOutcome, RawOutgoingMessage, ResourceController, ResourceTracker, Response, - ServiceRuntimeEndpoint, TransactionTracker, + system::OpenChainConfig, ExecutionOutcome, ExecutionRuntimeContext, ExecutionStateView, + Message, MessageContext, Operation, OperationContext, Query, QueryContext, RawExecutionOutcome, + RawOutgoingMessage, ResourceController, ResourceTracker, Response, ServiceRuntimeEndpoint, + TransactionTracker, }; use linera_views::{ context::Context, @@ -46,7 +46,7 @@ use crate::{ inbox::{Cursor, InboxError, InboxStateView}, manager::ChainManager, outbox::OutboxStateView, - ChainError, ChainExecutionContext, + ChainError, ChainExecutionContext, ExecutionResultExt, }; #[cfg(test)] @@ -385,12 +385,10 @@ where next_block_height: self.tip_state.get().next_block_height, local_time, }; - let response = self - .execution_state + self.execution_state .query_application(context, query, service_runtime_endpoint) .await - .map_err(|error| ChainError::ExecutionError(error, ChainExecutionContext::Query))?; - Ok(response) + .with_execution_context(ChainExecutionContext::Query) } pub async fn describe_application( @@ -402,9 +400,7 @@ where .registry .describe_application(application_id) .await - .map_err(|err| { - ChainError::ExecutionError(err.into(), ChainExecutionContext::DescribeApplication) - }) + .with_execution_context(ChainExecutionContext::DescribeApplication) } pub async fn mark_messages_as_received( @@ -745,7 +741,7 @@ where resource_controller .track_executed_block_size_sequence_extension(0, block.operations.len()) }) - .map_err(|err| ChainError::ExecutionError(err, ChainExecutionContext::Block))?; + .with_execution_context(ChainExecutionContext::Block)?; if self.is_closed() { ensure!( @@ -793,8 +789,6 @@ where Transaction::ReceiveMessages(_) => ChainExecutionContext::IncomingBundle(txn_index), Transaction::ExecuteOperation(_) => ChainExecutionContext::Operation(txn_index), }; - let with_context = - |error: ExecutionError| ChainError::ExecutionError(error, chain_execution_context); let maybe_responses = match replaying_oracle_responses.as_mut().map(Iterator::next) { Some(Some(responses)) => Some(responses), Some(None) => return Err(ChainError::MissingOracleResponseList), @@ -805,7 +799,7 @@ where Transaction::ReceiveMessages(incoming_bundle) => { resource_controller .track_executed_block_size_of(&incoming_bundle) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; for (message_id, posted_message) in incoming_bundle.messages_and_ids() { self.execute_message_in_block( message_id, @@ -823,7 +817,7 @@ where Transaction::ExecuteOperation(operation) => { resource_controller .track_executed_block_size_of(&operation) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; #[cfg(with_metrics)] let _operation_latency = OPERATION_EXECUTION_LATENCY.measure_latency(); let context = OperationContext { @@ -842,21 +836,22 @@ where &mut resource_controller, ) .await - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; resource_controller .with_state(&mut self.execution_state) .await? .track_operation(operation) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; } } self.execution_state .update_execution_outcomes_with_app_registrations(&mut txn_tracker) .await - .map_err(with_context)?; - let (txn_outcomes, txn_oracle_responses, new_next_message_index) = - txn_tracker.destructure().map_err(with_context)?; + .with_execution_context(chain_execution_context)?; + let (txn_outcomes, txn_oracle_responses, new_next_message_index) = txn_tracker + .destructure() + .with_execution_context(chain_execution_context)?; next_message_index = new_next_message_index; let (txn_messages, txn_events) = self .process_execution_outcomes(block.height, txn_outcomes) @@ -874,21 +869,21 @@ where .with_state(&mut self.execution_state) .await? .track_message(&message_out.message) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; } } resource_controller .track_executed_block_size_of(&(&txn_oracle_responses, &txn_messages, &txn_events)) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; resource_controller .track_executed_block_size_sequence_extension(oracle_responses.len(), 1) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; resource_controller .track_executed_block_size_sequence_extension(messages.len(), 1) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; resource_controller .track_executed_block_size_sequence_extension(events.len(), 1) - .map_err(with_context)?; + .with_execution_context(chain_execution_context)?; oracle_responses.push(txn_oracle_responses); messages.push(txn_messages); events.push(txn_events); @@ -901,7 +896,7 @@ where .with_state(&mut self.execution_state) .await? .track_block() - .map_err(|err| ChainError::ExecutionError(err, ChainExecutionContext::Block))?; + .with_execution_context(ChainExecutionContext::Block)?; } // Recompute the state hash. @@ -978,10 +973,6 @@ where let mut grant = posted_message.grant; match incoming_bundle.action { MessageAction::Accept => { - let with_context = |error: ExecutionError| { - let context = ChainExecutionContext::IncomingBundle(txn_index); - ChainError::ExecutionError(error, context) - }; // Once a chain is closed, accepting incoming messages is not allowed. ensure!(!self.is_closed(), ChainError::ClosedChain); @@ -995,20 +986,19 @@ where resource_controller, ) .await - .map_err(with_context)?; + .with_execution_context(ChainExecutionContext::IncomingBundle(txn_index))?; if grant > Amount::ZERO { if let Some(refund_grant_to) = posted_message.refund_grant_to { self.execution_state .send_refund(context, grant, refund_grant_to, txn_tracker) .await - .map_err(with_context)?; + .with_execution_context(ChainExecutionContext::IncomingBundle( + txn_index, + ))?; } } } MessageAction::Reject => { - let with_context = |error: ExecutionError| { - ChainError::ExecutionError(error, ChainExecutionContext::Block) - }; // If rejecting a message fails, the entire block proposal should be // scrapped. ensure!( @@ -1016,7 +1006,7 @@ where ChainError::CannotRejectMessage { chain_id: block.chain_id, origin: Box::new(incoming_bundle.origin.clone()), - posted_message: posted_message.clone(), + posted_message: Box::new(posted_message.clone()), } ); if posted_message.is_tracked() { @@ -1024,7 +1014,7 @@ where self.execution_state .bounce_message(context, grant, posted_message.message.clone(), txn_tracker) .await - .map_err(with_context)?; + .with_execution_context(ChainExecutionContext::Block)?; } else if grant > Amount::ZERO { // Nothing to do except maybe refund the grant. let Some(refund_grant_to) = posted_message.refund_grant_to else { @@ -1037,7 +1027,7 @@ where self.execution_state .send_refund(context, posted_message.grant, refund_grant_to, txn_tracker) .await - .map_err(with_context)?; + .with_execution_context(ChainExecutionContext::Block)?; } } } diff --git a/linera-chain/src/inbox.rs b/linera-chain/src/inbox.rs index ad73b8bc5d7..d513b2f1bc7 100644 --- a/linera-chain/src/inbox.rs +++ b/linera-chain/src/inbox.rs @@ -126,8 +126,8 @@ impl From<(ChainId, Origin, InboxError)> for ChainError { } => ChainError::UnexpectedMessage { chain_id, origin: origin.into(), - bundle, - previous_bundle, + bundle: Box::new(bundle), + previous_bundle: Box::new(previous_bundle), }, InboxError::IncorrectOrder { bundle, @@ -135,14 +135,14 @@ impl From<(ChainId, Origin, InboxError)> for ChainError { } => ChainError::IncorrectMessageOrder { chain_id, origin: origin.into(), - bundle, + bundle: Box::new(bundle), next_height: next_cursor.height, next_index: next_cursor.index, }, InboxError::UnskippableBundle { bundle } => ChainError::CannotSkipMessage { chain_id, origin: origin.into(), - bundle, + bundle: Box::new(bundle), }, } } diff --git a/linera-chain/src/lib.rs b/linera-chain/src/lib.rs index 66f9ab2d9e4..b67e8af3111 100644 --- a/linera-chain/src/lib.rs +++ b/linera-chain/src/lib.rs @@ -34,7 +34,7 @@ pub enum ChainError { #[error("Error in view operation: {0}")] ViewError(#[from] ViewError), #[error("Execution error: {0} during {1:?}")] - ExecutionError(ExecutionError, ChainExecutionContext), + ExecutionError(Box, ChainExecutionContext), #[error("The chain being queried is not active {0:?}")] InactiveChain(ChainId), @@ -54,8 +54,8 @@ pub enum ChainError { UnexpectedMessage { chain_id: ChainId, origin: Box, - bundle: MessageBundle, - previous_bundle: MessageBundle, + bundle: Box, + previous_bundle: Box, }, #[error( "Message in block proposed to {chain_id:?} is out of order compared to previous messages \ @@ -65,7 +65,7 @@ pub enum ChainError { IncorrectMessageOrder { chain_id: ChainId, origin: Box, - bundle: MessageBundle, + bundle: Box, next_height: BlockHeight, next_index: u32, }, @@ -76,7 +76,7 @@ pub enum ChainError { CannotRejectMessage { chain_id: ChainId, origin: Box, - posted_message: PostedMessage, + posted_message: Box, }, #[error( "Block proposed to {chain_id:?} is attempting to skip a message bundle \ @@ -85,7 +85,7 @@ pub enum ChainError { CannotSkipMessage { chain_id: ChainId, origin: Box, - bundle: MessageBundle, + bundle: Box, }, #[error( "Incoming message bundle in block proposed to {chain_id:?} has timestamp \ @@ -160,3 +160,16 @@ pub enum ChainExecutionContext { Operation(u32), Block, } + +trait ExecutionResultExt { + fn with_execution_context(self, context: ChainExecutionContext) -> Result; +} + +impl ExecutionResultExt for Result +where + E: Into, +{ + fn with_execution_context(self, context: ChainExecutionContext) -> Result { + self.map_err(|error| ChainError::ExecutionError(Box::new(error.into()), context)) + } +} diff --git a/linera-chain/src/unit_tests/chain_tests.rs b/linera-chain/src/unit_tests/chain_tests.rs index 15749b8525e..903a89d35c5 100644 --- a/linera-chain/src/unit_tests/chain_tests.rs +++ b/linera-chain/src/unit_tests/chain_tests.rs @@ -162,9 +162,9 @@ async fn test_block_size_limit() { assert_matches!( result, Err(ChainError::ExecutionError( - ExecutionError::ExecutedBlockTooLarge, + execution_error, ChainExecutionContext::Operation(1), - )) + )) if matches!(*execution_error, ExecutionError::ExecutedBlockTooLarge) ); // The valid block is accepted... diff --git a/linera-core/src/chain_worker/state/attempted_changes.rs b/linera-core/src/chain_worker/state/attempted_changes.rs index b27dbaba907..0954aee6d31 100644 --- a/linera-core/src/chain_worker/state/attempted_changes.rs +++ b/linera-core/src/chain_worker/state/attempted_changes.rs @@ -342,8 +342,8 @@ where ensure!( executed_block.outcome == verified_outcome, WorkerError::IncorrectOutcome { - submitted: executed_block.outcome.clone(), - computed: verified_outcome, + submitted: Box::new(executed_block.outcome.clone()), + computed: Box::new(verified_outcome), } ); // Advance to next block height. diff --git a/linera-core/src/client/mod.rs b/linera-core/src/client/mod.rs index aaddf0263f9..8ba37248112 100644 --- a/linera-core/src/client/mod.rs +++ b/linera-core/src/client/mod.rs @@ -987,7 +987,7 @@ where } /// Prepares the chain for the next operation, i.e. makes sure we have synchronized it up to - /// its current height. + /// its current height and are not missing any received messages from the inbox. #[instrument(level = "trace")] async fn prepare_chain(&self) -> Result, ChainClientError> { #[cfg(with_metrics)] @@ -1002,6 +1002,15 @@ where let nodes = self.validator_nodes().await?; info = self.synchronize_chain_state(&nodes, self.chain_id).await?; } + + let result = self + .chain_state_view() + .await? + .validate_incoming_bundles() + .await; + if matches!(result, Err(ChainError::MissingCrossChainUpdate { .. })) { + self.find_received_certificates().await?; + } self.update_from_info(&info); Ok(info) } @@ -2308,13 +2317,13 @@ where Err(ChainClientError::LocalNodeError(LocalNodeError::WorkerError( WorkerError::ChainError(error), ))) if matches!( - *error, + &*error, ChainError::ExecutionError( - ExecutionError::SystemError( - SystemExecutionError::InsufficientFundingForFees { .. } - ), + execution_error, ChainExecutionContext::Block - ) + ) if matches!(**execution_error, ExecutionError::SystemError( + SystemExecutionError::InsufficientFundingForFees { .. } + )) ) => { // We can't even pay for the execution of one empty block. Let's return zero. diff --git a/linera-core/src/data_types.rs b/linera-core/src/data_types.rs index af54a56d1b9..228d7d1b8bd 100644 --- a/linera-core/src/data_types.rs +++ b/linera-core/src/data_types.rs @@ -327,7 +327,6 @@ impl ClientOutcome { } } - #[expect(clippy::result_large_err)] pub fn try_map(self, f: F) -> Result, ChainClientError> where F: FnOnce(T) -> Result, diff --git a/linera-core/src/local_node.rs b/linera-core/src/local_node.rs index b82c0c8038d..c5e04807017 100644 --- a/linera-core/src/local_node.rs +++ b/linera-core/src/local_node.rs @@ -74,17 +74,16 @@ impl LocalNodeError { pub fn get_blobs_not_found(&self) -> Option> { match self { LocalNodeError::WorkerError(WorkerError::ChainError(chain_error)) => { - match **chain_error { - ChainError::ExecutionError( + match &**chain_error { + ChainError::ExecutionError(execution_error, _) => match **execution_error { ExecutionError::SystemError(SystemExecutionError::BlobNotFoundOnRead( blob_id, - )), - _, - ) - | ChainError::ExecutionError( - ExecutionError::ViewError(ViewError::BlobNotFoundOnRead(blob_id)), - _, - ) => Some(vec![blob_id]), + )) + | ExecutionError::ViewError(ViewError::BlobNotFoundOnRead(blob_id)) => { + Some(vec![blob_id]) + } + _ => None, + }, _ => None, } } diff --git a/linera-core/src/node.rs b/linera-core/src/node.rs index dd4d99ad145..85590b82dde 100644 --- a/linera-core/src/node.rs +++ b/linera-core/src/node.rs @@ -107,7 +107,6 @@ pub trait ValidatorNode { /// Turn an address into a validator node. #[cfg_attr(not(web), trait_variant::make(Send + Sync))] -#[expect(clippy::result_large_err)] pub trait ValidatorNodeProvider: 'static { #[cfg(not(web))] type Node: ValidatorNode + Send + Sync + Clone + 'static; @@ -174,7 +173,7 @@ pub enum NodeError { )] MissingCrossChainUpdate { chain_id: ChainId, - origin: Origin, + origin: Box, height: BlockHeight, }, @@ -283,18 +282,20 @@ impl From for NodeError { height, } => Self::MissingCrossChainUpdate { chain_id, - origin: *origin, + origin, height, }, ChainError::InactiveChain(chain_id) => Self::InactiveChain(chain_id), - ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::BlobNotFoundOnRead(blob_id)), - _, - ) - | ChainError::ExecutionError( - ExecutionError::ViewError(ViewError::BlobNotFoundOnRead(blob_id)), - _, - ) => Self::BlobNotFoundOnRead(blob_id), + ChainError::ExecutionError(execution_error, context) => match *execution_error { + ExecutionError::SystemError(SystemExecutionError::BlobNotFoundOnRead(blob_id)) + | ExecutionError::ViewError(ViewError::BlobNotFoundOnRead(blob_id)) => { + Self::BlobNotFoundOnRead(blob_id) + } + execution_error => Self::ChainError { + error: ChainError::ExecutionError(Box::new(execution_error), context) + .to_string(), + }, + }, error => Self::ChainError { error: error.to_string(), }, diff --git a/linera-core/src/unit_tests/client_tests.rs b/linera-core/src/unit_tests/client_tests.rs index c0ae8f2a8b2..e27e3a6e826 100644 --- a/linera-core/src/unit_tests/client_tests.rs +++ b/linera-core/src/unit_tests/client_tests.rs @@ -712,11 +712,11 @@ where result, Err(ChainClientError::LocalNodeError( LocalNodeError::WorkerError(WorkerError::ChainError(error)) - )) if matches!(&*error, ChainError::CannotSkipMessage { - bundle: MessageBundle { messages, .. }, .. - } if matches!(messages[..], [PostedMessage { - message: Message::System(SystemMessage::Credit { .. }), .. - }])) + )) if matches!(&*error, ChainError::CannotSkipMessage { bundle, .. } + if matches!(&**bundle, MessageBundle { messages, .. } + if matches!(messages[..], [PostedMessage { + message: Message::System(SystemMessage::Credit { .. }), .. + }]))) ); Ok(()) } @@ -1125,7 +1125,13 @@ where Account::chain(client3.chain_id), ) .await, - Err(ChainClientError::LocalNodeError(LocalNodeError::WorkerError(WorkerError::ChainError(error)))) if matches!(*error, ChainError::ExecutionError(ExecutionError::SystemError(SystemExecutionError::InsufficientFunding { .. }), ChainExecutionContext::Operation(_))) + Err(ChainClientError::LocalNodeError(LocalNodeError::WorkerError(WorkerError::ChainError( + error + )))) if matches!(&*error, ChainError::ExecutionError( + execution_error, ChainExecutionContext::Operation(_) + ) if matches!(**execution_error, ExecutionError::SystemError( + SystemExecutionError::InsufficientFunding { .. } + ))) ); // There is no pending block, since the proposal wasn't valid at the time. assert!(client2 @@ -1322,9 +1328,11 @@ where assert_matches!(obtained_error, Err(ChainClientError::LocalNodeError(LocalNodeError::WorkerError( WorkerError::ChainError(error) - ))) if matches!(*error, ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::InsufficientFunding { .. }), + ))) if matches!(&*error, ChainError::ExecutionError( + execution_error, ChainExecutionContext::Operation(0) + ) if matches!(**execution_error, + ExecutionError::SystemError(SystemExecutionError::InsufficientFunding { .. }) )) ); let obtained_error = sender @@ -1338,11 +1346,11 @@ where assert_matches!(obtained_error, Err(ChainClientError::LocalNodeError( LocalNodeError::WorkerError(WorkerError::ChainError(error)) - )) if matches!(*error, - ChainError::ExecutionError(ExecutionError::SystemError( - SystemExecutionError::InsufficientFundingForFees { .. } - ), ChainExecutionContext::Block) - ) + )) if matches!(&*error, ChainError::ExecutionError( + execution_error, ChainExecutionContext::Block + ) if matches!(**execution_error, ExecutionError::SystemError( + SystemExecutionError::InsufficientFundingForFees { .. } + ))) ); Ok(()) } diff --git a/linera-core/src/unit_tests/worker_tests.rs b/linera-core/src/unit_tests/worker_tests.rs index baceae147e5..6d9013122d9 100644 --- a/linera-core/src/unit_tests/worker_tests.rs +++ b/linera-core/src/unit_tests/worker_tests.rs @@ -482,13 +482,11 @@ where .await, Err( WorkerError::ChainError(error) - ) if matches!( - *error, - ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::IncorrectTransferAmount), - ChainExecutionContext::Operation(_) - ) - ) + ) if matches!(&*error, ChainError::ExecutionError( + execution_error, ChainExecutionContext::Operation(_) + ) if matches!(**execution_error, ExecutionError::SystemError( + SystemExecutionError::IncorrectTransferAmount + ))) ); let chain = worker.chain_state_view(ChainId::root(1)).await?; assert!(chain.is_active()); @@ -823,15 +821,11 @@ where worker.handle_block_proposal(block_proposal).await, Err( WorkerError::ChainError(error) - ) if matches!( - *error, - ChainError::ExecutionError( - ExecutionError::SystemError( - SystemExecutionError::InsufficientFunding { .. } - ), - ChainExecutionContext::Operation(_) - ) - ) + ) if matches!(&*error, ChainError::ExecutionError( + execution_error, ChainExecutionContext::Operation(_) + ) if matches!(**execution_error, ExecutionError::SystemError( + SystemExecutionError::InsufficientFunding { .. } + ))) ); } { @@ -1066,13 +1060,11 @@ where worker.handle_block_proposal(block_proposal).await, Err( WorkerError::ChainError(error) - ) if matches!( - *error, - ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::InsufficientFunding { .. }), - ChainExecutionContext::Operation(_) - ) - ) + ) if matches!(&*error, ChainError::ExecutionError( + execution_error, ChainExecutionContext::Operation(_) + ) if matches!(**execution_error, ExecutionError::SystemError( + SystemExecutionError::InsufficientFunding { .. } + ))) ); let chain = worker.chain_state_view(ChainId::root(1)).await?; assert!(chain.is_active()); diff --git a/linera-core/src/worker.rs b/linera-core/src/worker.rs index cc34917b4ca..fe61eb08714 100644 --- a/linera-core/src/worker.rs +++ b/linera-core/src/worker.rs @@ -188,8 +188,8 @@ pub enum WorkerError { " )] IncorrectOutcome { - computed: BlockExecutionOutcome, - submitted: BlockExecutionOutcome, + computed: Box, + submitted: Box, }, #[error("The timestamp of a Tick operation is in the future.")] InvalidTimestamp, diff --git a/linera-sdk/src/test/chain.rs b/linera-sdk/src/test/chain.rs index 340c7d5f030..54c2b41bd70 100644 --- a/linera-sdk/src/test/chain.rs +++ b/linera-sdk/src/test/chain.rs @@ -431,8 +431,11 @@ impl ActiveChain { if matches!( &*boxed_chain_error, ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::UnknownApplicationId(_)), + execution_error, ChainExecutionContext::DescribeApplication, + ) if matches!( + **execution_error, + ExecutionError::SystemError(SystemExecutionError::UnknownApplicationId(_)) ) ) => {