Compare commits

..

4 Commits

Author SHA1 Message Date
3380d16dc9
extend genesis config with ghost sudo
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:15:10 +03:00
384380ad55
ghost sudo added as a dependency to casper runtime
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:13:59 +03:00
4f23c39994
sudo pallet ported as local pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:12:08 +03:00
67fd48d500
hard reset flag added to starter script
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:10:07 +03:00
15 changed files with 1027 additions and 4 deletions

View File

@ -17,7 +17,7 @@ homepage.workspace = true
[workspace.package] [workspace.package]
license = "GPL-3.0-only" license = "GPL-3.0-only"
authors = ["571nky", "57r37ch", "f4750"] authors = ["571nky", "57r37ch", "f4750"]
version = "0.7.201" version = "0.7.203"
edition = "2021" edition = "2021"
homepage = "https://ghostchain.io" homepage = "https://ghostchain.io"
repository = "https://git.ghostchain.io/ghostchain/ghost-node" repository = "https://git.ghostchain.io/ghostchain/ghost-node"
@ -229,6 +229,7 @@ ghost-traits = { path = "pallets/traits", default-features = false }
ghost-networks = { path = "pallets/networks", default-features = false } ghost-networks = { path = "pallets/networks", default-features = false }
ghost-claims = { path = "pallets/claims", default-features = false } ghost-claims = { path = "pallets/claims", default-features = false }
ghost-slow-clap = { path = "pallets/slow-clap", default-features = false } ghost-slow-clap = { path = "pallets/slow-clap", default-features = false }
ghost-sudo = { path = "pallets/sudo", default-features = false }
ghost-runtime-constants = { package = "ghost-runtime-constants", path = "runtime/ghost/constants", default-features = false } ghost-runtime-constants = { package = "ghost-runtime-constants", path = "runtime/ghost/constants", default-features = false }
casper-runtime = { path = "runtime/casper", default-features = false } casper-runtime = { path = "runtime/casper", default-features = false }
casper-runtime-constants = { package = "casper-runtime-constants", path = "runtime/casper/constants", default-features = false } casper-runtime-constants = { package = "casper-runtime-constants", path = "runtime/casper/constants", default-features = false }
@ -271,6 +272,7 @@ members = [
"pallets/networks", "pallets/networks",
"pallets/claims", "pallets/claims",
"pallets/slow-clap", "pallets/slow-clap",
"pallets/sudo",
"utils/bags-list", "utils/bags-list",
"utils/chain-spec-builder", "utils/chain-spec-builder",
"utils/generate-bags", "utils/generate-bags",

45
pallets/sudo/Cargo.toml Normal file
View File

@ -0,0 +1,45 @@
[package]
name = "ghost-sudo"
version = "0.0.0"
description = "Port of the sudo pallet because of dependencies issue"
license.workspace = true
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true
[dependencies]
docify = "0.2.8"
codec = { workspace = true, features = ["derive"] }
frame-benchmarking = { workspace = true, optional = true }
scale-info = { workspace = true, features = ["derive"] }
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
]

View File

@ -0,0 +1,70 @@
use super::*;
use crate::Pallet;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
fn assert_last_event<T: Config>(generic_event: crate::Event<T>) {
let re: <T as Config>::RuntimeEvent = generic_event.into();
frame_system::Pallet::<T>::assert_last_event(re.into());
}
#[benchmarks(where <T as Config>::RuntimeCall: From<frame_system::Call<T>>)]
mod benchmarks {
use super::*;
#[benchmark]
fn set_key() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(&caller);
let new_sudoer: T::AccountId = account("sudoer", 0, 0);
let new_sudoer_lookup = T::Lookup::unlookup(new_sudoer.clone());
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), new_sudoer_lookup);
assert_last_event::<T>(Event::KeyChanged { old: Some(caller), new: new_sudoer });
}
#[benchmark]
fn sudo() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(&caller);
let call = frame_system::Call::remark { remark: vec![] }.into();
#[extrinsic_call]
_(RawOrigin::Signed(caller), Box::new(call));
assert_last_event::<T>(Event::Sudid { sudo_result: Ok(()) })
}
#[benchmark]
fn sudo_as() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(caller.clone());
let call = frame_system::Call::remark { remark: vec![] }.into();
let who: T::AccountId = account("as", 0, 0);
let who_lookup = T::Lookup::unlookup(who);
#[extrinsic_call]
_(RawOrigin::Signed(caller), who_lookup, Box::new(call));
assert_last_event::<T>(Event::SudoAsDone { sudo_result: Ok(()) })
}
#[benchmark]
fn remove_key() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(&caller);
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()));
assert_last_event::<T>(Event::KeyRemoved {});
}
impl_benchmark_test_suite!(Pallet, crate::mock::new_bench_ext(), crate::mock::Test);
}

