Skip to content

Commit

Permalink
add note bloat and waste time TrustedCalls and cli (#1645)
Browse files Browse the repository at this point in the history
* add note bloat and waste time TrusstedCalls and cli

* bloating state and wasting time works

* fix ringbuffer size tracking

* clippy

* fix tests
  • Loading branch information
brenzi authored Nov 10, 2024
1 parent 157871f commit 22daaf9
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 18 deletions.
25 changes: 25 additions & 0 deletions app-libs/sgx-runtime/pallets/notes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,29 @@ pub mod pallet {
}
Ok(().into())
}

#[pallet::call_index(1)]
#[pallet::weight((10_000, DispatchClass::Normal, Pays::Yes))]
pub fn note_string(
origin: OriginFor<T>,
// who is involved in this note (usually sender and recipient)
link_to: Vec<T::AccountId>,
payload: Vec<u8>,
) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;
ensure!(link_to.len() < 3, Error::<T>::TooManyLinkedAccounts);
let note = TimestampedTrustedNote::<T::Moment> {
timestamp: Timestamp::<T>::get(),
version: NOTE_VERSION,
note: TrustedNote::String(payload),
};
let (bucket_index, note_index) = Self::store_note(note)?;

for account in link_to {
<NotesLookup<T>>::mutate(bucket_index, account, |v| v.push(note_index));
}
Ok(().into())
}
}
}

Expand Down Expand Up @@ -196,6 +219,8 @@ impl<T: Config> Pallet<T> {
if let Some(bucket) = Self::buckets(bucket_index) {
if bucket.bytes + free <= T::MaxBucketSize::get() {
return Ok(bucket)
} else {
<ClosedBucketsSize<T>>::mutate(|s| *s = s.saturating_add(bucket.bytes));
}
}
bucket_index.saturating_add(1)
Expand Down
61 changes: 56 additions & 5 deletions app-libs/sgx-runtime/pallets/notes/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,42 @@ fn enforce_retention_limits_works() {
assert_eq!(Notes::last_bucket_index(), Some(0));
assert_eq!(Notes::first_bucket_index(), Some(0));

let second_bucket_size = MaxBucketSize::get() - 100;
let bucket = BucketInfo {
index: 1,
bytes: second_bucket_size,
begins_at: Default::default(),
ends_at: Default::default(),
};
<Buckets<Test>>::insert(1, bucket);
<LastBucketIndex<Test>>::put(1);

let third_bucket_size = MaxBucketSize::get() - 100;
let bucket = BucketInfo {
index: 2,
bytes: third_bucket_size,
begins_at: Default::default(),
ends_at: Default::default(),
};
<Buckets<Test>>::insert(2, bucket);
<LastBucketIndex<Test>>::put(2);

let closed_buckets_size = MaxTotalSize::get() - MaxBucketSize::get() + 1;
<ClosedBucketsSize<Test>>::put(closed_buckets_size);

assert_eq!(Notes::get_bucket_with_room_for(500).unwrap().index, 0);
assert_eq!(Notes::get_bucket_with_room_for(99).unwrap().index, 2);

let new_bucket = Notes::get_bucket_with_room_for(512).unwrap();
assert_eq!(new_bucket.index, 1);
assert_eq!(new_bucket.index, 3);
assert_eq!(new_bucket.bytes, 0);
assert_eq!(Notes::last_bucket_index(), Some(1));
assert_eq!(Notes::first_bucket_index(), Some(1));
assert_eq!(Notes::last_bucket_index(), Some(3));
assert_eq!(Notes::first_bucket_index(), Some(2));
assert!(Notes::buckets(0).is_none());
assert_eq!(Notes::closed_buckets_size(), closed_buckets_size - first_bucket_size);
assert!(Notes::buckets(1).is_none());
assert_eq!(
Notes::closed_buckets_size(),
closed_buckets_size - first_bucket_size - second_bucket_size + third_bucket_size
);
});
}

