Compare commits

..

15 Commits

Author SHA1 Message Date
613b09ac6a
fix weights calculations
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 03:13:11 +03:00
98de9373dd
make runtime more legit for real use case; make genesis file cleaner
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 03:11:15 +03:00
882ec7ec0d
remove unnecessary files and sligtly tweak the ratios
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 03:09:09 +03:00
afea8046f9
put benchmarking under the feature flag at once
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 03:06:41 +03:00
80f58e6b11
finally make feature to represent runtime
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 03:04:38 +03:00
20c8b9f1b2
fix the benchmarking script
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 03:03:39 +03:00
e694489f75
slightly optimize bridge in/out logic; make variable names more self descriptive; fix benchmarking for governance
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-02 02:59:26 +03:00
e104a49e53
fix runtime for the benchmarking
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 15:06:47 +03:00
99ac2f1f08
make fee calculations correct based on nanoseconds
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 15:05:56 +03:00
ffa65dc0a7
bump runtime-common version
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 15:04:27 +03:00
bfcd7af559
we need to use 1/3 if the block time because each validator will re-execute all extrinsics
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 15:03:33 +03:00
85f1dc9646
remove unnecessary code blocks
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 15:02:05 +03:00
e7a191d5e7
remove annoying warning
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 14:59:56 +03:00
c173734ea8
align governance preclaims with python script
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 14:58:52 +03:00
7b050f1363
fix tests for exodus pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-08-31 14:57:06 +03:00
40 changed files with 721 additions and 1144 deletions

View File

@ -17,7 +17,7 @@ homepage.workspace = true
[workspace.package]
license = "GPL-3.0-only"
authors = ["571nky", "57r37ch", "f4750"]
version = "0.9.0"
version = "0.9.1"
edition = "2021"
homepage = "https://ghostchain.io"
repository = "https://git.ghostchain.io/ghostchain/ghost-node"

View File