View File

@ -0,0 +1,82 @@
use crate::{Config, Key};
use codec::{Decode, Encode};
use frame_support::{dispatch::DispatchInfo, ensure};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, SignedExtension},
transaction_validity::{
InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,
UnknownTransaction, ValidTransaction,
},
};
use sp_std::{fmt, marker::PhantomData};
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct CheckOnlySudoAccount<T: Config + Send + Sync>(PhantomData<T>);
impl<T: Config + Send + Sync> Default for CheckOnlySudoAccount<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T: Config + Send + Sync> fmt::Debug for CheckOnlySudoAccount<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CheckOnlySudoAccount")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl<T: Config + Send + Sync> CheckOnlySudoAccount<T> {
/// Creates new `SignedExtension` to check sudo key.
pub fn new() -> Self {
Self::default()
}
}
impl<T: Config + Send + Sync> SignedExtension for CheckOnlySudoAccount<T>
where
<T as Config>::RuntimeCall: Dispatchable<Info = DispatchInfo>,
{
const IDENTIFIER: &'static str = "CheckOnlySudoAccount";
type AccountId = T::AccountId;
type Call = <T as Config>::RuntimeCall;
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(())
}
fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let sudo_key: T::AccountId = Key::<T>::get().ok_or(UnknownTransaction::CannotLookup)?;
ensure!(*who == sudo_key, InvalidTransaction::BadSigner);
Ok(ValidTransaction {
priority: info.weight.ref_time() as TransactionPriority,
..Default::default()
})
}
fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
self.validate(who, call, info, len).map(|_| ())
}
}

203
pallets/sudo/src/lib.rs Normal file
View File

@ -0,0 +1,203 @@
#![cfg_attr(not(feature = "std"), no_std)]
use sp_runtime::{traits::StaticLookup, DispatchResult};
use sp_std::prelude::*;
use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable};
mod extension;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use weights::WeightInfo;
pub use extension::CheckOnlySudoAccount;
pub use pallet::*;
type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
#[frame_support::pallet]
pub mod pallet {
use super::{DispatchResult, *};
use frame_support::pallet_prelude::*;
use frame_system::{pallet_prelude::*, RawOrigin};
pub mod config_preludes {
use super::*;
use frame_support::derive_impl;
pub struct TestDefaultConfig;
#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
impl frame_system::DefaultConfig for TestDefaultConfig {}
#[frame_support::register_default_impl(TestDefaultConfig)]
impl DefaultConfig for TestDefaultConfig {
type WeightInfo = ();
#[inject_runtime_type]
type RuntimeEvent = ();
#[inject_runtime_type]
type RuntimeCall = ();
}
}
#[pallet::config(with_default)]
pub trait Config: frame_system::Config {
#[pallet::no_default_bounds]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
#[pallet::no_default_bounds]
type RuntimeCall: Parameter
+ UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ GetDispatchInfo;
type WeightInfo: WeightInfo;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(
T::WeightInfo::sudo().saturating_add(dispatch_info.weight),
dispatch_info.class
)
})]
pub fn sudo(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) });
Ok(Pays::No.into())
}
#[pallet::call_index(1)]
#[pallet::weight((*weight, call.get_dispatch_info().class))]
pub fn sudo_unchecked_weight(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
weight: Weight,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let _ = weight;
let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) });
Ok(Pays::No.into())
}
#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::set_key())]
pub fn set_key(
origin: OriginFor<T>,
new: AccountIdLookupOf<T>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let new = T::Lookup::lookup(new)?;
Self::deposit_event(Event::KeyChanged { old: Key::<T>::get(), new: new.clone() });
Key::<T>::put(new);
Ok(Pays::No.into())
}
#[pallet::call_index(3)]
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(
T::WeightInfo::sudo_as().saturating_add(dispatch_info.weight),
dispatch_info.class,
)
})]
pub fn sudo_as(
origin: OriginFor<T>,
who: AccountIdLookupOf<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let who = T::Lookup::lookup(who)?;
let res = call.dispatch_bypass_filter(RawOrigin::Signed(who).into());
Self::deposit_event(Event::SudoAsDone {
sudo_result: res.map(|_| ()).map_err(|e| e.error),
});
Ok(Pays::No.into())
}
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::remove_key())]
pub fn remove_key(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
Self::deposit_event(Event::KeyRemoved {});
Key::<T>::kill();
Ok(Pays::No.into())
}
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
Sudid {
sudo_result: DispatchResult,
},
KeyChanged {
old: Option<T::AccountId>,
new: T::AccountId,
},
KeyRemoved,
SudoAsDone { sudo_result: DispatchResult },
}
#[pallet::error]
pub enum Error<T> {
RequireSudo,
}
#[pallet::storage]
pub(super) type Key<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
pub key: Option<T::AccountId>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Key::<T>::set(self.key.clone());
}
}
impl<T: Config> Pallet<T> {
pub(crate) fn ensure_sudo(origin: OriginFor<T>) -> DispatchResult {
let sender = ensure_signed_or_root(origin)?;
if let Some(sender) = sender {
if Key::<T>::get().map_or(false, |k| k == sender) {
Ok(())
} else {
Err(Error::<T>::RequireSudo.into())
}
} else {
Ok(())
}
}
}
}

