diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs
index 05531f47c6e052dbe8114b6c23d1956edfc4e434..8c4a1ed4bbda2a16b44bd8662896e4a2cc6f3fce 100644
--- a/substrate/bin/node/runtime/src/impls.rs
+++ b/substrate/bin/node/runtime/src/impls.rs
@@ -17,10 +17,6 @@
 
 //! Some configurable implementations as associated type for the substrate runtime.
 
-use crate::{
-	AccountId, AllianceMotion, Assets, Authorship, Balances, Hash, NegativeImbalance, Runtime,
-	RuntimeCall,
-};
 use frame_support::{
 	pallet_prelude::*,
 	traits::{
@@ -32,6 +28,11 @@ use pallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider};
 use pallet_asset_tx_payment::HandleCredit;
 use sp_std::prelude::*;
 
+use crate::{
+	AccountId, AllianceMotion, Assets, Authorship, Balances, Hash, NegativeImbalance, Runtime,
+	RuntimeCall,
+};
+
 pub struct Author;
 impl OnUnbalanced<NegativeImbalance> for Author {
 	fn on_nonzero_unbalanced(amount: NegativeImbalance) {
@@ -111,6 +112,10 @@ impl ProposalProvider<AccountId, Hash, RuntimeCall> for AllianceProposalProvider
 
 #[cfg(test)]
 mod multiplier_tests {
+	use frame_support::{
+		dispatch::DispatchClass,
+		weights::{Weight, WeightToFee},
+	};
 	use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
 	use sp_runtime::{
 		assert_eq_error_rate,
@@ -123,10 +128,6 @@ mod multiplier_tests {
 		AdjustmentVariable, MaximumMultiplier, MinimumMultiplier, Runtime,
 		RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment,
 	};
-	use frame_support::{
-		dispatch::DispatchClass,
-		weights::{Weight, WeightToFee},
-	};
 
 	fn max_normal() -> Weight {
 		BlockWeights::get()
@@ -161,14 +162,28 @@ mod multiplier_tests {
 		// bump if it is zero.
 		let previous_float = previous_float.max(min_multiplier().into_inner() as f64 / accuracy);
 
+		let max_normal = max_normal();
+		let target_weight = target();
+		let normalized_weight_dimensions = (
+			block_weight.ref_time() as f64 / max_normal.ref_time() as f64,
+			block_weight.proof_size() as f64 / max_normal.proof_size() as f64,
+		);
+
+		let (normal, max, target) =
+			if normalized_weight_dimensions.0 < normalized_weight_dimensions.1 {
+				(block_weight.proof_size(), max_normal.proof_size(), target_weight.proof_size())
+			} else {
+				(block_weight.ref_time(), max_normal.ref_time(), target_weight.ref_time())
+			};
+
 		// maximum tx weight
-		let m = max_normal().ref_time() as f64;
+		let m = max as f64;
 		// block weight always truncated to max weight
-		let block_weight = (block_weight.ref_time() as f64).min(m);
+		let block_weight = (normal as f64).min(m);
 		let v: f64 = AdjustmentVariable::get().to_float();
 
 		// Ideal saturation in terms of weight
-		let ss = target().ref_time() as f64;
+		let ss = target as f64;
 		// Current saturation in terms of weight
 		let s = block_weight;
 
@@ -218,10 +233,16 @@ mod multiplier_tests {
 	#[test]
 	fn multiplier_can_grow_from_zero() {
 		// if the min is too small, then this will not change, and we are doomed forever.
-		// the weight is 1/100th bigger than target.
+		// the block ref time is 1/100th bigger than target.
 		run_with_system_weight(target().set_ref_time(target().ref_time() * 101 / 100), || {
 			let next = runtime_multiplier_update(min_multiplier());
-			assert!(next > min_multiplier(), "{:?} !>= {:?}", next, min_multiplier());
+			assert!(next > min_multiplier(), "{:?} !> {:?}", next, min_multiplier());
+		});
+
+		// the block proof size is 1/100th bigger than target.
+		run_with_system_weight(target().set_proof_size((target().proof_size() / 100) * 101), || {
+			let next = runtime_multiplier_update(min_multiplier());
+			assert!(next > min_multiplier(), "{:?} !> {:?}", next, min_multiplier());
 		})
 	}
 
@@ -407,23 +428,33 @@ mod multiplier_tests {
 
 	#[test]
 	fn weight_to_fee_should_not_overflow_on_large_weights() {
-		let kb = Weight::from_parts(1024, 0);
-		let mb = 1024u64 * kb;
+		let kb_time = Weight::from_parts(1024, 0);
+		let kb_size = Weight::from_parts(0, 1024);
+		let mb_time = 1024u64 * kb_time;
 		let max_fm = Multiplier::saturating_from_integer(i128::MAX);
 
 		// check that for all values it can compute, correctly.
 		vec![
 			Weight::zero(),
+			// testcases ignoring proof size part of the weight.
 			Weight::from_parts(1, 0),
 			Weight::from_parts(10, 0),
 			Weight::from_parts(1000, 0),
-			kb,
-			10u64 * kb,
-			100u64 * kb,
-			mb,
-			10u64 * mb,
+			kb_time,
+			10u64 * kb_time,
+			100u64 * kb_time,
+			mb_time,
+			10u64 * mb_time,
 			Weight::from_parts(2147483647, 0),
 			Weight::from_parts(4294967295, 0),
+			// testcases ignoring ref time part of the weight.
+			Weight::from_parts(0, 100000000000),
+			1000000u64 * kb_size,
+			1000000000u64 * kb_size,
+			Weight::from_parts(0, 18014398509481983),
+			Weight::from_parts(0, 9223372036854775807),
+			// test cases with both parts of the weight.
+			BlockWeights::get().max_block / 1024,
 			BlockWeights::get().max_block / 2,
 			BlockWeights::get().max_block,
 			Weight::MAX / 2,
@@ -440,7 +471,14 @@ mod multiplier_tests {
 
 		// Some values that are all above the target and will cause an increase.
 		let t = target();
-		vec![t + Weight::from_parts(100, 0), t * 2, t * 4].into_iter().for_each(|i| {
+		vec![
+			t + Weight::from_parts(100, 0),
+			t + Weight::from_parts(0, t.proof_size() * 2),
+			t * 2,
+			t * 4,
+		]
+		.into_iter()
+		.for_each(|i| {
 			run_with_system_weight(i, || {
 				let fm = runtime_multiplier_update(max_fm);
 				// won't grow. The convert saturates everything.
diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs
index f7bdc23a0b3f004d035d8dde52145b1ae099c682..1ea2dc9f33ebbe79df4cacde1081f36add6d1f63 100644
--- a/substrate/frame/transaction-payment/src/lib.rs
+++ b/substrate/frame/transaction-payment/src/lib.rs
@@ -50,6 +50,15 @@
 use codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
 
+use frame_support::{
+	dispatch::{
+		DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo,
+	},
+	traits::{Defensive, EstimateCallFee, Get},
+	weights::{Weight, WeightToFee},
+};
+pub use pallet::*;
+pub use payment::*;
 use sp_runtime::{
 	traits::{
 		Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion,
@@ -58,17 +67,10 @@ use sp_runtime::{
 	transaction_validity::{
 		TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction,
 	},
-	FixedPointNumber, FixedPointOperand, FixedU128, Perquintill, RuntimeDebug,
+	FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Perquintill, RuntimeDebug,
 };
 use sp_std::prelude::*;
-
-use frame_support::{
-	dispatch::{
-		DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo,
-	},
-	traits::{EstimateCallFee, Get},
-	weights::{Weight, WeightToFee},
-};
+pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo};
 
 #[cfg(test)]
 mod mock;
@@ -78,10 +80,6 @@ mod tests;
 mod payment;
 mod types;
 
-pub use pallet::*;
-pub use payment::*;
-pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo};
-
 /// Fee multiplier.
 pub type Multiplier = FixedU128;
 
@@ -108,10 +106,17 @@ type BalanceOf<T> = <<T as Config>::OnChargeTransaction as OnChargeTransaction<T
 /// with tests that the combination of this `M` and `V` is not such that the multiplier can drop to
 /// zero and never recover.
 ///
-/// note that `s'` is interpreted as a portion in the _normal transaction_ capacity of the block.
+/// Note that `s'` is interpreted as a portion in the _normal transaction_ capacity of the block.
 /// For example, given `s' == 0.25` and `AvailableBlockRatio = 0.75`, then the target fullness is
 /// _0.25 of the normal capacity_ and _0.1875 of the entire block_.
 ///
+/// Since block weight is multi-dimension, we use the scarcer resource, referred as limiting
+/// dimension, for calculation of fees. We determine the limiting dimension by comparing the
+/// dimensions using the ratio of `dimension_value / max_dimension_value` and selecting the largest
+/// ratio. For instance, if a block is 30% full based on `ref_time` and 25% full based on
+/// `proof_size`, we identify `ref_time` as the limiting dimension, indicating that the block is 30%
+/// full.
+///
 /// This implementation implies the bound:
 /// - `v ≤ p / k * (s − s')`
 /// - or, solving for `p`: `p >= v * k * (s - s')`
@@ -207,15 +212,30 @@ where
 		let normal_block_weight =
 			current_block_weight.get(DispatchClass::Normal).min(normal_max_weight);
 
-		// TODO: Handle all weight dimensions
-		let normal_max_weight = normal_max_weight.ref_time();
-		let normal_block_weight = normal_block_weight.ref_time();
-
-		let s = S::get();
-		let v = V::get();
-
-		let target_weight = (s * normal_max_weight) as u128;
-		let block_weight = normal_block_weight as u128;
+		// Normalize dimensions so they can be compared. Ensure (defensive) max weight is non-zero.
+		let normalized_ref_time = Perbill::from_rational(
+			normal_block_weight.ref_time(),
+			normal_max_weight.ref_time().max(1),
+		);
+		let normalized_proof_size = Perbill::from_rational(
+			normal_block_weight.proof_size(),
+			normal_max_weight.proof_size().max(1),
+		);
+
+		// Pick the limiting dimension. If the proof size is the limiting dimension, then the
+		// multiplier is adjusted by the proof size. Otherwise, it is adjusted by the ref time.
+		let (normal_limiting_dimension, max_limiting_dimension) =
+			if normalized_ref_time < normalized_proof_size {
+				(normal_block_weight.proof_size(), normal_max_weight.proof_size())
+			} else {
+				(normal_block_weight.ref_time(), normal_max_weight.ref_time())
+			};
+
+		let target_block_fullness = S::get();
+		let adjustment_variable = V::get();
+
+		let target_weight = (target_block_fullness * max_limiting_dimension) as u128;
+		let block_weight = normal_limiting_dimension as u128;
 
 		// determines if the first_term is positive
 		let positive = block_weight >= target_weight;
@@ -223,12 +243,13 @@ where
 
 		// defensive only, a test case assures that the maximum weight diff can fit in Multiplier
 		// without any saturation.
-		let diff = Multiplier::saturating_from_rational(diff_abs, normal_max_weight.max(1));
+		let diff = Multiplier::saturating_from_rational(diff_abs, max_limiting_dimension.max(1));
 		let diff_squared = diff.saturating_mul(diff);
 
-		let v_squared_2 = v.saturating_mul(v) / Multiplier::saturating_from_integer(2);
+		let v_squared_2 = adjustment_variable.saturating_mul(adjustment_variable) /
+			Multiplier::saturating_from_integer(2);
 
-		let first_term = v.saturating_mul(diff);
+		let first_term = adjustment_variable.saturating_mul(diff);
 		let second_term = v_squared_2.saturating_mul(diff_squared);
 
 		if positive {
@@ -290,10 +311,11 @@ const MULTIPLIER_DEFAULT_VALUE: Multiplier = Multiplier::from_u32(1);
 
 #[frame_support::pallet]
 pub mod pallet {
-	use super::*;
 	use frame_support::pallet_prelude::*;
 	use frame_system::pallet_prelude::*;
 
+	use super::*;
+
 	#[pallet::pallet]
 	pub struct Pallet<T>(_);
 
@@ -710,19 +732,20 @@ where
 		tip: BalanceOf<T>,
 		final_fee: BalanceOf<T>,
 	) -> TransactionPriority {
-		// Calculate how many such extrinsics we could fit into an empty block and take
-		// the limitting factor.
+		// Calculate how many such extrinsics we could fit into an empty block and take the
+		// limiting factor.
 		let max_block_weight = T::BlockWeights::get().max_block;
 		let max_block_length = *T::BlockLength::get().max.get(info.class) as u64;
 
-		// TODO: Take into account all dimensions of weight
-		let max_block_weight = max_block_weight.ref_time();
-		let info_weight = info.weight.ref_time();
-
-		let bounded_weight = info_weight.clamp(1, max_block_weight);
+		// bounded_weight is used as a divisor later so we keep it non-zero.
+		let bounded_weight = info.weight.max(Weight::from_parts(1, 1)).min(max_block_weight);
 		let bounded_length = (len as u64).clamp(1, max_block_length);
 
-		let max_tx_per_block_weight = max_block_weight / bounded_weight;
+		// returns the scarce resource, i.e. the one that is limiting the number of transactions.
+		let max_tx_per_block_weight = max_block_weight
+			.checked_div_per_component(&bounded_weight)
+			.defensive_proof("bounded_weight is non-zero; qed")
+			.unwrap_or(1);
 		let max_tx_per_block_length = max_block_length / bounded_length;
 		// Given our current knowledge this value is going to be in a reasonable range - i.e.
 		// less than 10^9 (2^30), so multiplying by the `tip` value is unlikely to overflow the