Skip to content

Commit b780463

Browse files
authored
Make some operations exempt from app permissions. (#3851)
## Motivation Chains with restricted block operations can't process e.g. new events because system operations are not allowed. ## Proposal Allow `Process*Epoch` and `UpdateStreams`. Enforce that `UpdateStreams` actually has new events. ## Test Plan A test was extended. ## Release Plan - These changes should be backported to the latest `testnet` branch, then - be released in a new SDK, - be released in a validator hotfix. ## Links - Fixes #3849. - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
1 parent 3263682 commit b780463

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

linera-chain/src/chain.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,10 @@ where
11001100
app_permissions.mandatory_applications.iter().cloned(),
11011101
);
11021102
for operation in &block.operations {
1103+
if operation.is_exempt_from_permissions() {
1104+
mandatory.clear();
1105+
continue;
1106+
}
11031107
ensure!(
11041108
app_permissions.can_execute_operations(&operation.application_id()),
11051109
ChainError::AuthorizedApplications(

linera-core/src/unit_tests/client_tests.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ mod wasm;
99
use assert_matches::assert_matches;
1010
use futures::StreamExt;
1111
use linera_base::{
12-
crypto::AccountSecretKey,
12+
crypto::{AccountSecretKey, CryptoHash},
1313
data_types::*,
14-
identifiers::{Account, AccountOwner, ChainId, MessageId},
14+
identifiers::{Account, AccountOwner, ApplicationId, ChainId, MessageId},
1515
ownership::{ChainOwnership, TimeoutConfig},
1616
};
1717
use linera_chain::{
@@ -1161,7 +1161,7 @@ where
11611161
assert_eq!(user.epoch().await.unwrap(), Epoch::from(1));
11621162

11631163
// Create a new committee.
1164-
let committee = Committee::new(validators, ResourceControlPolicy::only_fuel());
1164+
let committee = Committee::new(validators.clone(), ResourceControlPolicy::only_fuel());
11651165
admin.stage_new_committee(committee).await.unwrap();
11661166
assert_eq!(admin.next_block_height(), BlockHeight::from(5));
11671167
assert!(admin.pending_proposal().is_none());
@@ -1236,6 +1236,22 @@ where
12361236
admin.process_inbox().await.unwrap();
12371237
// Transfer goes through and the previous one as well thanks to block chaining.
12381238
assert_eq!(admin.local_balance().await.unwrap(), Amount::from_tokens(3));
1239+
1240+
user.change_application_permissions(ApplicationPermissions::new_single(ApplicationId::new(
1241+
CryptoHash::test_hash("foo"),
1242+
)))
1243+
.await?;
1244+
1245+
let committee = Committee::new(validators, ResourceControlPolicy::default());
1246+
admin.stage_new_committee(committee).await.unwrap();
1247+
assert_eq!(admin.epoch().await.unwrap(), Epoch::from(3));
1248+
1249+
// Despite the restrictive application permissions, some system operations are still allowed,
1250+
// and the user chain can migrate to the new epoch.
1251+
user.synchronize_from_validators().await?;
1252+
user.process_inbox().await?;
1253+
assert_eq!(user.epoch().await.unwrap(), Epoch::from(3));
1254+
12391255
Ok(())
12401256
}
12411257

linera-execution/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ pub enum ExecutionError {
333333
InternalError(&'static str),
334334
#[error("UpdateStreams contains an unknown event")]
335335
EventNotFound(EventId),
336+
#[error("UpdateStreams is outdated")]
337+
OutdatedUpdateStreams,
336338
}
337339

338340
impl From<ViewError> for ExecutionError {
@@ -1211,6 +1213,19 @@ impl Operation {
12111213
_ => vec![],
12121214
}
12131215
}
1216+
1217+
/// Returns whether this operation is allowed regardless of application permissions.
1218+
pub fn is_exempt_from_permissions(&self) -> bool {
1219+
let Operation::System(system_op) = self else {
1220+
return false;
1221+
};
1222+
matches!(
1223+
**system_op,
1224+
SystemOperation::ProcessNewEpoch(_)
1225+
| SystemOperation::ProcessRemovedEpoch(_)
1226+
| SystemOperation::UpdateStreams(_)
1227+
)
1228+
}
12141229
}
12151230

12161231
impl From<SystemMessage> for Message {

linera-execution/src/system.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -519,9 +519,10 @@ where
519519
.event_subscriptions
520520
.get_mut_or_default(&(chain_id, stream_id.clone()))
521521
.await?;
522-
if subscriptions.next_index >= next_index {
523-
continue;
524-
}
522+
ensure!(
523+
subscriptions.next_index < next_index,
524+
ExecutionError::OutdatedUpdateStreams
525+
);
525526
for application_id in &subscriptions.applications {
526527
txn_tracker.add_stream_to_process(
527528
*application_id,

0 commit comments

Comments
 (0)