109
pallets/sudo/src/mock.rs Normal file
View File

@ -0,0 +1,109 @@
use super::*;
use crate as sudo;
use frame_support::derive_impl;
use sp_io;
use sp_runtime::BuildStorage;
#[frame_support::pallet]
pub mod logger {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(*weight)]
pub fn privileged_i32_log(
origin: OriginFor<T>,
i: i32,
weight: Weight,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
<I32Log<T>>::try_append(i).map_err(|_| "could not append")?;
Self::deposit_event(Event::AppendI32 { value: i, weight });
Ok(().into())
}
#[pallet::call_index(1)]
#[pallet::weight(*weight)]
pub fn non_privileged_log(
origin: OriginFor<T>,
i: i32,
weight: Weight,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
<I32Log<T>>::try_append(i).map_err(|_| "could not append")?;
<AccountLog<T>>::try_append(sender.clone()).map_err(|_| "could not append")?;
Self::deposit_event(Event::AppendI32AndAccount { sender, value: i, weight });
Ok(().into())
}
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
AppendI32 { value: i32, weight: Weight },
AppendI32AndAccount { sender: T::AccountId, value: i32, weight: Weight },
}
#[pallet::storage]
#[pallet::getter(fn account_log)]
pub(super) type AccountLog<T: Config> =
StorageValue<_, BoundedVec<T::AccountId, ConstU32<1_000>>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn i32_log)]
pub(super) type I32Log<T> = StorageValue<_, BoundedVec<i32, ConstU32<1_000>>, ValueQuery>;
}
type Block = frame_system::mocking::MockBlock<Test>;
frame_support::construct_runtime!(
pub enum Test
{
System: frame_system,
Sudo: sudo,
Logger: logger,
}
);
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type Block = Block;
}
impl logger::Config for Test {
type RuntimeEvent = RuntimeEvent;
}
impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type WeightInfo = ();
}
pub type SudoCall = sudo::Call<Test>;
pub type LoggerCall = logger::Call<Test>;
pub fn new_test_ext(root_key: u64) -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
sudo::GenesisConfig::<Test> { key: Some(root_key) }
.assimilate_storage(&mut t)
.unwrap();
let mut ext: sp_io::TestExternalities = t.into();
ext.execute_with(|| System::set_block_number(1));
ext
}
#[cfg(feature = "runtime-benchmarks")]
pub fn new_bench_ext() -> sp_io::TestExternalities {
frame_system::GenesisConfig::<Test>::default().build_storage().unwrap().into()
}

188
pallets/sudo/src/tests.rs Normal file
View File