@ -55,6 +55,7 @@ pub enum Subcommand {
/// Revert the chain to a previous state.
Revert(sc_cli::RevertCmd),
#[cfg(feature = "runtime-benchmarks")]
/// The custom benchmark subcommmand benchmarking runtime pallets.
#[clap(subcommand)]
Benchmark(frame_benchmarking_cli::BenchmarkCmd),

View File

@ -279,22 +279,13 @@ pub fn run() -> Result<()> {
task_manager,
))
})?)
}
},
#[cfg(feature = "runtime-benchmarks")]
Some(Subcommand::Benchmark(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
match cmd {
#[cfg(not(feature = "runtime-benchmarks"))]
BenchmarkCmd::Storage(_) => {
return Err(sc_cli::Error::Input(
"Compile with `--feature=runtime-benchmarks \
to enable storage benchmarks."
.into(),
)
.into())
}
#[cfg(feature = "runtime-benchmarks")]
BenchmarkCmd::Storage(cmd) => runner.sync_run(|mut config| {
let (client, backend, _, _) = service::new_chain_ops(&mut config)?;
let db = backend.expose_db();
@ -350,21 +341,11 @@ pub fn run() -> Result<()> {
BenchmarkCmd::Pallet(cmd) => {
set_ss58_version(chain_spec);
if cfg!(feature = "runtime-benchmarks") {
runner.sync_run(|config| {
cmd.run_with_spec::<sp_runtime::traits::HashingFor<service::Block>, ()>(
Some(config.chain_spec),
)
.map_err(|e| Error::SubstrateCli(e))
})
} else {
Err(sc_cli::Error::Input(
"Benchmarking wasn't enabled when building the node. \
You can enable it with `--features=runtime-benchmarks`."
.into(),
)
.into())
}
runner.sync_run(|config| {
cmd.run_with_spec::<sp_runtime::traits::HashingFor<service::Block>, ()>(
Some(config.chain_spec),
).map_err(|e| Error::SubstrateCli(e))
})
}
BenchmarkCmd::Machine(cmd) => runner.sync_run(|config| {
cmd.run(
@ -379,6 +360,13 @@ pub fn run() -> Result<()> {
_ => Err(Error::CommandNotImplemented),
}
}
#[cfg(not(feature = "runtime-benchmarks"))]
Some(Subcommand::Benchmark(_)) => {
return Err(sc_cli::Error::Input(
"Benchmarking wasn't enabled when building the node. \
You can enable it with `--features=runtime-benchmarks`.".into(),
).into())
},
Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
Some(Subcommand::ChainInfo(cmd)) => {
let runner = cli.create_runner(cmd)?;

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-exodus"
version = "0.0.0"
version = "0.0.2"
description = "Threshold signature generation with DKG included"
license.workspace = true
authors.workspace = true

View File

@ -59,7 +59,7 @@ use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
#[cfg(any(test, feature = "runtime-benchmarks"))]
#[cfg(any(test))]
mod mock;
#[cfg(test)]
@ -497,7 +497,7 @@ pub mod pallet {
who: T::AccountId,
network_id: NetworkIdOf<T>,
amount: BalanceOf<T>,
commission: Perbill,
bounty: Perbill,
receiver: EvmAddress,
}
}
@ -1843,7 +1843,7 @@ pub mod pallet {
origin: OriginFor<T>,
network_id: NetworkIdOf<T>,
amount: BalanceOf<T>,
commission: Perbill,
bounty: Perbill,
receiver: EvmAddress,
) -> DispatchResult {
let who = ensure_signed(origin)?;
@ -1858,7 +1858,7 @@ pub mod pallet {
Self::do_register_evm_bridge_out_exodus(
network_id,
amount,
commission,
bounty,
receiver,
)?;
@ -1866,7 +1866,7 @@ pub mod pallet {
who,
network_id,
amount,
commission,
bounty,
receiver,
});
@ -2138,7 +2138,7 @@ impl<T: Config> Pallet<T> {
fn do_register_evm_bridge_out_exodus(
network_id: NetworkIdOf<T>,
amount: BalanceOf<T>,
commission: Perbill,
bounty: Perbill,
receiver: EvmAddress,
) -> DispatchResult {
let network = T::NetworkDataHandler::get(&network_id)
@ -2156,7 +2156,7 @@ impl<T: Config> Pallet<T> {
exodus_session,
network_id,
amount,
commission,
bounty,
receiver
);
@ -3921,7 +3921,6 @@ impl<T: Config> Pallet<T> {
network_curve,
);
// TODO: log here
let round1_secret_package = round1_metadata.try_update_max_signers(
|round1_secret_package| -> ExodusResult<Vec<u8>> {
network_curve.dkg_narrow_round_max_signers(

View File

@ -1,5 +1,6 @@
use crate::*;
use crate::mock::*;
use strum::IntoEnumIterator;
use sp_std::{
prelude::Vec,
@ -585,7 +586,7 @@ fn run_succesfull_dkg_session_partially(
) -> (u64, u64) {
let authorities: Vec<UintAuthorityId> = raw_authorities.iter().map(|&id| id.into()).collect();
let prev_dkg_index = ext.execute_with(|| QualificationDkgState::<Runtime>::get(curve).get_dkg_index());
ext.execute_with(|| Exodus::start_dkg_qualification(authorities));
ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter()));
let dkg_index = ext.execute_with(|| QualificationDkgState::<Runtime>::get(curve).get_dkg_index());
let (start_block, round_delay) = ext.execute_with(|| {
@ -1102,7 +1103,7 @@ fn test_exodus_dkg_robustness() {
];
let mut dkg_index = ext.execute_with(|| {
Exodus::start_dkg_qualification(authorities);
Exodus::start_dkg_qualification(authorities, NetworkCurve::iter());
QualificationDkgState::<Runtime>::get(curve).get_dkg_index()
});
@ -1223,7 +1224,7 @@ fn test_prepare_round4_abort_on_byzantine_attack() {
let authorities: Vec<UintAuthorityId> = raw_authorities.iter().map(|&id| id.into()).collect();
let authorities_len = authorities.len();
ext.execute_with(|| Exodus::start_dkg_qualification(authorities));
ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter()));
let dkg_rounds = [
execute_round0_happy_path,
@ -1267,7 +1268,7 @@ fn test_prepare_round5_abort_on_byzantine_attack() {
let authorities: Vec<UintAuthorityId> = raw_authorities.iter().map(|&id| id.into()).collect();
let authorities_len = authorities.len();
ext.execute_with(|| Exodus::start_dkg_qualification(authorities));
ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter()));
let dkg_rounds = [
execute_round0_happy_path,
@ -1315,7 +1316,7 @@ fn test_prepare_round5_kick_on_empty_justifications() {
let authorities: Vec<UintAuthorityId> = raw_authorities.iter().map(|&id| id.into()).collect();
let authorities_len = authorities.len();
ext.execute_with(|| Exodus::start_dkg_qualification(authorities));
ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter()));
let dkg_rounds = [
execute_round0_happy_path,

View File

@ -120,7 +120,7 @@ pub enum ExodusRequestType<NetworkId, Balance> {
exodus_session: ExodusSession,
network_id: NetworkId,
amount: Balance,
commission: Perbill,
bounty: Perbill,
receiver: EvmAddress,
},
EvmGovernance { network_id: NetworkId },
@ -144,22 +144,22 @@ where
[exodus_session, public_key, parity]
)
},
ExodusRequestType::EvmBridgeOut { exodus_session, network_id, amount, commission, receiver } => {
ExodusRequestType::EvmBridgeOut { exodus_session, network_id, amount, bounty, receiver } => {
let mut buffer = [0u8; 32];
buffer[0..20].copy_from_slice(receiver.as_ref());
let chain_id_u64: u64 = (*network_id).unique_saturated_into();
buffer[20..28].copy_from_slice(&chain_id_u64.to_be_bytes());
let scaled_commission = multiply_by_rational_with_rounding(
commission.deconstruct() as u128,
let scaled_bounty = multiply_by_rational_with_rounding(
bounty.deconstruct() as u128,
1u128 << 32,
1_000_000_000,
sp_runtime::Rounding::Down
)?;
let commission_uint32 = scaled_commission as u32;
buffer[28..32].copy_from_slice(&commission_uint32.to_be_bytes());
let bounty_uint32 = scaled_bounty as u32;
buffer[28..32].copy_from_slice(&bounty_uint32.to_be_bytes());
let mut amount_buffer = [0u8; 32];
let amount_u128: u128 = (*amount).unique_saturated_into();
@ -208,14 +208,14 @@ where
exodus_session: ExodusSession,
network_id: NetworkId,
amount: Balance,
commission: Perbill,
bounty: Perbill,
receiver: EvmAddress,
) -> Self {
let evm_bridge_out = ExodusRequestType::EvmBridgeOut {
exodus_session,
network_id,
amount,
commission,
bounty,
receiver,
};
Self::default_request_for(evm_bridge_out)

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-governance"
version = "0.3.0"
version = "0.3.2"
description = "Full-chain and cross-chain governance pallet with early adopter share claims"
license.workspace = true
authors.workspace = true
@ -33,9 +33,7 @@ ghost-networks = { workspace = true }
[dev-dependencies]
libsecp256k1 = { workspace = true, default-features = true }
hex = { workspace = true }
# hex-literal = { workspace = true, default-features = true }
# serde_json = { workspace = true, default-features = true }
hex-literal = { workspace = true, default-features = true }
[features]
default = ["std"]
@ -43,7 +41,6 @@ std = [
"frame-benchmarking?/std",
"serde/std",
"codec/std",
"hex/std",
"scale-info/std",
"libsecp256k1/std",
"frame-support/std",

View File

@ -2,25 +2,25 @@
use super::*;
use frame_benchmarking::v2::*;
use frame_support::dispatch::RawOrigin;
use ghost_helpers::merkle_tree::{generate_tree, generate_proof};
#[benchmarks(where T: Config)]
mod benchmarks {
use super::*;
#[benchmark]
fn claim() {
fn claim(
p: Linear<1, { T::MaxProofDepth::get() }>
) -> Result<(), BenchmarkError> {
let network_id = Default::default();
let current_account: T::AccountId = frame_benchmarking::whitelisted_caller();
let max_proof_depth = p;
let max_proof_depth = <<T as Config>::MaxProofDepth as Get<u32>>::get();
let minimum_donation_u128 = <<T as Config>::MinimumDonation as Get<u128>>::get();
let minimum_donation: BalanceOf<T> = minimum_donation_u128.unique_saturated_into();
let dummy_balance_u128 = 420u128;
let dummy_balance: BalanceOf<T> = dummy_balance_u128.unique_saturated_into();
let dummy_shares_u128 = 420u128;
let dummy_shares: BalanceOf<T> = dummy_shares_u128.unique_saturated_into();
let secret_key = libsecp256k1::SecretKey::parse(&[69u8; 32]).unwrap();
let public_key = libsecp256k1::PublicKey::from_secret_key(&secret_key);
@ -31,28 +31,45 @@ mod benchmarks {
evm_addr_bytes.copy_from_slice(&pubkey_hash.as_ref()[12..32]);
let dummy_evm_address = EvmAddress::from(evm_addr_bytes);
let total_entries = 1u64 << max_proof_depth;
let max_index = total_entries - 1;
let raw_values = (0..total_entries)
.map(|i| i as TokenId)
.collect::<Vec<TokenId>>();
let target_index = 0u32;
let claim_package_init = ClaimPackage {
shares: dummy_shares,
merkle_proof: Default::default(),
token_id: 0,
index: target_index,
};
let merkle_tree = generate_tree::<SubstrateKeccakHasher, _, _, _, _>(
max_index,
raw_values,
|index: TokenId| -> Result<(usize, Vec<u8>), ()> {
let claim_package = ClaimPackage {
balance: dummy_balance,
merkle_proof: Default::default(),
token_id: index,
};
let preimage_init = claim_package_init.get_preimage(&dummy_evm_address, network_id);
let mut current_hash = SubstrateKeccakHasher::hash(&preimage_init);
let claim_preimage = claim_package.get_preimage(&dummy_evm_address);
Ok((index as usize, claim_preimage.to_vec()))
let mut proof_hashes = Vec::with_capacity(max_proof_depth as usize);
let mut current_index = target_index as usize;
let hash_len = SubstrateKeccakHasher::hash_len();
let mut combined = sp_std::vec![0u8; hash_len * 2];
for i in 0..max_proof_depth {
let mut sibling_bytes = [0u8; 32];
sibling_bytes[24..32].copy_from_slice(&(i as u64).to_be_bytes());
let sibling_hash = EvmHash::from_slice(&sibling_bytes);
proof_hashes.push(sibling_hash);
let sibling_bytes_ref = sibling_hash.as_ref();
let hash_bytes = current_hash.as_ref();
if current_index % 2 == 0 {
combined[..hash_len].copy_from_slice(hash_bytes);
combined[hash_len..].copy_from_slice(sibling_bytes_ref);
} else {
combined[..hash_len].copy_from_slice(sibling_bytes_ref);
combined[hash_len..].copy_from_slice(hash_bytes);
}
).unwrap();
let merkle_root = *merkle_tree.last().unwrap();
current_hash = SubstrateKeccakHasher::hash(&combined);
current_index >>= 1;
}
let merkle_root = current_hash;
let member_share = MemberShare {
initiated_network: None,
@ -62,28 +79,23 @@ mod benchmarks {
MemberShares::<T>::insert(&current_account, member_share);
let network_state = NetworkShare::new(
dummy_balance,
dummy_shares,
merkle_root,
max_proof_depth,
);
NetworkShares::<T>::insert(&network_id, network_state);
let global_state = ShareState::new(dummy_balance);
let global_state = ShareState::new(dummy_shares);
GlobalShares::<T>::put(global_state);
let merkle_proof = generate_proof::<SubstrateKeccakHasher, _>(
&merkle_tree,
total_entries - 1,
0,
);
let claim_package = ClaimPackage {
merkle_proof: BoundedVec::try_from(merkle_proof).unwrap(),
balance: dummy_balance,
index: 0,
merkle_proof: BoundedVec::try_from(proof_hashes).unwrap(),
shares: dummy_shares,
token_id: 0
};
let preimage = claim_package.get_preimage(&dummy_evm_address);
let preimage = claim_package.get_preimage(&dummy_evm_address, network_id);
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
let message_string_bytes = Pallet::<T>::ethereum_signable_message(
@ -116,15 +128,17 @@ mod benchmarks {
evm_signature,
);
assert_eq!(dummy_balance, GlobalShares::<T>::get().claimed_shares);
assert_eq!(dummy_shares, GlobalShares::<T>::get().claimed_shares);
assert_eq!(
dummy_balance,
dummy_shares,
MemberShares::<T>::get(&current_account).activated_shares
);
assert_eq!(
dummy_balance,
dummy_shares,
NetworkShares::<T>::get(&network_id).claimed_shares(),
);
Ok(())
}
impl_benchmark_test_suite!(

View File

@ -143,8 +143,9 @@ pub struct ClaimPackage<Balance>
where
Balance: Default + Copy + Clone,
{
pub index: u32,
pub token_id: TokenId,
pub balance: Balance,
pub shares: Balance,
pub merkle_proof: BoundedVec<EvmHash, ConstU32<MAX_POSSIBLE_PROOF_DEPTH>>,
}
@ -152,21 +153,33 @@ impl<Balance> ClaimPackage<Balance>
where
Balance: Default + Copy + Clone + UniqueSaturatedInto<u128>,
{
pub fn get_preimage(&self, evm_address: &EvmAddress) -> [u8; 96] {
pub fn get_preimage<NetworkId>(
&self,
evm_address: &EvmAddress,
network_id: NetworkId
) -> [u8; 128]
where
NetworkId: Default + Copy + Clone + UniqueSaturatedInto<u128>,
{
let mut token_id_bytes = [0u8; 32];
U256::from(self.token_id as u128).to_big_endian(&mut token_id_bytes);
let balance_u128: u128 = self.balance.unique_saturated_into();
let mut balance_bytes = [0u8; 32];
U256::from(balance_u128).to_big_endian(&mut balance_bytes);
let mut shares_bytes = [0u8; 32];
let shares_u128: u128 = self.shares.unique_saturated_into();
U256::from(shares_u128).to_big_endian(&mut shares_bytes);
let mut address_bytes = [0u8; 32];
address_bytes[12..32].copy_from_slice(evm_address.as_bytes());
let mut preimage = [0u8; 96];
let mut network_id_bytes = [0u8; 32];
let network_id_u128: u128 = network_id.unique_saturated_into();
U256::from(network_id_u128).to_big_endian(&mut network_id_bytes);
let mut preimage = [0u8; 128];
preimage[0..32].copy_from_slice(&token_id_bytes);
preimage[32..64].copy_from_slice(&balance_bytes);
preimage[32..64].copy_from_slice(&shares_bytes);
preimage[64..96].copy_from_slice(&address_bytes);
preimage[96..128].copy_from_slice(&network_id_bytes);
preimage
}
@ -209,7 +222,7 @@ pub mod pallet {
pub enum Event<T: Config> {
SharesClaimed {
who: T::AccountId,
balance: BalanceOf<T>,
shares: BalanceOf<T>,
network_id: NetworkIdOf<T>,
}
}
@ -295,7 +308,9 @@ pub mod pallet {
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(<T as Config>::WeightInfo::claim())]
#[pallet::weight(<T as Config>::WeightInfo::claim(
claim_package.merkle_proof.len() as u32,
))]
pub fn claim(
origin: OriginFor<T>,
network_id: NetworkIdOf<T>,
@ -320,7 +335,7 @@ pub mod pallet {
ensure!(correct_network_bound, Error::<T>::BoundedToOtherNetwork);
let preimage = claim_package.get_preimage(&evm_address);
let preimage = claim_package.get_preimage(&evm_address, network_id);
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
ensure!(
@ -336,25 +351,25 @@ pub mod pallet {
let proof_size_match = package_proof_size == state.proofs_size;
ensure!(proof_size_match, Error::<T>::SharesOverflowed);
let increased = state.try_increase_claimed(claim_package.balance);
let increased = state.try_increase_claimed(claim_package.shares);
ensure!(increased.is_some(), Error::<T>::SharesOverflowed);
Ok(())
})?;
GlobalShares::<T>::try_mutate(|state| -> DispatchResult {
let increased = state.try_increase_claimed(claim_package.balance);
let increased = state.try_increase_claimed(claim_package.shares);
ensure!(increased.is_some(), Error::<T>::SharesOverflowed);
Ok(())
})?;
member_share.increase_activated_shares(claim_package.balance);
member_share.increase_activated_shares(claim_package.shares);
member_share.initiate_on_network(network_id);
MemberShares::<T>::insert(&who, member_share);
ClaimedHashes::<T>::insert(&preimage_hash, true);
Self::deposit_event(Event::<T>::SharesClaimed {
balance: claim_package.balance,
shares: claim_package.shares,
network_id,
who,
});
@ -447,11 +462,11 @@ impl<T: Config> Pallet<T> {
let network_state = NetworkShares::<T>::get(network_id);
let is_merkle_proof_valid =
verify_tree_proof::<SubstrateKeccakHasher, TokenId>(
verify_tree_proof::<SubstrateKeccakHasher, _>(
preimage,
&claim_package.merkle_proof,
network_state.merkle_root,
claim_package.token_id,
claim_package.index,
);
ensure!(is_merkle_proof_valid, Error::<T>::InvalidMerkleProof);

View File

@ -16,7 +16,7 @@ impl frame_system::Config for Test {
type RuntimeCall = RuntimeCall;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type AccountData = pallet_balances::AccountData<u64>;
type AccountData = pallet_balances::AccountData<u128>;
type MaxConsumers = frame_support::traits::ConstU32<16>;
type AccountId = sp_runtime::AccountId32;
@ -25,7 +25,9 @@ impl frame_system::Config for Test {
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
impl pallet_balances::Config for Test {
type ExistentialDeposit = frame_support::traits::ConstU128<1>;
type AccountStore = System;
type Balance = u128;
}
parameter_types! {

View File

@ -2,6 +2,7 @@
use mock::*;
use super::*;
use hex_literal::hex;
use sp_runtime::AccountId32;
use frame_support::traits::Get;
@ -15,7 +16,7 @@ pub struct NewTestUser {
pub substrate_account: AccountId32,
pub evm_secret: SecretKey,
pub evm_address: EvmAddress,
pub allowed_balance: u64,
pub allowed_shares: u128,
pub token_id: u128,
}
@ -39,7 +40,7 @@ fn claim_happy_path() {
substrate_account: AccountId32::new([11u8; 32]),
evm_secret: secret_key_1,
evm_address: EvmAddress::from(evm_addr_bytes_1),
allowed_balance: 420u64,
allowed_shares: 420u128,
token_id: 0,
};
@ -55,7 +56,7 @@ fn claim_happy_path() {
substrate_account: AccountId32::new([22u8; 32]),
evm_secret: secret_key_2,
evm_address: EvmAddress::from(evm_addr_bytes_2),
allowed_balance: 1337u64,
allowed_shares: 1337u128,
token_id: 1,
};
@ -71,7 +72,7 @@ fn claim_happy_path() {
substrate_account: AccountId32::new([69u8; 32]),
evm_secret: secret_key_3,
evm_address: EvmAddress::from(evm_addr_bytes_3),
allowed_balance: 69u64,
allowed_shares: 69u128,
token_id: 2,
};
@ -87,12 +88,13 @@ fn claim_happy_path() {
let (index, u) = item;
let tmp_package = ClaimPackage {
balance: u.allowed_balance,
shares: u.allowed_shares,
merkle_proof: Default::default(),
token_id: u.token_id,
index: index as u32
};
Ok((index as usize, tmp_package.get_preimage(&u.evm_address).to_vec()))
Ok((index as usize, tmp_package.get_preimage(&u.evm_address, network_id).to_vec()))
}
).unwrap();
@ -117,12 +119,13 @@ fn claim_happy_path() {
let proof = generate_proof::<SubstrateKeccakHasher, u8>(&merkle_tree, max_index, slot_index as u8);
let claim_package = ClaimPackage {
balance: current_user.allowed_balance,
shares: current_user.allowed_shares,
merkle_proof: BoundedVec::try_from(proof).unwrap(),
token_id: current_user.token_id,
index: slot_index as u32,
};
let preimage = claim_package.get_preimage(&current_user.evm_address);
let preimage = claim_package.get_preimage(&current_user.evm_address, network_id);
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
let message_string_bytes = Governance::ethereum_signable_message(
@ -155,10 +158,10 @@ fn claim_happy_path() {
));
let updated_share = MemberShares::<Test>::get(&current_user.substrate_account);
assert_eq!(updated_share.activated_shares, current_user.allowed_balance);
assert_eq!(updated_share.activated_shares, current_user.allowed_shares);
global_activated += current_user.allowed_balance;
network_activated += current_user.allowed_balance;
global_activated += current_user.allowed_shares;
network_activated += current_user.allowed_shares;
}
assert_eq!(global_activated, GlobalShares::<Test>::get().claimed_shares);
@ -168,3 +171,139 @@ fn claim_happy_path() {
);
});
}
#[test]
fn verify_proof_from_python_preclaims_for_sepolia() {
new_test_ext().execute_with(|| {
// ===========================================================================================================
// === FINAL MERKLE ROOT FOR [SEPOLIA]: 0xd7f7f0061338c2c59a96caa8a2572491315755cdcce534954d4ce30150c3bb7c ===
// ===========================================================================================================
// [+] Total padded leaves: 128
// [+] Merkle tree size: 255
// [+] Network ID: 11155111
// [+] Proof size: 7
// [+] Total shares: 694000000000000000000
let network_id = 11155111u64;
let merkle_root = EvmHash::from(hex!("d7f7f0061338c2c59a96caa8a2572491315755cdcce534954d4ce30150c3bb7c"));
let proof_size = 7;
let total_shares = 694000000000000000000;
let network_state = NetworkShare::new(total_shares, merkle_root, proof_size);
let global_state = ShareState::new(total_shares);
NetworkShares::<Test>::insert(&network_id, network_state);
GlobalShares::<Test>::put(global_state);
let evm_holder_1 = EvmAddress::from(hex!("D500EFDef75E89Bf6caF5C98F7633575d0049a72"));
let claim_package_1 = ClaimPackage {
index: 0,
token_id: 1,
shares: 670000000000000000000,
merkle_proof: BoundedVec::try_from(
vec![
EvmHash::from(hex!("4dba08ba4fae6cbb0a6be6bdce81e91baf913d1857f470e97388157edd4d8d5c")),
EvmHash::from(hex!("7c1a4d2ebe6a500171b0c0f6c624898261da62d09c132106c4acec277660bd01")),
EvmHash::from(hex!("00c5bca05597b46f72d9ee739bd3c6ff80ebd1d20944879fe0c8d1dc9fda1643")),
EvmHash::from(hex!("5cf752cd738db6581182f07395e89cc61cd2ca630d6e85235d506f7395217d5f")),
EvmHash::from(hex!("4df068cecd63b6ccfd326df735afbfbe254df62613f7d9b52769f0e99f156957")),
EvmHash::from(hex!("d7f20777e3a1fed303fe1a459ce115e2561a92d66b34fd16dd793b8b69295082")),
EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4")),
]
).unwrap(),
};
let preimage_1 = claim_package_1.get_preimage(&evm_holder_1, network_id);
assert_ok!(
Governance::verify_merkle_proof(
&network_id,
&preimage_1,
&claim_package_1,
)
);
let evm_holder_2 = EvmAddress::from(hex!("Ee71538ae7677829676BD8dD18259Ed93E6B44e9"));
let claim_package_2 = ClaimPackage {
index: 2,
token_id: 3,
shares: 8000000000000000000,
merkle_proof: BoundedVec::try_from(
vec![
EvmHash::from(hex!("a8bbe4e0578964e3e6c40b93380967d69b7a1fd0358bffe789473892ec82872d")),
EvmHash::from(hex!("9b771d13977930979a26632d74e350885d5750b00646a5b03114b5815afb9f2f")),
EvmHash::from(hex!("00c5bca05597b46f72d9ee739bd3c6ff80ebd1d20944879fe0c8d1dc9fda1643")),
EvmHash::from(hex!("5cf752cd738db6581182f07395e89cc61cd2ca630d6e85235d506f7395217d5f")),
EvmHash::from(hex!("4df068cecd63b6ccfd326df735afbfbe254df62613f7d9b52769f0e99f156957")),
EvmHash::from(hex!("d7f20777e3a1fed303fe1a459ce115e2561a92d66b34fd16dd793b8b69295082")),
EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4")),
]
).unwrap(),
};
let preimage_2 = claim_package_2.get_preimage(&evm_holder_2, network_id);
assert_ok!(
Governance::verify_merkle_proof(
&network_id,
&preimage_2,
&claim_package_2,
)
);
let evm_holder_3 = EvmAddress::from(hex!("29c6D9e3c3981e4FcF2AC6B486e4E4210daeA1Ee"));
let claim_package_3 = ClaimPackage {
index: 6,
token_id: 7,
shares: 4000000000000000000,
merkle_proof: BoundedVec::try_from(
vec![
EvmHash::from(hex!("d28eec1544597d9e050c88a7a84535be82caf9b9e0b0c9b59b39283e7885a0d1")),
EvmHash::from(hex!("6e939188f98c3ed00931e66fdfc220c036b98edc54a212f5b18e2d3776c7c22f")),
EvmHash::from(hex!("4141baa2d892b0111bbb102078bd3ad5331c74f176b228c588741c1c306cb67d")),
EvmHash::from(hex!("5cf752cd738db6581182f07395e89cc61cd2ca630d6e85235d506f7395217d5f")),
EvmHash::from(hex!("4df068cecd63b6ccfd326df735afbfbe254df62613f7d9b52769f0e99f156957")),
EvmHash::from(hex!("d7f20777e3a1fed303fe1a459ce115e2561a92d66b34fd16dd793b8b69295082")),
EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4"))
]
).unwrap(),
};
let preimage_3 = claim_package_3.get_preimage(&evm_holder_3, network_id);
assert_ok!(
Governance::verify_merkle_proof(
&network_id,
&preimage_3,
&claim_package_3,
)
);
let evm_holder_4 = EvmAddress::from(hex!("Fe962E8BB2a6877d14b53E0a07932C040eC885ea"));
let claim_package_4 = ClaimPackage {
index: 35,
token_id: 36,
shares: 4000000000000000000,
merkle_proof: BoundedVec::try_from(
vec![
EvmHash::from(hex!("6b405422bcab22b7c28a9b429096e31d664522154856efb0d7b16485080b2e2a")),
EvmHash::from(hex!("620bb1858eaf6c6bb543fcf5f4b0d0b5adfbb95506403038eb153f075a00f522")),
EvmHash::from(hex!("e0b7058849ff216808963201ad2336f5587ff02eff08aceddb4764cc785413fd")),
EvmHash::from(hex!("e23325a502fe4248c8e049400a92a1c655689499c129b0ce6be3fad5d4a12dc1")),
EvmHash::from(hex!("0cde8f646452003d6c8ff1fd265ea41cd3af2e733e63ec25a9dfc82ddf41e968")),
EvmHash::from(hex!("c012942dae89ee6d1e1e44e876ae29b9421aaf0597dd2345f07a1439a98e0cbd")),
EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4"))
]
).unwrap(),
};
let preimage_4 = claim_package_4.get_preimage(&evm_holder_4, network_id);
assert_ok!(
Governance::verify_merkle_proof(
&network_id,
&preimage_4,
&claim_package_4,
)
);
})
}

View File

@ -48,7 +48,7 @@ use core::marker::PhantomData;
/// Weight functions needed for `ghost_claims`.
pub trait WeightInfo {
fn claim() -> Weight;
fn claim(p: u32) -> Weight;
}
impl WeightInfo for () {
@ -64,7 +64,7 @@ impl WeightInfo for () {
/// Proof: `CultCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IndexToId` (r:0 w:6)
/// Proof: `CultCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
fn claim() -> Weight {
fn claim(_p: u32) -> Weight {
// Proof Size summary in bytes:
// Measured: `896`
// Estimated: `16164`

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-helpers"
version = "0.0.5"
version = "0.0.6"
description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components."
license.workspace = true
authors.workspace = true

View File

@ -223,8 +223,8 @@ pub struct NetworkData {
pub rate_limit_delay: u64,
pub block_deviation: u64,
pub incoming_fee: u32,
pub outgoing_fee: u32,
pub incoming_share: u32,
pub outgoing_share: u32,
}
#[derive(Default)]
@ -240,8 +240,8 @@ pub struct NetworkDataBuilder {
pub rate_limit_delay: u64,
pub block_deviation: u64,
pub incoming_fee: u32,
pub outgoing_fee: u32,
pub incoming_share: u32,
pub outgoing_share: u32,
}
impl NetworkDataBuilder {
@ -280,13 +280,13 @@ impl NetworkDataBuilder {
self
}
pub fn with_incoming_fee(mut self, incoming_fee: u32) -> Self {
self.incoming_fee = incoming_fee;
pub fn with_incoming_share(mut self, incoming_share: u32) -> Self {
self.incoming_share = incoming_share;
self
}
pub fn with_outgoing_fee(mut self, outgoing_fee: u32) -> Self {
self.outgoing_fee = outgoing_fee;
pub fn with_outgoing_share(mut self, outgoing_share: u32) -> Self {
self.outgoing_share = outgoing_share;
self
}
@ -328,8 +328,8 @@ impl NetworkDataBuilder {
rate_limit_delay: self.rate_limit_delay,
block_deviation: self.block_deviation,
incoming_fee: self.incoming_fee,
outgoing_fee: self.outgoing_fee,
incoming_share: self.incoming_share,
outgoing_share: self.outgoing_share,
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-networks"
version = "0.2.7"
version = "0.2.8"
description = "Registry and lifecycle management for external network metadata and cryptographic profiles."
license.workspace = true
authors.workspace = true

View File

@ -42,8 +42,8 @@ fn prepare_network<T: Config>(
.with_rate_limit_delay(6)
.with_finality_delay(69)
.with_block_deviation(420)
.with_incoming_fee(0)
.with_outgoing_fee(0)
.with_incoming_share(0)
.with_outgoing_share(0)
.build();
(chain_id, network)
@ -204,27 +204,27 @@ benchmarks! {
assert_ne!(GhostNetworks::<T>::networks(chain_id), prev_network);
}
update_incoming_network_fee {
let incoming_fee = 1337;
update_incoming_network_share {
let incoming_share = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id, network)?;
}: _<T::RuntimeOrigin>(authority, chain_id, incoming_fee)
}: _<T::RuntimeOrigin>(authority, chain_id, incoming_share)
verify {
assert_last_event::<T>(Event::NetworkIncomingFeeUpdated { chain_id, incoming_fee }.into());
assert_last_event::<T>(Event::NetworkIncomingShareUpdated { chain_id, incoming_share }.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
}
update_outgoing_network_fee {
let outgoing_fee = 1337;
update_outgoing_network_share {
let outgoing_share = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id, network)?;
}: _<T::RuntimeOrigin>(authority, chain_id, outgoing_fee)
}: _<T::RuntimeOrigin>(authority, chain_id, outgoing_share)
verify {
assert_last_event::<T>(Event::NetworkOutgoingFeeUpdated { chain_id, outgoing_fee }.into());
assert_last_event::<T>(Event::NetworkOutgoingShareUpdated { chain_id, outgoing_share }.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id), prev_network);
}

View File

@ -1,6 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::large_enum_variant)]
#![allow(clippy::too_many_arguments)]
use frame_support::{
pallet_prelude::*,
@ -12,8 +10,11 @@ use scale_info::TypeInfo;
use sp_runtime::{
curve::PiecewiseLinear,
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member, UniqueSaturatedInto},
DispatchResult,
traits::{
AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member,
Saturating, UniqueSaturatedInto,
},
DispatchResult, Perbill,
};
use sp_std::{convert::TryInto, prelude::*};
@ -42,9 +43,10 @@ pub type BalanceOf<T> =
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct BridgeAdjustment<Balance> {
pub bridged_out: Balance,
pub bridged_in: Balance,
pub struct NetworkImbalanceState<Balance> {
pub outgoing: Balance,
pub incoming: Balance,
pub curve_share: Balance,
}
pub struct BridgedInflationCurve<RewardCurve, T>(core::marker::PhantomData<(RewardCurve, T)>);
@ -71,16 +73,18 @@ where
_era_duration_in_millis: u64,
) -> (Balance, Balance) {
let reward_curve = RewardCurve::get();
let bridged_imbalance = BridgedImbalance::<T>::take();
let accumulated_commission = AccumulatedCommission::<T>::take();
let state = NetworkImbalance::<T>::take();
let accumulated_commission: Balance = accumulated_commission.into();
let accumulated_commission: Balance = state.curve_share.into();
let adjusted_issuance: Balance = total_issuance
.saturating_add(bridged_imbalance.bridged_out.into())
.saturating_sub(bridged_imbalance.bridged_in.into());
.saturating_add(state.outgoing.into())
.saturating_sub(state.incoming.into());
let estimated_reward =
reward_curve.calculate_for_fraction_times_denominator(total_staked, adjusted_issuance);
reward_curve.calculate_for_fraction_times_denominator(
total_staked,
adjusted_issuance,
);
let payout: Balance = sp_runtime::helpers_128bit::multiply_by_rational_with_rounding(
estimated_reward.unique_saturated_into(),
@ -172,20 +176,19 @@ pub mod module {
NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType },
NetworkCurveUpdated { chain_id: T::NetworkId, network_curve: NetworkCurve },
NetworkGatekeeperUpdated { chain_id: T::NetworkId },
NetworkIncomingFeeUpdated { chain_id: T::NetworkId, incoming_fee: u32 },
NetworkOutgoingFeeUpdated { chain_id: T::NetworkId, outgoing_fee: u32 },
NetworkIncomingShareUpdated { chain_id: T::NetworkId, incoming_share: u32 },
NetworkOutgoingShareUpdated { chain_id: T::NetworkId, outgoing_share: u32 },
NetworkAvgBlockSpeedUpdated { chain_id: T::NetworkId, avg_block_speed: u64 },
NetworkRemoved { chain_id: T::NetworkId },
}
#[pallet::storage]
#[pallet::getter(fn bridged_imbalance)]
pub type BridgedImbalance<T: Config> =
StorageValue<_, BridgeAdjustment<BalanceOf<T>>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn accumulated_commission)]
pub type AccumulatedCommission<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
#[pallet::getter(fn network_imbalance)]
pub type NetworkImbalance<T: Config> = StorageValue<
_,
NetworkImbalanceState<BalanceOf<T>>,
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn network_indexes)]
@ -216,8 +219,8 @@ pub mod module {
>;
#[pallet::storage]
#[pallet::getter(fn gatekeeper_amount)]
pub type GatekeeperAmount<T: Config> =
#[pallet::getter(fn gatekeeper_amounts)]
pub type GatekeeperAmounts<T: Config> =
StorageMap<_, Twox64Concat, T::NetworkId, BalanceOf<T>, ValueQuery>;
#[pallet::genesis_config]
@ -239,7 +242,7 @@ pub mod module {
.for_each(|network| {
Pallet::<T>::do_register_network(network.id, network.data.clone())
.expect("Error registering network");
GatekeeperAmount::<T>::insert(network.id, network.amount);
GatekeeperAmounts::<T>::insert(network.id, network.amount);
});
}
@ -366,25 +369,25 @@ pub mod module {
}
#[pallet::call_index(9)]
#[pallet::weight(T::WeightInfo::update_incoming_network_fee())]
pub fn update_incoming_network_fee(
#[pallet::weight(T::WeightInfo::update_incoming_network_share())]
pub fn update_incoming_network_share(
origin: OriginFor<T>,
chain_id: T::NetworkId,
incoming_fee: u32,
incoming_share: u32,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_incoming_network_fee(chain_id, incoming_fee)
Self::do_update_incoming_network_share(chain_id, incoming_share)
}
#[pallet::call_index(10)]
#[pallet::weight(T::WeightInfo::update_outgoing_network_fee())]
pub fn update_outgoing_network_fee(
#[pallet::weight(T::WeightInfo::update_outgoing_network_share())]
pub fn update_outgoing_network_share(
origin: OriginFor<T>,
chain_id: T::NetworkId,
outgoing_fee: u32,
outgoing_share: u32,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_outgoing_network_fee(chain_id, outgoing_fee)
Self::do_update_outgoing_network_share(chain_id, outgoing_share)
}
#[pallet::call_index(11)]
@ -688,38 +691,38 @@ impl<T: Config> Pallet<T> {
Ok(())
}
pub fn do_update_incoming_network_fee(
pub fn do_update_incoming_network_share(
chain_id: T::NetworkId,
incoming_fee: u32,
incoming_share: u32,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
net.incoming_fee = incoming_fee;
net.incoming_share = incoming_share;
*maybe_network = Some(net.clone());
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkIncomingFeeUpdated {
Self::deposit_event(Event::<T>::NetworkIncomingShareUpdated {
chain_id,
incoming_fee,
incoming_share,
});
Ok(())
}
pub fn do_update_outgoing_network_fee(
pub fn do_update_outgoing_network_share(
chain_id: T::NetworkId,
outgoing_fee: u32,
outgoing_share: u32,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
net.outgoing_fee = outgoing_fee;
net.outgoing_share = outgoing_share;
*maybe_network = Some(net.clone());
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkOutgoingFeeUpdated {
Self::deposit_event(Event::<T>::NetworkOutgoingShareUpdated {
chain_id,
outgoing_fee,
outgoing_share,
});
Ok(())
}
@ -793,79 +796,61 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
Self::do_remove_network(chain_id)
}
fn increase_gatekeeper_amount(
fn register_incoming(
network_id: &T::NetworkId,
amount: &BalanceOf<T>,
amount: BalanceOf<T>,
) -> Result<BalanceOf<T>, ()> {
let new_gatekeeper_amount =
GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| match gatekeeper_amount
.checked_add(amount)
{
Some(value) => {
*gatekeeper_amount = value;
Ok(value)
}
None => Err(()),
})?;
let incoming_share = Networks::<T>::get(&network_id)
.map(|network| network.incoming_share)
.ok_or(())?;
Ok(new_gatekeeper_amount)
}
fn decrease_gatekeeper_amount(
network_id: &T::NetworkId,
amount: &BalanceOf<T>,
) -> Result<BalanceOf<T>, ()> {
let new_gatekeeper_amount =
GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| match gatekeeper_amount
.checked_sub(amount)
{
Some(value) => {
*gatekeeper_amount = value;
Ok(value)
}
None => Err(()),
})?;
Ok(new_gatekeeper_amount)
}
fn accumulate_outgoing_imbalance(amount: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
let new_bridged_out_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_out.checked_add(amount) {
Some(value) => {
(*bridged_imbalance).bridged_out = value;
Ok(value)
}
None => Err(()),
}
GatekeeperAmounts::<T>::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> {
*gatekeeper_amount = gatekeeper_amount.checked_add(&amount).ok_or(())?;
Ok(())
})?;
Ok(new_bridged_out_amount)
}
let curve_share = Perbill::from_parts(incoming_share).mul_ceil(amount);
let final_amount = amount.saturating_sub(curve_share);
fn accumulate_incoming_imbalance(amount: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
let new_bridged_in_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_in.checked_add(amount) {
Some(value) => {
(*bridged_imbalance).bridged_in = value;
Ok(value)
}
None => Err(()),
}
NetworkImbalance::<T>::try_mutate(|imbalance_state| -> Result<(), ()> {
imbalance_state.incoming = imbalance_state.incoming
.checked_add(&final_amount)
.ok_or(())?;
imbalance_state.curve_share = imbalance_state.curve_share
.checked_add(&curve_share)
.ok_or(())?;
Ok(())
})?;
Ok(new_bridged_in_amount)
Ok(final_amount)
}
fn accumulate_commission(commission: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
AccumulatedCommission::<T>::mutate(|accumulated| {
match accumulated.checked_add(commission) {
Some(value) => {
*accumulated = value;
Ok(value)
}
None => Err(()),
}
})
fn register_outgoing(
network_id: &T::NetworkId,
amount: BalanceOf<T>
) -> Result<BalanceOf<T>, ()> {
let outgoing_share = Networks::<T>::get(&network_id)
.map(|network| network.outgoing_share)
.ok_or(())?;
GatekeeperAmounts::<T>::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> {
*gatekeeper_amount = gatekeeper_amount.checked_sub(&amount).ok_or(())?;
Ok(())
})?;
let curve_share = Perbill::from_parts(outgoing_share).mul_ceil(amount);
let final_amount = amount.saturating_sub(curve_share);
NetworkImbalance::<T>::try_mutate(|imbalance_state| -> Result<(), ()> {
imbalance_state.outgoing = imbalance_state.outgoing
.checked_add(&final_amount)
.ok_or(())?;
imbalance_state.curve_share = imbalance_state.curve_share
.checked_add(&curve_share)
.ok_or(())?;
Ok(())
})?;
Ok(final_amount)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -58,8 +58,8 @@ pub trait WeightInfo {
fn update_network_curve() -> Weight;
fn update_network_gatekeeper() -> Weight;
fn update_network_topic_name() -> Weight;
fn update_incoming_network_fee() -> Weight;
fn update_outgoing_network_fee() -> Weight;
fn update_incoming_network_share() -> Weight;
fn update_outgoing_network_share() -> Weight;
fn update_avg_block_speed() -> Weight;
fn remove_network() -> Weight;
}
@ -191,7 +191,7 @@ impl WeightInfo for () {
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_incoming_network_fee() -> Weight {
fn update_incoming_network_share() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
@ -203,7 +203,7 @@ impl WeightInfo for () {
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_outgoing_network_fee() -> Weight {
fn update_outgoing_network_share() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`

View File

@ -16,7 +16,6 @@
// limitations under the License.
use super::*;
use crate::log;
use frame_support::traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-traits"
version = "0.4.2"
version = "0.4.3"
description = "Shared traits including `GhostHasher`, `NetworkDataBasicHandler`, `BoundedBTreeMap`, `MerkleTree` and more."
license.workspace = true
authors.workspace = true

View File

@ -47,18 +47,8 @@ pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<
fn register(chain_id: Self::NetworkId, network: Network) -> DispatchResult;
fn remove(chain_id: Self::NetworkId) -> DispatchResult;
fn increase_gatekeeper_amount(
chain_id: &Self::NetworkId,
amount: &Balance,
) -> Result<Balance, ()>;
fn decrease_gatekeeper_amount(
chain_id: &Self::NetworkId,
amount: &Balance,
) -> Result<Balance, ()>;
fn accumulate_outgoing_imbalance(amount: &Balance) -> Result<Balance, ()>;
fn accumulate_incoming_imbalance(amount: &Balance) -> Result<Balance, ()>;
fn accumulate_commission(commission: &Balance) -> Result<Balance, ()>;
fn register_incoming(chain_id: &Self::NetworkId, amount: Balance) -> Result<Balance, ()>;
fn register_outgoing(chain_id: &Self::NetworkId, amount: Balance) -> Result<Balance, ()>;
}
pub trait NetworkRpcResolver<W, B, H, I, S> {

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-weaver"
version = "0.0.0"
version = "0.0.2"
description = "Weaving a secure cryptographic tapestry across different external chains."
license.workspace = true
authors.workspace = true

View File

@ -19,8 +19,8 @@ use sp_runtime::{
storage::StorageValueRef,
storage_lock::{StorageLock, Time},
},
traits::{BlockNumberProvider, Saturating, UniqueSaturatedInto},
Perbill, RuntimeAppPublic,
traits::{BlockNumberProvider, UniqueSaturatedInto},
RuntimeAppPublic,
};
use ghost_helpers::{
@ -47,7 +47,7 @@ mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
#[cfg(any(test, feature = "runtime-benchmarks"))]
#[cfg(any(test))]
mod mock;
use crate::errors::*;
@ -179,9 +179,7 @@ pub mod pallet {
ThreadAlreadyPulled,
InvalidMerkleProof,
InvalidReceiverAddress,
CouldNotAccumulateIncomingImbalance,
CouldNotIncreaseGatekeeperAmount,
CouldNotAccumulateCommission,
CouldNotRegisterIncoming,
}
#[pallet::storage]
@ -446,24 +444,14 @@ pub mod pallet {
.verify_proof(root_hash, &network_data.gatekeeper)
.ok_or(Error::<T>::InvalidMerkleProof)?;
let amount = thread_proof.amount().clone();
let receiver_bytes: &[u8; 32] = receiver_account.as_ref();
let receiver = T::AccountId::decode(&mut &receiver_bytes[..])
.map_err(|_| Error::<T>::InvalidReceiverAddress)?;
let commission = Perbill::from_parts(network_data.incoming_fee).mul_ceil(amount);
let pure_amount = amount.saturating_sub(commission);
let _ = T::NetworkDataHandler::accumulate_incoming_imbalance(&pure_amount)
.map_err(|_| Error::<T>::CouldNotAccumulateIncomingImbalance)
.and_then(|_| {
T::NetworkDataHandler::increase_gatekeeper_amount(&network_id, &amount)
.map_err(|_| Error::<T>::CouldNotIncreaseGatekeeperAmount)
})
.and_then(|_| {
T::NetworkDataHandler::accumulate_commission(&commission)
.map_err(|_| Error::<T>::CouldNotAccumulateCommission)
})?;
let amount = thread_proof.amount();
let pure_amount =
T::NetworkDataHandler::register_incoming(&network_id, amount)
.map_err(|_| Error::<T>::CouldNotRegisterIncoming)?;
let _ = T::Currency::deposit_creating(&receiver, pure_amount);
PulledThreads::<T>::insert(pulled_thread_key, ());

View File

@ -220,16 +220,6 @@ impl<Block, NetworkId, AuthIndex> AttestationMetadata<Block, NetworkId, AuthInde
}
}
#[derive(Default, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct NetworkAttestation<Block, BoundedMap>
where
Block: AtLeast32BitUnsigned + Encode + Decode + TypeInfo + MaxEncodedLen + Default,
BoundedMap: Encode + Decode + TypeInfo + MaxEncodedLen + Default + Clone,
{
pub until: Block,
pub map: BoundedMap,
}
#[derive(Default, Copy, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct TapestryDraft<Block: AtLeast32BitUnsigned> {
pub until: Block,
@ -277,12 +267,6 @@ where
}
}
#[derive(Default, Copy, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct LoomState {
pub hash: H256,
pub pulled_threads: ThreadId,
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct ThreadPayload<Balance: UniqueSaturatedInto<u128>> {
proof_index: ThreadId,

View File

@ -1,6 +1,6 @@
[package]
name = "casper-runtime"
version = "4.0.0"
version = "4.0.2"
build = "build.rs"
description = "Runtime of the Casper Network"
edition.workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "casper-runtime-constants"
version = "0.4.0"
version = "0.4.2"
authors.workspace = true
edition.workspace = true
homepage.workspace = true

View File

@ -15,10 +15,10 @@ pub mod currency {
pub const CSPR: Balance = 1_000 * STRH; // 10^18
/// The existential deposit.
pub const EXISTENTIAL_DEPOSIT: Balance = STNK;
pub const EXISTENTIAL_DEPOSIT: Balance = 500 * STNK;
pub const fn deposit(items: u32, bytes: u32) -> Balance {
(items as Balance) * 20 * STRH + (bytes as Balance) * 200 * STNK
(items as Balance) * 2 * STRH + (bytes as Balance) * 200 * STNK
}
}
@ -39,7 +39,7 @@ pub mod time {
// 1 in 4 blocks (on average, not counting collisions) woll be primary babe
// blocks.The choice of is done on accordance to the slot duration and expected
// target block tim, for safely resisting network delays of maximum two
// target block time, for safely resisting network delays of maximum two
// seconds.
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
}
@ -69,7 +69,7 @@ pub mod fee {
type Balance = Balance;
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
let fee_per_nanosecond: Balance = 10 * super::currency::FTSO;
let fee_per_nanosecond: Balance = (424 * super::currency::FTSO) / 1_200_000;
smallvec![WeightToFeeCoefficient {
degree: 1,
@ -84,7 +84,7 @@ pub mod fee {
#[cfg(test)]
mod tests {
use super::{
currency::{CSPR, STNK, STRH},
currency::{CSPR, STNK},
fee::WeightToFee,
};
use crate::weights::ExtrinsicBaseWeight;
@ -94,18 +94,22 @@ mod tests {
#[test]
fn full_block_fee_is_correct() {
let full_block = WeightToFee::weight_to_fee(&MAXIMUM_BLOCK_WEIGHT);
assert!(full_block >= 50 * CSPR);
assert!(full_block <= 70 * CSPR);
let lower_bound = 1 * CSPR;
let upper_bound = 2 * CSPR;
assert!(full_block >= lower_bound);
assert!(full_block <= upper_bound);
}
#[test]
fn extrinsic_base_fee_is_correct() {
let x = WeightToFee::weight_to_fee(&ExtrinsicBaseWeight::get());
let ext_weight = WeightToFee::weight_to_fee(&ExtrinsicBaseWeight::get());
let lower_bound = STRH / 2;
let upper_bound = (3 * STRH) / 2;
let lower_bound = 100 * STNK;
let upper_bound = 300 * STNK;
assert!(x >= lower_bound);
assert!(x <= upper_bound);
assert!(ext_weight >= lower_bound);
assert!(ext_weight <= upper_bound);
}
}

View File

@ -7,15 +7,15 @@
// Ghost Network is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Ghost Network. If not, see <http://www.gnu.org/licenses/>.
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2024-07-30 (Y/M/D)
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! DATE: 2026-08-31 (Y/M/D)
//! HOSTNAME: `LAPTOP-IOUQRLAP`, CPU: `AMD Ryzen 7 2700U with Radeon Vega Mobile Gfx`
//!
//! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development`
//! WARMUPS: `10`, REPEAT: `100`
@ -37,43 +37,43 @@ use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight};
parameter_types! {
/// Time to execute an empty block.
/// Calculated by multiplying the *Average* with `1.0` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 64_363_191, 66_078_314
/// Average: 64_551_214
/// Median: 64_500_078
/// Std-Dev: 229678.99
///
/// Percentiles nanoseconds:
/// 99th: 65_668_012
/// 95th: 64_888_421
/// 75th: 64_563_448
pub const BlockExecutionWeight: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(64_551_214), 0);
/// Time to execute an empty block.
/// Calculated by multiplying the *Average* with `1.0` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 553_400, 1_996_400
/// Average: 771_526
/// Median: 680_500
/// Std-Dev: 248209.17
///
/// Percentiles nanoseconds:
/// 99th: 1_652_700
/// 95th: 1_212_900
/// 75th: 849_300
pub const BlockExecutionWeight: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(771_526), 0);
}
#[cfg(test)]
mod test_weights {
use sp_weights::constants;
use sp_weights::constants;
/// Checks that the weight exists and is sane.
// NOTE: If this test fails but you are sure that the generated values are fine,
// you can delete it.
#[test]
fn sane() {
let w = super::BlockExecutionWeight::get();
/// Checks that the weight exists and is sane.
// NOTE: If this test fails but you are sure that the generated values are fine,
// you can delete it.
#[test]
fn sane() {
let w = super::BlockExecutionWeight::get();
// At least 100 µs.
assert!(
w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS,
"Weight should be at least 100 µs."
);
// At most 50 ms.
assert!(
w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS,
"Weight should be at most 50 ms."
);
}
// At least 100 µs.
assert!(
w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS,
"Weight should be at least 100 µs."
);
// At most 50 ms.
assert!(
w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS,
"Weight should be at most 50 ms."
);
}
}

View File

@ -221,8 +221,8 @@ fn casper_testnet_networks() -> Vec<NetworkInitiation<NetworkId, Balance>> {
.with_finality_delay(69)
.with_rate_limit_delay(5_000)
.with_block_deviation(420)
.with_incoming_fee(69_000_000u32)
.with_outgoing_fee(69_000_000u32)
.with_incoming_share(69_000_000u32)
.with_outgoing_share(69_000_000u32)
.build()
)
.build()
@ -235,8 +235,9 @@ pub fn testnet_config_genesis(
initial_networks: Vec<NetworkInitiation<NetworkId, Balance>>,
initial_claims: Vec<NetworkClaim<NetworkId, Balance>>,
) -> serde_json::Value {
const ENDOWMENT: u128 = 31 * CSPR;
const STASH: u128 = 69 * CSPR;
const ENDOWMENT: u128 = 31 * CSPR;
const STASH_BOND: u128 = 68 * CSPR;
const STASH_FEES: u128 = 1 * CSPR;
let sudo = initial_authorities.first().map(|x| x.account.clone()).unwrap();
@ -246,7 +247,7 @@ pub fn testnet_config_genesis(
.iter()
.map(|x| (x.account.clone(), x.balance))
.chain(initial_authorities.iter().map(|x| (x.account.clone(), ENDOWMENT)))
.chain(initial_authorities.iter().map(|x| (x.stash.clone(), STASH)))
.chain(initial_authorities.iter().map(|x| (x.stash.clone(), STASH_BOND + STASH_FEES)))
.collect::<Vec<_>>(),
},
"session": {
@ -258,25 +259,39 @@ pub fn testnet_config_genesis(
.collect::<Vec<_>>(),
},
"staking": {
"validatorCount": initial_authorities.len() as u32,
"minimumValidatorCount": 4,
"invulnerables": initial_authorities
.iter()
.map(|x| x.stash.clone())
.collect::<Vec<_>>(),
// "minNominatorBond": 42 * CSPR,
// "minValidatorBond": 6900 * STRH,
// "maxNominatorsCount": 3000u32,
// "maxValidatorsCount": 500u32,
"minimumValidatorCount": if cfg!(feature = "runtime-benchmarks") {
1u32
} else {
4u32
},
// "validatorCount": 50u32,
"forceEra": Forcing::NotForcing,
"slashRewardFraction": Perbill::from_percent(10),
// "slashRewardFraction": Perbill::from_percent(10),
"stakers": initial_authorities
.iter()
.map(|x| (
x.stash.clone(),
x.stash.clone(),
STASH,
STASH_BOND,
StakerStatus::<AccountId>::Validator,
))
.collect::<Vec<_>>(),
},
"babe": { "epochConfig": Some(crate::BABE_GENESIS_EPOCH_CONFIG) },
// "ghostNominationPools": {
// "minJoinBond": 10 * STNK,
// "minCreateBond": 20 * CSPR,
// "maxPools": 256u32,
// "maxMembersPerPool": 1024u32,
// "maxMembers": 20000u32,
// "globalMaxCommission": Perbill::from_percent(15),
// },
"ghostSudo": { "key": sudo },
"ghostNetworks": { "networks": initial_networks },
"ghostGovernance": { "networkClaims": initial_claims },

View File

@ -14,11 +14,15 @@ use frame_support::{
genesis_builder_helper::{build_state, get_preset},
traits::{
fungible::HoldConsideration,
tokens::{imbalance::ResolveTo, PayFromAccount, UnityAssetBalanceConversion},
tokens::{imbalance::ResolveTo, UnityAssetBalanceConversion},
ConstU128, ConstU32, InstanceFilter, KeyOwnerProofSystem,
LinearStoragePrice,
},
};
#[cfg(not(feature = "runtime-benchmarks"))]
use frame_support::traits::tokens::PayFromAccount;
use frame_system::EnsureRoot;
use runtime_common::{
impl_runtime_weights, impls::DealWithFees, prod_or_fast, BlockHashCount, BlockLength,
@ -238,8 +242,8 @@ impl pallet_babe::Config for Runtime {
type DisabledValidators = Session;
type WeightInfo = weights::pallet_babe::WeightInfo<Runtime>;
type MaxAuthorities = MaxAuthorities;
type MaxNominators = MaxNominators;
type MaxAuthorities = MaxActiveValidators;
type MaxNominators = MaxElectingVoters;
type KeyOwnerProof =
<Historical as KeyOwnerProofSystem<(KeyTypeId, pallet_babe::AuthorityId)>>::Proof;
@ -339,9 +343,9 @@ parameter_types! {
// 4 hour session, 1 hour unsigned phase, 32 ofchain executions.
pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 32;
pub const MaxElectingVoters: u32 = 5_000;
pub const MaxElectableTargets: u32 = 1500;
pub const MaxActiveValidators: u32 = 1_000;
pub const MaxElectingVoters: u32 = 3_000;
pub const MaxElectableTargets: u32 = 400;
pub const MaxActiveValidators: u32 = 300;
// ... and all of the validators as electable targets. Whilist this is the
// case, we cannot and shall increase the size of the validator intentions.
@ -549,8 +553,6 @@ parameter_types! {
pub const DataDepositPerByte: Balance = 1 * STRH;
pub const MaxApprovals: u32 = 10;
pub const MaxAuthorities: u32 = 1_500;
pub const MaxNominators: u32 = 10_000;
}
#[cfg(not(feature = "runtime-benchmarks"))]
@ -577,8 +579,8 @@ impl EnsureOrigin<RuntimeOrigin> for RootSpendOrigin {
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> RuntimeOrigin {
EnsureRoot::<AccountId>::successful_origin()
fn try_successful_origin() -> Result<RuntimeOrigin, ()> {
EnsureRoot::<AccountId>::try_successful_origin()
}
}
@ -644,7 +646,7 @@ impl pallet_offences::Config for Runtime {
}
impl pallet_authority_discovery::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
type MaxAuthorities = MaxActiveValidators;
}
parameter_types! {
@ -661,8 +663,8 @@ impl pallet_grandpa::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::pallet_grandpa::WeightInfo<Runtime>;
type MaxAuthorities = MaxAuthorities;
type MaxNominators = MaxNominators;
type MaxAuthorities = MaxActiveValidators;
type MaxNominators = MaxElectingVoters;
type MaxSetIdSessionEntries = MaxSetIdSessionEntries;
type KeyOwnerProof = <Historical as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
@ -1054,7 +1056,6 @@ mod benches {
// that path resolves correctly in the generated file.
// Substrate
[pallet_alliance, Alliance]
[pallet_babe, Babe]
[pallet_bags_list, VoterList]
[pallet_balances, Balances]
@ -1077,7 +1078,7 @@ mod benches {
// Ghosts
[ghost_nomination_pools, NominationPoolsBench::<Runtime>]
[ghost_networks, GhostNetworks]
[ghost_claims, GhostClaims]
[ghost_governance, GhostGovernance]
[ghost_weaver, GhostWeaver]
[ghost_exodus, GhostExodus]
[ghost_sudo, GhostSudo]
@ -1537,11 +1538,11 @@ mod test_fees {
fn nominator_limit() {
use pallet_election_provider_multi_phase::WeightInfo;
// starting point of the nominators.
let target_voters: u32 = 50_000;
let target_voters: u32 = 3_000;
// assuming we want around 5k candidates and 1k active validators. (March 31, 2021)
let all_targets: u32 = 5_000;
let desired: u32 = 1_000;
// assuming we want around 3k candidates and 300 active validators.
let all_targets: u32 = 400;
let desired: u32 = 300;
let weight_with = |active| {
<Runtime as pallet_election_provider_multi_phase::Config>::WeightInfo::submit_unsigned(
active,

View File

@ -1,6 +1,6 @@
[package]
name = "runtime-common"
version = "0.4.5"
version = "0.4.7"
authors.workspace = true
edition.workspace = true
homepage.workspace = true

View File

@ -8,7 +8,7 @@ impl ArgumentsFactory<(), AccountId> for BenchmarkTreasuryHelper {
fn create_asset_kind(_seed: u32) -> () {
()
}
fn create_beneficiary(mut seed: [u8; 32]) -> AccountId {
fn create_beneficiary(seed: [u8; 32]) -> AccountId {
AccountId::from_entropy(&mut seed.as_slice()).unwrap()
}
}

View File

@ -30,19 +30,19 @@ pub use sp_runtime::BuildStorage;
pub use impls::ToAuthor;
/// We assume that an on-initialize consumes 30% of the weight on average, hence
/// We assume that an on-initialize consumes 10% of the weight on average, hence
/// a single extrinsic will not be allowed to consume more than
/// `AvailableBlockRatio - 30%`.
pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(30);
/// `AvailableBlockRatio - 10%`.
pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
/// We allow `Normal` extrinsics to fill up the block up to 60%, the rest can
/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can
/// be used by `Operational` extrinsics.
pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(60);
pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
/// We allow for 6 seconds of compute with a 12 seconds average block time.
/// We allow for 4 seconds of compute with a 12 seconds average block time.
/// The storage proof size is not limited so far.
pub const MAXIMUM_BLOCK_WEIGHT: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(6), u64::MAX);
Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(4), u64::MAX);
const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct());
@ -112,19 +112,19 @@ macro_rules! impl_runtime_weights {
.for_class(DispatchClass::all(), |weights| {
weights.base_extrinsic = $runtime::weights::ExtrinsicBaseWeight::get();
})
.for_class(DispatchClass::Normal, |weights| {
weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
})
.for_class(DispatchClass::Operational, |weights| {
weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
// Operational transactions have an extra reserved space, so that they
// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
weights.reserved = Some(
MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT,
);
})
.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
.build_or_panic();
.for_class(DispatchClass::Normal, |weights| {
weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
})
.for_class(DispatchClass::Operational, |weights| {
weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
// Operational transactions have an extra reserved space, so that they
// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
weights.reserved = Some(
MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT,
);
})
.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
.build_or_panic();
}
};
}
@ -138,8 +138,8 @@ static_assertions::assert_eq_size!(primitives::Balance, u128);
/// A reasonable benchmarking config for staking pallet.
pub struct StakingBenchmarkingConfig;
impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig {
type MaxValidators = ConstU32<500>;
type MaxNominators = ConstU32<10_000>;
type MaxValidators = ConstU32<299>; // MaxActiveValidators: u32 = 300
type MaxNominators = ConstU32<3_000>;
}
/// Convert a balance to an unsigned 256-bit number, use in nomination pools.
@ -173,7 +173,7 @@ macro_rules! prod_or_fast {
}
};
($prod:expr, $test:expr, $env:expr) => {
if cfg!(feature == "fast-runtime") {
if cfg!(feature = "fast-runtime") {
core::option_env!($env)
.map(|s| s.parse().ok())
.flatten()

View File

@ -1,27 +0,0 @@
use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_PER_TIME_PER_NANOS, Weight};
parameter_types! {
pub const BlockExecutionWeight: Weight =
Weight::from_ref_time(WEIGHT_PER_TIME_PER_NANOS.saturating_mul(7_955_558));
}
#[cfg(test)]
mod test_weights {
use sp_weights::constants;
#[test]
fn sane() {
let w = super::BlockExecutionWeight::get();
assert!(
w.ref_time() >= 100u64 * constants::WEIGHT_PER_TIME_PER_MICROS,
"Weight should be at least 100 µs."
);
assert!(
w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS,
"Weight should be at most 50 ms."
);
}
}

View File

@ -1,28 +0,0 @@
use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight};
parameter_types! {
pub const ExtrinsicBaseWeight: Weight =
Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(94_914));
}
#[cfg(test)]
mod test_weights {
use frame_support::traits::Get;
use sp_weights::constants;
#[test]
fn sane() {
let w = super::ExtrinsicBaseWeight::get();
assert!(
w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS,
"Weight should be at least 10 µs."
);
assert!(
w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS,
"Weight should be at most 1 ms."
);
}
}

View File

@ -1,5 +0,0 @@
pub mod block_weights;
pub mod extrinsic_weight;
pub use block_weights::BlockExecutionWeight;
pub use extrinsic_weights::ExtrinsicBaseWeight;

View File

@ -40,23 +40,23 @@ while getopts 'bfp:v' flag; do
esac
done
if [ "$skip_build" != true ]
then
echo "[+] Compiling Node with 'runtime-benchmarks' features"
cargo build --release --locked --features=runtime-benchmarks
fi
ERR_FILE="benchmarking_errors.txt"
EXECUTABLE=./target/release/ghost
RUNTIME="casper"
rm -f $ERR_FILE
if [ "$skip_build" != true ]
then
echo "[+] Compiling Node with 'runtime-benchmarks' features"
cargo build --release --locked --features=runtime-benchmarks,$RUNTIME-native
fi
# Update the block and extrinsic overhead weights
echo "[+] Benchmarking block and extrinsic overheads..."
OUTPUT=$(
$EXECUTABLE benchmark overhead \
--chain="${RUNTIME}-dev" \
--chain="${RUNTIME}-local" \
--wasm-execution=compiled \
--weight-path="./runtime/${RUNTIME}/constants/src/weights/" \
--header=./file_header.txt \
@ -70,7 +70,7 @@ fi
echo "[+] Benchmarking the machine..."
OUTPUT=$(
$EXECUTABLE benchmark machine --chain=${RUNTIME}-dev 2>&1
$EXECUTABLE benchmark machine --allow-fail --chain=${RUNTIME}-dev 2>&1
)
if [ $? -ne 0 ]; then
# Do not write the error file since it is not a benchmarking error
@ -108,23 +108,18 @@ fi
EXCLUDED_PALLETS=(
# helper pallets
"pallet_election_provider_support_benchmarking"
# pallets without automatic benchmarking
"pallet_babe"
"pallet_grandpa"
"pallet_bags_list"
"frame_system"
"pallet_staking"
"pallet_offences"
"frame_benchmarking"
)
# Load all pallet names in an array
ALL_PALLETS=($(
$EXECUTABLE benchmark pallet --list=pallets --no-csv-header --chain=${RUNTIME}-dev
$EXECUTABLE benchmark pallet --list=pallets --no-csv-header --chain=${RUNTIME}-dev 2>/dev/null | grep -v ':' | grep -v 'baseline'
))
# Filter out the excluded pallets by concatenating the arrays and discarding duplicates
PALLETS=($({ printf '%s\n' "${ALL_PALLETS[@]}" "${EXCLUDED_PALLETS[@]}"; } | sort | uniq -u))
PALLETS=($(
printf '%s\n' "${ALL_PALLETS[@]}" | grep -Fvxf <(printf '%s\n' "${EXCLUDED_PALLETS[@]}")
))
TOTAL_PALLETS=${#PALLETS[@]}
CURRENT=0
@ -142,6 +137,11 @@ for PALLET in "${PALLETS[@]}"; do
unset start_pallet
fi
if [[ -z "$PALLET" || "$PALLET" == "::" || "$PALLET" == "baseline" || "$PALLET" == "pallet" ]]; then
echo "[+] ($CURRENT/$TOTAL_PALLETS) Skipping garbage names: '${PALLET}'"
continue
fi
FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')";
WEIGHT_FILE="./runtime/${RUNTIME}/src/weights/${PALLET}.rs"
echo "[+] Benchmarking $PALLET for $RUNTIME with weight file $WEIGHT_FILE ($CURRENT/$TOTAL_PALLETS)";

View File

@ -106,7 +106,7 @@ tempfile = { workspace = true }
[features]
default = ["db", "full-node"]
db = ["sc-service/rocksdb"]
full-node = ["kvdb-rocksdb", "parity-db"]
full-node = ["kvdb-rocksdb", "parity-db", "casper-native"]
runtime-benchmarks = [
"frame-benchmarking-cli/runtime-benchmarks",
"frame-benchmarking/runtime-benchmarks",