Expand Down Expand Up @@ -209,3 +233,30 @@ fn note_trusted_call_works() {
);
})
}

#[test]
fn note_string_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
let now: u64 = 234;
set_timestamp(now);
let alice = AccountKeyring::Alice.to_account_id();
let bob = AccountKeyring::Bob.to_account_id();
let msg = "helllllooo Aliiicceee".to_string();
assert_ok!(Notes::note_string(
RuntimeOrigin::signed(bob.clone()),
[bob.clone(), alice.clone()].into(),
msg.encode()
));
assert_eq!(Notes::notes_lookup(0, alice.clone()), vec![0]);
assert_eq!(Notes::notes_lookup(0, bob.clone()), vec![0]);
let expected_note = TimestampedTrustedNote::<Moment> {
timestamp: now,
version: 1,
note: TrustedNote::String(msg.encode()),
};
assert_eq!(Notes::notes(0, 0), Some(expected_note.clone()));
let bucket = Notes::buckets(0).unwrap();
assert_eq!(bucket.bytes, expected_note.encoded_size() as u32);
})
}
13 changes: 10 additions & 3 deletions app-libs/sgx-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,20 @@ impl pallet_guess_the_number::Config for Runtime {
type MaxWinners = ConstU8<12>;
}

parameter_types! {
pub const MaxNoteSize: u32 = 512;
pub const MaxBucketSize: u32 = 51_200;
pub const MaxTotalSize: u32 = 5_120_000;
}

impl pallet_notes::Config for Runtime {
type MomentsPerDay = MomentsPerDay;
type Currency = Balances;
type MaxNoteSize = ConstU32<512>;
type MaxBucketSize = ConstU32<51200>;
type MaxTotalSize = ConstU32<5_120_000>;
type MaxNoteSize = MaxNoteSize;
type MaxBucketSize = MaxBucketSize;
type MaxTotalSize = MaxTotalSize;
}

// The plain sgx-runtime without the `evm-pallet`
#[cfg(not(feature = "evm"))]
construct_runtime!(
Expand Down
19 changes: 19 additions & 0 deletions app-libs/stf/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,25 @@ pub fn ensure_enclave_signer_account<AccountId: Encode + Decode + PartialEq>(
}
}

pub fn ensure_maintainer_account<AccountId: Encode + Decode + PartialEq + From<[u8; 32]>>(
account: &AccountId,
) -> StfResult<()> {
let expected_maintainer_account: AccountId = AccountId::from([
148, 117, 87, 242, 252, 96, 167, 29, 118, 69, 87, 119, 15, 57, 142, 82, 216, 8, 210, 102,
12, 213, 46, 76, 214, 5, 144, 153, 148, 113, 89, 95,
]);
if &expected_maintainer_account == account {
Ok(())
} else {
error!(
"Expected maintainer account {}, but found {}",
account_id_to_string(&expected_maintainer_account),
account_id_to_string(account)
);
Err(StfError::RequireMaintainerAccount)
}
}