@ -0,0 +1,188 @@
use super::*;
use frame_support::{assert_noop, assert_ok, weights::Weight};
use mock::{
new_test_ext, Logger, LoggerCall, RuntimeCall, RuntimeEvent as TestEvent, RuntimeOrigin, Sudo,
SudoCall, System, Test,
};
#[test]
fn test_setup_works() {
new_test_ext(1).execute_with(|| {
assert_eq!(Key::<Test>::get(), Some(1u64));
assert!(Logger::i32_log().is_empty());
assert!(Logger::account_log().is_empty());
});
}
#[docify::export]
#[test]
fn sudo_basics() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call));
assert_eq!(Logger::i32_log(), vec![42i32]);
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_noop!(Sudo::sudo(RuntimeOrigin::signed(2), call), Error::<Test>::RequireSudo);
});
}
#[test]
fn sudo_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call));
System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) }));
})
}
#[test]
fn sudo_unchecked_weight_basics() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_ok!(Sudo::sudo_unchecked_weight(
RuntimeOrigin::signed(1),
call,
Weight::from_parts(1_000, 0)
));
assert_eq!(Logger::i32_log(), vec![42i32]);
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_noop!(
Sudo::sudo_unchecked_weight(
RuntimeOrigin::signed(2),
call,
Weight::from_parts(1_000, 0)
),
Error::<Test>::RequireSudo,
);
assert_eq!(Logger::i32_log(), vec![42i32]);
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
let sudo_unchecked_weight_call =
SudoCall::sudo_unchecked_weight { call, weight: Weight::from_parts(1_000, 0) };
let info = sudo_unchecked_weight_call.get_dispatch_info();
assert_eq!(info.weight, Weight::from_parts(1_000, 0));
});
}
#[test]
fn sudo_unchecked_weight_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo_unchecked_weight(
RuntimeOrigin::signed(1),
call,
Weight::from_parts(1_000, 0)
));
System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) }));
})
}
#[docify::export]
#[test]
fn set_key_basics() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2));
assert_eq!(Key::<Test>::get(), Some(2u64));
});
new_test_ext(1).execute_with(|| {
assert_noop!(Sudo::set_key(RuntimeOrigin::signed(2), 3), Error::<Test>::RequireSudo);
});
}
#[test]
fn set_key_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2));
System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old: Some(1), new: 2 }));
assert_ok!(Sudo::set_key(RuntimeOrigin::signed(2), 4));
System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old: Some(2), new: 4 }));
});
}
#[test]
fn remove_key_works() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::remove_key(RuntimeOrigin::signed(1)));
assert!(Key::<Test>::get().is_none());
System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {}));
assert_noop!(Sudo::remove_key(RuntimeOrigin::signed(1)), Error::<Test>::RequireSudo);
assert_noop!(Sudo::set_key(RuntimeOrigin::signed(1), 1), Error::<Test>::RequireSudo);
});
}
#[test]
fn using_root_origin_works() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::remove_key(RuntimeOrigin::root()));
assert!(Key::<Test>::get().is_none());
System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {}));
assert_ok!(Sudo::set_key(RuntimeOrigin::root(), 1));
assert_eq!(Some(1), Key::<Test>::get());
});
}
#[test]
fn sudo_as_basics() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
assert!(Logger::i32_log().is_empty());
assert!(Logger::account_log().is_empty());
let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_noop!(Sudo::sudo_as(RuntimeOrigin::signed(3), 2, call), Error::<Test>::RequireSudo);
let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
assert_eq!(Logger::i32_log(), vec![42i32]);
assert_eq!(Logger::account_log(), vec![2]);
});
}
#[docify::export]
#[test]
fn sudo_as_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) }));
});
}

151
pallets/sudo/src/weights.rs Normal file
View File

