Skip to content

Commit

Permalink
limit the maximum extrinsic weight to max domain bundle weight with b…
Browse files Browse the repository at this point in the history
…undle slot propability to be 1
  • Loading branch information
vedhavyas committed May 30, 2024
1 parent cee3bd6 commit a533a6f
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 49 deletions.
33 changes: 3 additions & 30 deletions crates/pallet-domains/src/domain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ use frame_system::pallet_prelude::*;
use scale_info::TypeInfo;
use sp_core::Get;
use sp_domains::{
derive_domain_block_hash, DomainBundleLimit, DomainId, DomainsDigestItem,
DomainsTransfersTracker, OnDomainInstantiated, OperatorAllowList, RuntimeId, RuntimeType,
calculate_max_bundle_weight_and_size, derive_domain_block_hash, DomainBundleLimit, DomainId,
DomainsDigestItem, DomainsTransfersTracker, OnDomainInstantiated, OperatorAllowList, RuntimeId,
RuntimeType,
};
use sp_runtime::traits::{CheckedAdd, Zero};
use sp_runtime::DigestItem;
Expand Down Expand Up @@ -317,34 +318,6 @@ pub(crate) fn do_update_domain_allow_list<T: Config>(
})
}

// See https://forum.subspace.network/t/on-bundle-weight-limits-sum/2277 for more details
// about the formula
pub(crate) fn calculate_max_bundle_weight_and_size(
max_domain_block_size: u32,
max_domain_block_weight: Weight,
consensus_slot_probability: (u64, u64),
bundle_slot_probability: (u64, u64),
) -> Option<DomainBundleLimit> {
// (n1 / d1) / (n2 / d2) is equal to (n1 * d2) / (d1 * n2)
// This represents: bundle_slot_probability/SLOT_PROBABILITY
let expected_bundles_per_block = bundle_slot_probability
.0
.checked_mul(consensus_slot_probability.1)?
.checked_div(
bundle_slot_probability
.1
.checked_mul(consensus_slot_probability.0)?,
)?;

let max_bundle_weight = max_domain_block_weight.checked_div(expected_bundles_per_block)?;
let max_bundle_size = (max_domain_block_size as u64).checked_div(expected_bundles_per_block)?;

Some(DomainBundleLimit {
max_bundle_size: max_bundle_size as u32,
max_bundle_weight,
})
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
24 changes: 23 additions & 1 deletion crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use bundle_producer_election::{BundleProducerElectionParams, ProofOfElectionErro
use core::num::ParseIntError;
use core::ops::{Add, Sub};
use core::str::FromStr;
use domain_runtime_primitives::MultiAccountId;
use domain_runtime_primitives::{calculate_max_bundle_weight, MultiAccountId};
use frame_support::storage::storage_prefix;
use frame_support::{Blake2_128Concat, StorageHasher};
use hexlit::hex;
Expand Down Expand Up @@ -1032,6 +1032,28 @@ pub struct DomainBundleLimit {
pub max_bundle_weight: Weight,
}

/// Calculates the max bundle weight and size
// See https://forum.subspace.network/t/on-bundle-weight-limits-sum/2277 for more details
// about the formula
pub fn calculate_max_bundle_weight_and_size(
max_domain_block_size: u32,
max_domain_block_weight: Weight,
consensus_slot_probability: (u64, u64),
bundle_slot_probability: (u64, u64),
) -> Option<DomainBundleLimit> {
let (expected_bundles_per_block, max_bundle_weight) = calculate_max_bundle_weight(
max_domain_block_weight,
consensus_slot_probability,
bundle_slot_probability,
)?;
let max_bundle_size = (max_domain_block_size as u64).checked_div(expected_bundles_per_block)?;

Some(DomainBundleLimit {
max_bundle_size: max_bundle_size as u32,
max_bundle_weight,
})
}

/// Checks if the signer Id hash is within the tx range
pub fn signer_in_tx_range(bundle_vrf_hash: &U256, signer_id_hash: &U256, tx_range: &U256) -> bool {
let distance_from_vrf_hash = bidirectional_distance(bundle_vrf_hash, signer_id_hash);
Expand Down
12 changes: 11 additions & 1 deletion crates/subspace-runtime-primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use codec::{Codec, Decode, Encode};
use frame_support::pallet_prelude::Weight;
use frame_support::traits::tokens;
use frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND;
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
use scale_info::TypeInfo;
use sp_core::parameter_types;
use sp_runtime::traits::{Bounded, IdentifyAccount, Verify};
use sp_runtime::{FixedPointNumber, MultiSignature, Perquintill};
use sp_runtime::{FixedPointNumber, MultiSignature, Perbill, Perquintill};
pub use subspace_core_primitives::BlockNumber;

/// Minimum desired number of replicas of the blockchain to be stored by the network,
Expand All @@ -42,6 +44,14 @@ pub const SHANNON: Balance = 1;
pub const DECIMAL_PLACES: u8 = 18;
/// One Subspace Credit.
pub const SSC: Balance = (10 * SHANNON).pow(DECIMAL_PLACES as u32);
/// A ratio of `Normal` dispatch class within block, for `BlockWeight` and `BlockLength`.
pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
/// 1 in 6 slots (on average, not counting collisions) will have a block.
/// Must match ratio between block and slot duration in constants above.
pub const SLOT_PROBABILITY: (u64, u64) = (1, 6);
/// The block weight for 2 seconds of compute
pub const BLOCK_WEIGHT_FOR_2_SEC: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);

/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;
Expand Down
23 changes: 7 additions & 16 deletions crates/subspace-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ use codec::{Decode, Encode, MaxEncodedLen};
use core::num::NonZeroU64;
use domain_runtime_primitives::opaque::Header as DomainHeader;
use domain_runtime_primitives::{
AccountIdConverter, BlockNumber as DomainNumber, Hash as DomainHash,
maximum_domain_block_weight, AccountIdConverter, BlockNumber as DomainNumber,
Hash as DomainHash,
};
use frame_support::genesis_builder_helper::{build_config, create_default_config};
use frame_support::inherent::ProvideInherent;
use frame_support::traits::{
ConstU16, ConstU32, ConstU64, ConstU8, Currency, Everything, Get, OnRuntimeUpgrade,
VariantCount,
};
use frame_support::weights::constants::{ParityDbWeight, WEIGHT_REF_TIME_PER_SECOND};
use frame_support::weights::constants::ParityDbWeight;
use frame_support::weights::{ConstantMultiplier, IdentityFee, Weight};
use frame_support::{construct_runtime, parameter_types, PalletId};
use frame_system::limits::{BlockLength, BlockWeights};
Expand Down Expand Up @@ -82,7 +83,7 @@ use sp_runtime::traits::{
};
use sp_runtime::transaction_validity::{TransactionSource, TransactionValidity};
use sp_runtime::{
create_runtime_str, generic, AccountId32, ApplyExtrinsicResult, ExtrinsicInclusionMode, Perbill,
create_runtime_str, generic, AccountId32, ApplyExtrinsicResult, ExtrinsicInclusionMode,
};
use sp_std::collections::btree_map::BTreeMap;
use sp_std::marker::PhantomData;
Expand All @@ -98,7 +99,8 @@ use subspace_core_primitives::{
};
use subspace_runtime_primitives::{
AccountId, Balance, BlockNumber, FindBlockRewardAddress, Hash, Moment, Nonce, Signature,
SlowAdjustingFeeUpdate, MIN_REPLICATION_FACTOR, SHANNON, SSC,
SlowAdjustingFeeUpdate, BLOCK_WEIGHT_FOR_2_SEC, MIN_REPLICATION_FACTOR, NORMAL_DISPATCH_RATIO,
SHANNON, SLOT_PROBABILITY, SSC,
};

sp_runtime::impl_opaque_keys! {
Expand Down Expand Up @@ -146,10 +148,6 @@ pub const MILLISECS_PER_BLOCK: u64 = 6000;
// Attempting to do so will brick block production.
const SLOT_DURATION: u64 = 1000;

/// 1 in 6 slots (on average, not counting collisions) will have a block.
/// Must match ratio between block and slot duration in constants above.
const SLOT_PROBABILITY: (u64, u64) = (1, 6);

/// Number of slots between slot arrival and when corresponding block can be produced.
const BLOCK_AUTHORING_DELAY: SlotNumber = 4;

Expand Down Expand Up @@ -198,13 +196,6 @@ const RECENT_HISTORY_FRACTION: (HistorySize, HistorySize) = (
const MIN_SECTOR_LIFETIME: HistorySize =
HistorySize::new(NonZeroU64::new(4).expect("Not zero; qed"));

/// The block weight for 2 seconds of compute
const BLOCK_WEIGHT_FOR_2_SEC: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);

/// A ratio of `Normal` dispatch class within block, for `BlockWeight` and `BlockLength`.
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);

/// Maximum block length for non-`Normal` extrinsic is 5 MiB.
const MAX_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;

Expand Down Expand Up @@ -587,7 +578,7 @@ parameter_types! {
/// Use the consensus chain's `Normal` extrinsics block size limit as the domain block size limit
pub MaxDomainBlockSize: u32 = NORMAL_DISPATCH_RATIO * MAX_BLOCK_LENGTH;
/// Use the consensus chain's `Normal` extrinsics block weight limit as the domain block weight limit
pub MaxDomainBlockWeight: Weight = NORMAL_DISPATCH_RATIO * BLOCK_WEIGHT_FOR_2_SEC;
pub MaxDomainBlockWeight: Weight = maximum_domain_block_weight();
pub const MaxBundlesPerBlock: u32 = 10;
pub const DomainInstantiationDeposit: Balance = 100 * SSC;
pub const MaxDomainNameLength: u32 = 32;
Expand Down
49 changes: 48 additions & 1 deletion domains/primitives/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ use sp_runtime::traits::{Convert, IdentifyAccount, Verify};
use sp_runtime::transaction_validity::TransactionValidityError;
use sp_runtime::{MultiAddress, MultiSignature, Perbill};
use sp_weights::Weight;
use subspace_runtime_primitives::SHANNON;
use subspace_runtime_primitives::{
BLOCK_WEIGHT_FOR_2_SEC, NORMAL_DISPATCH_RATIO, SHANNON, SLOT_PROBABILITY,
};

/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;
Expand Down Expand Up @@ -66,6 +68,11 @@ pub const SLOT_DURATION: u64 = 1000;
/// The EVM chain Id type
pub type EVMChainId = u64;

/// The maximum domain block weight.
pub fn maximum_domain_block_weight() -> Weight {
NORMAL_DISPATCH_RATIO * BLOCK_WEIGHT_FOR_2_SEC
}

/// Maximum block length for mandatory dispatch.
pub const MAXIMUM_MANDATORY_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;

Expand Down Expand Up @@ -99,17 +106,57 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5);
/// Maximum total block weight.
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(u64::MAX, u64::MAX);

/// Calculates the max bundle weight
// See https://forum.subspace.network/t/on-bundle-weight-limits-sum/2277 for more details
// about the formula
pub fn calculate_max_bundle_weight(
max_domain_block_weight: Weight,
consensus_slot_probability: (u64, u64),
bundle_slot_probability: (u64, u64),
) -> Option<(u64, Weight)> {
// (n1 / d1) / (n2 / d2) is equal to (n1 * d2) / (d1 * n2)
// This represents: bundle_slot_probability/SLOT_PROBABILITY
let expected_bundles_per_block = bundle_slot_probability
.0
.checked_mul(consensus_slot_probability.1)?
.checked_div(
bundle_slot_probability
.1
.checked_mul(consensus_slot_probability.0)?,
)?;

let max_bundle_weight = max_domain_block_weight.checked_div(expected_bundles_per_block)?;
Some((expected_bundles_per_block, max_bundle_weight))
}

/// Calculates the maximum extrinsic weight for domains.
/// We take bundle slot probability to be always at the maximum i.e 1 such that
/// operator can produce bundle in each slot
fn maximum_domain_extrinsic_weight() -> Option<Weight> {
let (_, max_bundle_weight) =
calculate_max_bundle_weight(maximum_domain_block_weight(), SLOT_PROBABILITY, (1, 1))?;
Some(max_bundle_weight)
}

pub fn block_weights() -> BlockWeights {
let max_extrinsic_weight =
maximum_domain_extrinsic_weight().expect("Maximum extrinsic weight must always be valid");
BlockWeights::builder()
.base_block(BlockExecutionWeight::get())
.for_class(DispatchClass::all(), |weights| {
weights.base_extrinsic = ExtrinsicBaseWeight::get();
})
.for_class(DispatchClass::Normal, |weights| {
// maximum weight of each transaction would be the maximum weight of
// single bundle
weights.max_extrinsic = Some(max_extrinsic_weight);
// explicitly set max_total weight for normal dispatches to maximum
weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
})
.for_class(DispatchClass::Operational, |weights| {
// maximum weight of each transaction would be the maximum weight of
// single bundle
weights.max_extrinsic = Some(max_extrinsic_weight);
// explicitly set max_total weight for operational dispatches to maximum
weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
})
Expand Down

0 comments on commit a533a6f

Please sign in to comment.