pub fn set_block_number(block_number: u32) {
sp_io::storage::set(&storage_value_key("System", "Number"), &block_number.encode());
}
Expand Down
43 changes: 40 additions & 3 deletions app-libs/stf/src/trusted_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use crate::evm_helpers::{create_code_hash, evm_create2_address, evm_create_addre
use crate::{
guess_the_number::GuessTheNumberTrustedCall,
helpers::{
enclave_signer_account, ensure_enclave_signer_account, get_mortality, shard_vault,
shielding_target_genesis_hash, store_note, wrap_bytes,
enclave_signer_account, ensure_enclave_signer_account, ensure_maintainer_account,
get_mortality, shard_vault, shielding_target_genesis_hash, store_note, wrap_bytes,
},
Getter, STF_SHIELDING_FEE_AMOUNT_DIVIDER,
};
Expand Down Expand Up @@ -58,6 +58,7 @@ use itp_types::{
};
use itp_utils::stringify::account_id_to_string;
use log::*;
use pallet_notes::{TimestampedTrustedNote, TrustedNote};
use sp_core::{
crypto::{AccountId32, UncheckedFrom},
ed25519,
Expand All @@ -77,6 +78,8 @@ pub enum TrustedCall {
balance_unshield(AccountId, AccountId, Balance, ShardIdentifier) = 3, // (AccountIncognito, BeneficiaryPublicAccount, Amount, Shard)
balance_shield(AccountId, AccountId, Balance, ParentchainId) = 4, // (Root, AccountIncognito, Amount, origin parentchain)
balance_transfer_with_note(AccountId, AccountId, Balance, Vec<u8>) = 5,
note_bloat(AccountId, u32) = 10,
waste_time(AccountId, u32) = 11,
guess_the_number(GuessTheNumberTrustedCall) = 50,
#[cfg(feature = "evm")]
evm_withdraw(AccountId, H160, Balance) = 90, // (Origin, Address EVM Account, Value)
Expand Down Expand Up @@ -136,6 +139,8 @@ impl TrustedCall {
Self::balance_shield(sender_account, ..) => sender_account,
Self::balance_transfer_with_note(sender_account, ..) => sender_account,
Self::timestamp_set(sender_account, ..) => sender_account,
Self::note_bloat(sender_account, ..) => sender_account,
Self::waste_time(sender_account, ..) => sender_account,
#[cfg(feature = "evm")]
Self::evm_withdraw(sender_account, ..) => sender_account,
#[cfg(feature = "evm")]
Expand Down Expand Up @@ -463,7 +468,39 @@ where
};
Ok(())
},

TrustedCall::note_bloat(sender, kilobytes) => {
ensure_maintainer_account(&sender)?;
if kilobytes >= 1_100 {
return Err(StfError::Dispatch("bloat value must be below 1.1 MB".to_string()))
}
std::println!("⣿STF⣿ bloating notes by {}kB", kilobytes);
// make sure we use exactly 512 bytes per note
let dummy = TimestampedTrustedNote {
timestamp: 0u64,
version: 0u16,
note: TrustedNote::String(vec![0u8; 400]),
};
let msg = vec![111u8; 512 - (dummy.encoded_size() - 400)];
for _ in 0..kilobytes * 2 {
ita_sgx_runtime::NotesCall::<Runtime>::note_string {
link_to: vec![],
payload: msg.clone(),
}
.dispatch_bypass_filter(ita_sgx_runtime::RuntimeOrigin::signed(sender.clone()))
.map_err(|e| StfError::Dispatch(format!("Store note error: {:?}", e.error)))?;
}
Ok(())
},
TrustedCall::waste_time(sender, milliseconds) => {
ensure_maintainer_account(&sender)?;
if milliseconds > 10_000 {
return Err(StfError::Dispatch("waste time value must be below 10s".to_string()))
}
std::println!("⣿STF⣿ waste time: {}ms", milliseconds);
std::thread::sleep(std::time::Duration::from_millis(milliseconds as u64));
std::println!("⣿STF⣿ finished wasting time");
Ok(())
},
#[cfg(feature = "evm")]
TrustedCall::evm_withdraw(from, address, value) => {
debug!("evm_withdraw({}, {}, {})", account_id_to_string(&from), address, value);
Expand Down
2 changes: 2 additions & 0 deletions cli/src/trusted_base_cli/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ pub mod get_shard_vault;
pub mod get_total_issuance;

pub mod nonce;
pub mod note_bloat;
pub mod transfer;
pub mod unshield_funds;
pub mod version;
pub mod waste_time;

#[cfg(feature = "test")]
pub mod set_balance;
64 changes: 64 additions & 0 deletions cli/src/trusted_base_cli/commands/note_bloat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2021 Integritee AG and Supercomputing Systems AG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

use crate::{
get_layer_two_nonce,
trusted_cli::TrustedCli,
trusted_command_utils::{get_identifiers, get_pair_from_str},
trusted_operation::{perform_trusted_operation, send_direct_request},
Cli, CliResult, CliResultOk,
};
use ita_stf::{Getter, Index, TrustedCall, TrustedCallSigned};
use itp_stf_primitives::{
traits::TrustedCallSigning,
types::{KeyPair, TrustedOperation},
};
use log::*;
use sp_core::{crypto::Ss58Codec, Pair};
use std::boxed::Box;

#[derive(Parser)]
pub struct NoteBloatCommand {
/// subject's AccountId in ss58check format. must have maintainer privilege
account: String,

/// kilobytes of notes to store
kilobytes: u32,
}

impl NoteBloatCommand {
pub(crate) fn run(&self, cli: &Cli, trusted_args: &TrustedCli) -> CliResult {
let signer = get_pair_from_str(trusted_args, &self.account);
info!("account ss58 is {}", signer.public().to_ss58check());

println!("send trusted call note-bloat({}kB)", self.kilobytes);

let (mrenclave, shard) = get_identifiers(trusted_args);
let nonce = get_layer_two_nonce!(signer, cli, trusted_args);
let top: TrustedOperation<TrustedCallSigned, Getter> =
TrustedCall::note_bloat(signer.public().into(), self.kilobytes)
.sign(&KeyPair::Sr25519(Box::new(signer)), nonce, &mrenclave, &shard)
.into_trusted_operation(trusted_args.direct);

if trusted_args.direct {
Ok(send_direct_request(cli, trusted_args, &top).map(|_| CliResultOk::None)?)
} else {
Ok(perform_trusted_operation::<()>(cli, trusted_args, &top)
.map(|_| CliResultOk::None)?)
}
}
}
64 changes: 64 additions & 0 deletions cli/src/trusted_base_cli/commands/waste_time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2021 Integritee AG and Supercomputing Systems AG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

use crate::{
get_layer_two_nonce,
trusted_cli::TrustedCli,
trusted_command_utils::{get_identifiers, get_pair_from_str},
trusted_operation::{perform_trusted_operation, send_direct_request},
Cli, CliResult, CliResultOk,
};
use ita_stf::{Getter, Index, TrustedCall, TrustedCallSigned};
use itp_stf_primitives::{
traits::TrustedCallSigning,
types::{KeyPair, TrustedOperation},
};
use log::*;
use sp_core::{crypto::Ss58Codec, Pair};
use std::boxed::Box;

#[derive(Parser)]
pub struct WasteTimeCommand {
/// subject's AccountId in ss58check format. must have maintainer privilege
account: String,

/// milliseconds to waste
millis: u32,
}

impl WasteTimeCommand {
pub(crate) fn run(&self, cli: &Cli, trusted_args: &TrustedCli) -> CliResult {
let signer = get_pair_from_str(trusted_args, &self.account);
info!("account ss58 is {}", signer.public().to_ss58check());

println!("send trusted call waste-time({}ms)", self.millis);

let (mrenclave, shard) = get_identifiers(trusted_args);
let nonce = get_layer_two_nonce!(signer, cli, trusted_args);
let top: TrustedOperation<TrustedCallSigned, Getter> =
TrustedCall::waste_time(signer.public().into(), self.millis)
.sign(&KeyPair::Sr25519(Box::new(signer)), nonce, &mrenclave, &shard)
.into_trusted_operation(trusted_args.direct);

if trusted_args.direct {
Ok(send_direct_request(cli, trusted_args, &top).map(|_| CliResultOk::None)?)
} else {
Ok(perform_trusted_operation::<()>(cli, trusted_args, &top)
.map(|_| CliResultOk::None)?)
}
}
}
Loading

0 comments on commit 22daaf9

Please sign in to comment.