@ -0,0 +1,151 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// 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.
//! Autogenerated weights for `pallet_sudo`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
// Executed Command:
// ./target/production/substrate-node
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet_sudo
// --no-storage-info
// --no-median-slopes
// --no-min-squares
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --output=./substrate/frame/sudo/src/weights.rs
// --header=./substrate/HEADER-APACHE2
// --template=./substrate/.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weight functions needed for `pallet_sudo`.
pub trait WeightInfo {
fn set_key() -> Weight;
fn sudo() -> Weight;
fn sudo_as() -> Weight;
fn remove_key() -> Weight;
}
/// Weights for `pallet_sudo` using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: `Sudo::Key` (r:1 w:1)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 9_486_000 picoseconds.
Weight::from_parts(9_663_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:0)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 10_501_000 picoseconds.
Weight::from_parts(10_729_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:0)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 10_742_000 picoseconds.
Weight::from_parts(11_003_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:1)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 8_837_000 picoseconds.
Weight::from_parts(9_127_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: `Sudo::Key` (r:1 w:1)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 9_486_000 picoseconds.
Weight::from_parts(9_663_000, 1517)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:0)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 10_501_000 picoseconds.
Weight::from_parts(10_729_000, 1517)
.saturating_add(RocksDbWeight::get().reads(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:0)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 10_742_000 picoseconds.
Weight::from_parts(11_003_000, 1517)
.saturating_add(RocksDbWeight::get().reads(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:1)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 8_837_000 picoseconds.
Weight::from_parts(9_127_000, 1517)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}

View File

@ -1,6 +1,6 @@
[package] [package]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.25" version = "3.5.26"
build = "build.rs" build = "build.rs"
description = "Runtime of the Casper Network" description = "Runtime of the Casper Network"
edition.workspace = true edition.workspace = true
@ -87,6 +87,7 @@ pallet-whitelist = { workspace = true }
ghost-networks = { workspace = true } ghost-networks = { workspace = true }
ghost-claims = { workspace = true } ghost-claims = { workspace = true }
ghost-slow-clap = { workspace = true } ghost-slow-clap = { workspace = true }
ghost-sudo = { workspace = true }
casper-runtime-constants = { workspace = true } casper-runtime-constants = { workspace = true }
runtime-common = { workspace = true } runtime-common = { workspace = true }
primitives = { workspace = true } primitives = { workspace = true }
@ -205,6 +206,7 @@ std = [
"ghost-networks/std", "ghost-networks/std",
"ghost-claims/std", "ghost-claims/std",
"ghost-slow-clap/std", "ghost-slow-clap/std",
"ghost-sudo/std",
"casper-runtime-constants/std", "casper-runtime-constants/std",
"runtime-common/std", "runtime-common/std",
"primitives/std", "primitives/std",
@ -252,6 +254,7 @@ runtime-benchmarks = [
"ghost-networks/runtime-benchmarks", "ghost-networks/runtime-benchmarks",
"ghost-claims/runtime-benchmarks", "ghost-claims/runtime-benchmarks",
"ghost-slow-clap/runtime-benchmarks", "ghost-slow-clap/runtime-benchmarks",
"ghost-sudo/runtime-benchmarks",
"runtime-common/runtime-benchmarks", "runtime-common/runtime-benchmarks",
] ]
try-runtime = [ try-runtime = [
@ -297,5 +300,6 @@ try-runtime = [
"ghost-networks/try-runtime", "ghost-networks/try-runtime",
"ghost-claims/try-runtime", "ghost-claims/try-runtime",
"ghost-slow-clap/try-runtime", "ghost-slow-clap/try-runtime",
"ghost-sudo/try-runtime",
"runtime-common/try-runtime", "runtime-common/try-runtime",
] ]

View File

@ -28,3 +28,6 @@ std = [
"sp-runtime/std", "sp-runtime/std",
"sp-weights/std", "sp-weights/std",
] ]
# Set timing constants (e.g session period) to faster versions to speed up testing.
fast-runtime = []

View File

@ -1105,6 +1105,12 @@ impl ghost_slow_clap::Config for Runtime {
type WeightInfo = weights::ghost_slow_clap::WeightInfo<Runtime>; type WeightInfo = weights::ghost_slow_clap::WeightInfo<Runtime>;
} }
impl ghost_sudo::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type WeightInfo = weights::ghost_sudo::WeightInfo<Runtime>;
}
construct_runtime! { construct_runtime! {
pub enum Runtime pub enum Runtime
{ {
@ -1132,6 +1138,7 @@ construct_runtime! {
Session: pallet_session = 9, Session: pallet_session = 9,
Grandpa: pallet_grandpa = 11, Grandpa: pallet_grandpa = 11,
AuthorityDiscovery: pallet_authority_discovery = 12, AuthorityDiscovery: pallet_authority_discovery = 12,
GhostSudo: ghost_sudo = 13,
// Governance stuff. // Governance stuff.
Treasury: pallet_treasury = 19, Treasury: pallet_treasury = 19,
@ -1260,6 +1267,7 @@ mod benches {
[ghost_networks, GhostNetworks] [ghost_networks, GhostNetworks]
[ghost_claims, GhostClaims] [ghost_claims, GhostClaims]
[ghost_slow_clap, GhostSlowClaps] [ghost_slow_clap, GhostSlowClaps]
[ghost_sudo, GhostSudo]
); );
} }
@ -1566,6 +1574,7 @@ sp_api::impl_runtime_apis! {
(list, storage_info) (list, storage_info)
} }
#[allow(non_local_definitions)]
fn dispatch_benchmark( fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig, config: frame_benchmarking::BenchmarkConfig,
) -> Result< ) -> Result<

