Skip to content

Commit 34e86f6

Browse files
authored
Support custom ResourceControlPolicy in integration tests (#3505)
## Motivation In integration tests, the `ResourceControlPolicy` was hardcoded to use the default value. With the addition of an HTTP allow list (#3427), the tests aren't able to test any HTTP requests. ## Proposal Allow changing the `ResourceControlPolicy` used inside a test, allowing to add hosts to the allow list. For the policy change to work, a new committee and epoch must be published. Therefore the epoch and committee can't be assumed to be constant anymore. ## Test Plan Wrote some (upcoming) tests that try to perform an HTTP request without changing the policy and after adding the host to the policy, and ensured that the former fails while the latter succeeds. ## Release Plan - These changes follow the usual release cycle, because this will help with tests that use a feature that has not yet been released. ## Links - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
1 parent 4075c1b commit 34e86f6

File tree

4 files changed

+90
-18
lines changed

4 files changed

+90
-18
lines changed

linera-execution/src/committee.rs

+5
Original file line numberDiff line numberDiff line change
@@ -380,4 +380,9 @@ impl Committee {
380380
pub fn policy(&self) -> &ResourceControlPolicy {
381381
&self.policy
382382
}
383+
384+
/// Returns a mutable reference to this committee's [`ResourceControlPolicy`].
385+
pub fn policy_mut(&mut self) -> &mut ResourceControlPolicy {
386+
&mut self.policy
387+
}
383388
}

linera-sdk/src/test/block.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use linera_chain::{
1919
types::{ConfirmedBlock, ConfirmedBlockCertificate},
2020
};
2121
use linera_execution::{
22+
committee::Epoch,
2223
system::{Recipient, SystemChannel, SystemOperation},
2324
Operation,
2425
};
@@ -48,6 +49,7 @@ impl BlockBuilder {
4849
pub(crate) fn new(
4950
chain_id: ChainId,
5051
owner: Owner,
52+
epoch: Epoch,
5153
previous_block: Option<&ConfirmedBlockCertificate>,
5254
validator: TestValidator,
5355
) -> Self {
@@ -64,7 +66,7 @@ impl BlockBuilder {
6466

6567
BlockBuilder {
6668
block: ProposedBlock {
67-
epoch: 0.into(),
69+
epoch,
6870
chain_id,
6971
incoming_bundles: vec![],
7072
operations: vec![],
@@ -224,7 +226,8 @@ impl BlockBuilder {
224226
Round::Fast,
225227
self.validator.key_pair(),
226228
);
227-
let mut builder = SignatureAggregator::new(value, Round::Fast, self.validator.committee());
229+
let committee = self.validator.committee().await;
230+
let mut builder = SignatureAggregator::new(value, Round::Fast, &committee);
228231
let certificate = builder
229232
.append(vote.public_key, vote.signature)
230233
.expect("Failed to sign block")

linera-sdk/src/test/chain.rs

+16
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use linera_base::{
2222
use linera_chain::{types::ConfirmedBlockCertificate, ChainError, ChainExecutionContext};
2323
use linera_core::{data_types::ChainInfoQuery, worker::WorkerError};
2424
use linera_execution::{
25+
committee::Epoch,
2526
system::{
2627
SystemExecutionError, SystemOperation, SystemQuery, SystemResponse,
2728
CREATE_APPLICATION_MESSAGE_INDEX,
@@ -93,6 +94,20 @@ impl ActiveChain {
9394
self.key_pair = key_pair
9495
}
9596

97+
/// Returns the current [`Epoch`] the chain is in.
98+
pub async fn epoch(&self) -> Epoch {
99+
self.validator
100+
.worker()
101+
.chain_state_view(self.id())
102+
.await
103+
.expect("Failed to load chain")
104+
.execution_state
105+
.system
106+
.epoch
107+
.get()
108+
.expect("Active chains should be in an epoch")
109+
}
110+
96111
/// Reads the current shared balance available to all of the owners of this microchain.
97112
pub async fn chain_balance(&self) -> Amount {
98113
let query = Query::System(SystemQuery);
@@ -244,6 +259,7 @@ impl ActiveChain {
244259
let mut block = BlockBuilder::new(
245260
self.description.into(),
246261
self.key_pair.public().into(),
262+
self.epoch().await,
247263
tip.as_ref(),
248264
self.validator.clone(),
249265
);

linera-sdk/src/test/validator.rs

+64-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
use std::{num::NonZeroUsize, sync::Arc};
1010

1111
use dashmap::DashMap;
12-
use futures::FutureExt as _;
12+
use futures::{
13+
lock::{MappedMutexGuard, Mutex, MutexGuard},
14+
FutureExt as _,
15+
};
1316
use linera_base::{
1417
crypto::{AccountSecretKey, ValidatorKeypair, ValidatorSecretKey},
1518
data_types::{Amount, ApplicationPermissions, Timestamp},
@@ -19,8 +22,10 @@ use linera_base::{
1922
use linera_core::worker::WorkerState;
2023
use linera_execution::{
2124
committee::{Committee, Epoch},
22-
system::{OpenChainConfig, SystemOperation, OPEN_CHAIN_MESSAGE_INDEX},
23-
WasmRuntime,
25+
system::{
26+
AdminOperation, OpenChainConfig, SystemChannel, SystemOperation, OPEN_CHAIN_MESSAGE_INDEX,
27+
},
28+
ResourceControlPolicy, WasmRuntime,
2429
};
2530
use linera_storage::{DbStorage, Storage, TestClock};
2631
use linera_views::memory::MemoryStore;
@@ -45,7 +50,7 @@ use crate::ContractAbi;
4550
pub struct TestValidator {
4651
validator_secret: ValidatorSecretKey,
4752
account_secret: AccountSecretKey,
48-
committee: Committee,
53+
committee: Arc<Mutex<(Epoch, Committee)>>,
4954
storage: DbStorage<MemoryStore, TestClock>,
5055
worker: WorkerState<DbStorage<MemoryStore, TestClock>>,
5156
clock: TestClock,
@@ -71,10 +76,13 @@ impl TestValidator {
7176
pub async fn new() -> Self {
7277
let validator_keypair = ValidatorKeypair::generate();
7378
let account_secret = AccountSecretKey::generate();
74-
let committee = Committee::make_simple(vec![(
75-
validator_keypair.public_key,
76-
account_secret.public(),
77-
)]);
79+
let committee = Arc::new(Mutex::new((
80+
Epoch::ZERO,
81+
Committee::make_simple(vec![(
82+
validator_keypair.public_key,
83+
account_secret.public(),
84+
)]),
85+
)));
7886
let wasm_runtime = Some(WasmRuntime::default());
7987
let storage = DbStorage::<MemoryStore, _>::make_test_storage(wasm_runtime)
8088
.now_or_never()
@@ -166,11 +174,50 @@ impl TestValidator {
166174
&self.validator_secret
167175
}
168176

169-
/// Returns the committee that this test validator is part of.
177+
/// Returns the latest committee that this test validator is part of.
170178
///
171179
/// The committee contains only this validator.
172-
pub fn committee(&self) -> &Committee {
173-
&self.committee
180+
pub async fn committee(&self) -> MappedMutexGuard<'_, (Epoch, Committee), Committee> {
181+
MutexGuard::map(self.committee.lock().await, |(_epoch, committee)| committee)
182+
}
183+
184+
/// Updates the admin chain, creating a new epoch with an updated
185+
/// [`ResourceControlPolicy`].
186+
pub async fn change_resource_control_policy(
187+
&self,
188+
adjustment: impl FnOnce(&mut ResourceControlPolicy),
189+
) {
190+
let (epoch, committee) = {
191+
let (ref mut epoch, ref mut committee) = &mut *self.committee.lock().await;
192+
193+
epoch
194+
.try_add_assign_one()
195+
.expect("Reached the limit of epochs");
196+
197+
adjustment(committee.policy_mut());
198+
199+
(*epoch, committee.clone())
200+
};
201+
202+
let admin_chain = self.get_chain(&ChainId::root(0));
203+
204+
let certificate = admin_chain
205+
.add_block(|block| {
206+
block.with_system_operation(SystemOperation::Admin(
207+
AdminOperation::CreateCommittee { epoch, committee },
208+
));
209+
})
210+
.await;
211+
212+
for entry in self.chains.iter() {
213+
let chain = entry.value();
214+
215+
chain
216+
.add_block(|block| {
217+
block.with_system_messages_from(&certificate, SystemChannel::Admin);
218+
})
219+
.await;
220+
}
174221
}
175222

176223
/// Creates a new microchain and returns the [`ActiveChain`] that can be used to add blocks to
@@ -210,13 +257,13 @@ impl TestValidator {
210257
.get(&admin_id)
211258
.expect("Admin chain should be created when the `TestValidator` is constructed");
212259

260+
let (epoch, committee) = self.committee.lock().await.clone();
261+
213262
let new_chain_config = OpenChainConfig {
214263
ownership: ChainOwnership::single(owner),
215-
committees: [(Epoch::ZERO, self.committee.clone())]
216-
.into_iter()
217-
.collect(),
264+
committees: [(epoch, committee)].into_iter().collect(),
218265
admin_id,
219-
epoch: Epoch::ZERO,
266+
epoch,
220267
balance: Amount::ZERO,
221268
application_permissions: ApplicationPermissions::default(),
222269
};
@@ -244,11 +291,12 @@ impl TestValidator {
244291
async fn create_admin_chain(&self) {
245292
let key_pair = AccountSecretKey::generate();
246293
let description = ChainDescription::Root(0);
294+
let committee = self.committee.lock().await.1.clone();
247295

248296
self.worker()
249297
.storage_client()
250298
.create_chain(
251-
self.committee.clone(),
299+
committee,
252300
ChainId::root(0),
253301
description,
254302
key_pair.public().into(),

0 commit comments

Comments
 (0)