View File

@ -0,0 +1,97 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// 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.
//! Autogenerated weights for `pallet_sudo`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
// Executed Command:
// ./target/production/substrate-node
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet_sudo
// --no-storage-info
// --no-median-slopes
// --no-min-squares
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --output=./substrate/frame/sudo/src/weights.rs
// --header=./substrate/HEADER-APACHE2
// --template=./substrate/.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weights for `pallet_sudo` using the Substrate node and recommended hardware.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> ghost_sudo::WeightInfo for WeightInfo<T> {
/// Storage: `Sudo::Key` (r:1 w:1)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 9_486_000 picoseconds.
Weight::from_parts(9_663_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:0)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 10_501_000 picoseconds.
Weight::from_parts(10_729_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:0)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 10_742_000 picoseconds.
Weight::from_parts(11_003_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
}
/// Storage: `Sudo::Key` (r:1 w:1)
/// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 8_837_000 picoseconds.
Weight::from_parts(9_127_000, 1517)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}

View File

@ -3,6 +3,7 @@ pub mod frame_system;
pub mod ghost_claims; pub mod ghost_claims;
pub mod ghost_networks; pub mod ghost_networks;
pub mod ghost_slow_clap; pub mod ghost_slow_clap;
pub mod ghost_sudo;
pub mod pallet_alliance; pub mod pallet_alliance;
pub mod pallet_bags_list; pub mod pallet_bags_list;
pub mod pallet_balances; pub mod pallet_balances;

View File

@ -2,6 +2,7 @@
set -Ee set -Ee
HARD_RESET=false
CHECK_KEYS=false CHECK_KEYS=false
INSERT_KEYS=false INSERT_KEYS=false
UNIT_FILE=false UNIT_FILE=false
@ -96,6 +97,7 @@ help() {
echo -e "-s, --base-path\n\tPath to the folder with chain database ('/var/lib/ghost' is default)." echo -e "-s, --base-path\n\tPath to the folder with chain database ('/var/lib/ghost' is default)."
echo -e "-c, --specification-path\n\tPath to specification ('/etc/ghost' is default)." echo -e "-c, --specification-path\n\tPath to specification ('/etc/ghost' is default)."
echo -e "-n, --specification-name\n\tSpecification name to be used ('casper' is default)." echo -e "-n, --specification-name\n\tSpecification name to be used ('casper' is default)."
echo -e "--hard-reset-i-know-what-im-doing\n\tWill completely remove ledger along with associated session keys."
echo -e "-h, --help\n\tPrints help information." echo -e "-h, --help\n\tPrints help information."
} }
@ -163,6 +165,9 @@ while [ $# -gt 0 ]; do
if [[ "$1" != *=* ]]; then shift; fi if [[ "$1" != *=* ]]; then shift; fi
SPECIFICATION_NAME="${1#*=}" SPECIFICATION_NAME="${1#*=}"
;; ;;
--hard-reset-i-know-what-im-doing)
HARD_RESET=true
;;
--help|-h) --help|-h)
help help
exit 0 exit 0
@ -175,6 +180,51 @@ while [ $# -gt 0 ]; do
shift shift
done done
if [[ $HARD_RESET = true ]]; then
echo -e "\n"
echo "WARNING!!! THIS ACTION WILL COMPLETELY PURGE THE LEDGER AND REBUILD THE NODE USING THE LATEST"
echo "REPOSITORY VERSION. NOTE THAT THE VALIDATION PROCESS WILL BE LOST BECAUSE SESSION OF KEYS."
echo "THERE ARE TWO SCENARIOS IN WHICH YOU MIGHT NEED TO PROCEED:"
echo -e "\t- A new version of the network hsa been released, and a restart is neccessary"
echo -e "\t- There is a critical issue, and you require a hard reset of the node in a single command"
echo -e "\n"
if prompt "[?] do you understand all risks?"; then
echo "[+] you were warned, I hope you know what you're doing"
else
echo "[-] aborting hard reset"
exit 1
fi
cd $PROJECT_FOLDER
# TODO: uncomment later
# echo "[+] fetching the latest ghost-node source code"
# git switch main
# git pull origin main
cd $PROJECT_FOLDER
echo "[+] starting build in 3 seconds..."
sleep 3
cargo build $RELEASE $FEATURES
echo "[+] trying to stop current ghost-node"
sudo systemctl stop ghost-node
echo "[+] trying to remove locally stored ledger"
sudo rm -rf "$BASE_PATH/chains/*"
cd $PROJECT_FOLDER
echo "[+] trying to copy executable to '$EXECUTABLE_PATH'"
sudo cp target/$TARGET/ghost $EXECUTABLE_PATH
cp service/chain-specs/$SPECIFICATION_NAME.json $SPECIFICATION_PATH
echo "[+] ghost executable copied in '$EXECUTABLE_PATH' from '$TARGET'"
echo "[+] specification '$SPECIFICATION_NAME.json' copied to '$SPECIFICATION_PATH'"
echo "[+] starting ghost-node"
sudo systemctl start ghost-node
exit 0
fi
if [[ $SET_ENVIRONMENT = true ]]; then if [[ $SET_ENVIRONMENT = true ]]; then
echo -e "\n" echo -e "\n"
echo "WARNING!!! THIS IS HIGHLY EXPERIMENTAL FLAG, USE IT ONLY ON YOUR" echo "WARNING!!! THIS IS HIGHLY EXPERIMENTAL FLAG, USE IT ONLY ON YOUR"
@ -262,7 +312,7 @@ fi
if [[ ! -z $RELEASE ]]; then if [[ ! -z $RELEASE ]]; then
if prompt "[?] 'cargo build $RELEASE $FEATURES' is what you want?"; then if prompt "[?] 'cargo build $RELEASE $FEATURES' is what you want?"; then
cd $PROJECT_FOLDER cd $PROJECT_FOLDER
echo "[+] Starting build in 3 seconds..." echo "[+] starting build in 3 seconds..."
sleep 3 sleep 3
cargo build $RELEASE $FEATURES cargo build $RELEASE $FEATURES
fi fi
@ -347,7 +397,6 @@ if [[ $ARGUMENTS = true ]]; then
CLI_ARGS+=("--public-addr=$public_addr") CLI_ARGS+=("--public-addr=$public_addr")
fi fi
# default for now # default for now
CLI_ARGS+=("--telemetry-url='wss://telemetry.ghostchain.io/submit/ 9'") CLI_ARGS+=("--telemetry-url='wss://telemetry.ghostchain.io/submit/ 9'")
CLI_ARGS+=("--base-path=$BASE_PATH") CLI_ARGS+=("--base-path=$BASE_PATH")

View File

@ -272,6 +272,11 @@ pub fn testnet_config_genesis(
"babe": { "babe": {
"epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG), "epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG),
}, },
"ghostSudo": {
"key": endowed_accounts
.first()
.cloned(),
},
"ghostNetworks": { "ghostNetworks": {
"networks": evm_networks, "networks": evm_networks,
}, },
@ -709,6 +714,11 @@ fn casper_staging_config_genesis() -> serde_json::Value {
"babe": { "babe": {
"epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG), "epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG),
}, },
"ghostSudo": {
"key": endowed_accounts
.first()
.cloned(),
},
"ghostNetworks": { "ghostNetworks": {
"networks": evm_networks, "networks": evm_networks,
}, },