Skip to content

Commit 534b43d

Browse files
gabriele-0201rphmeier
authored andcommitted
fees: add MaximumSkippedBlocks constant
Limit the number of skipped blocks in the fee update mechanism to the expected maximum. This is done to avoid the possibility of incorrectly updating the fee multiplier. For example, if the chain halts and skips more than 10000 blocks, the approximation given by the first n terms of e^x could diverge significantly from the actual value. Therefore, we set a boundary on the number of skipped blocks to ensure the accuracy of the approximation
1 parent cdf6a22 commit 534b43d

File tree

7 files changed

+60
-12
lines changed

7 files changed

+60
-12
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sugondat/chain/pallets/length-fee-adjustment/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ polkadot-primitives = { workspace = true }
2929
[dev-dependencies]
3030
sp-io = { workspace = true }
3131
sp-core = { workspace = true }
32+
sugondat-primitives = { workspace = true, features = ["std"] }
3233

3334
[features]
3435
default = [ "std" ]
@@ -53,4 +54,4 @@ runtime-benchmarks = [
5354
"sp-runtime/runtime-benchmarks",
5455
"dep:sp-io"
5556
]
56-
try-runtime = [ "frame-support/try-runtime" ]
57+
try-runtime = [ "frame-support/try-runtime" ]

sugondat/chain/pallets/length-fee-adjustment/src/lib.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,18 @@ pub mod pallet {
9999
///
100100
/// Here, m represents the number of terms needed to be below the error.
101101
/// The smallest value of m that satisfies the inequality should be used as the value for this parameter.
102-
///
103-
/// The maximum number of skipped blocks is used to ensure that only the right amount of terms is used,
104-
/// and no terms are wasted. If n is exceeded, the approximation could diverge significantly from the actual value of e^x.
105-
/// This means that producing a block at most every n skipped blocks should be enforced to avoid falling into this error.
106102
#[pallet::constant]
107103
type SkippedBlocksNumberTerms: Get<u32>;
108104

105+
/// The maximum number of skipped blocks is used to ensure that only the right amount of terms is used
106+
/// and no terms are wasted. If n is exceeded, the approximation could diverge significantly from the actual value of e^x.
107+
/// If the number of skipped blocks exceeds this value, it will be bounded to this value.
108+
/// However, this limitation comes at the cost of losing the real fee adjustment update.
109+
/// Therefore, producing a block at most every n skipped blocks should be enforced to avoid falling into this circumstance.
110+
#[pallet::constant]
111+
type MaximumSkippedBlocks: Get<u32>;
112+
113+
/// A source to provide the relay-parent number of the previous block.
109114
type LastRelayBlockNumberProvider: LastRelayBlockNumberProvider;
110115
}
111116

@@ -243,10 +248,11 @@ pub mod pallet {
243248
// However, saturating it to zero will prevent the multiplier from changing
244249
let relay_parent_distance = relay_block_number.saturating_sub(prev_relay_block_number);
245250

246-
// TODO: update with `n_skipped_blocks = relay_parent_distance.saturating_sub(1)`
251+
// TODO: update with `relay_parent_distance.saturating_sub(1)`
247252
// when updating to asynchronous backing
248253
// https://github.com/thrumdev/blobs/issues/166
249-
let n_skipped_blocks = relay_parent_distance.saturating_sub(2) / 2;
254+
let n_skipped_blocks =
255+
(relay_parent_distance.saturating_sub(2) / 2).min(T::MaximumSkippedBlocks::get());
250256

251257
let n_skipped_blocks = Multiplier::saturating_from_integer(n_skipped_blocks);
252258
let target_block_size = Multiplier::from(TargetBlockSize::<T>::get());

sugondat/chain/pallets/length-fee-adjustment/src/mock.rs

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ parameter_types! {
8787
// https://github.com/thrumdev/blobs/issues/166
8888
// Accepted error is less than 10^(-2)
8989
pub SkippedBlocksNumberTerms: u32 = 3;
90+
pub MaximumSkippedBlocks: u32 = sugondat_primitives::MAX_SKIPPED_BLOCKS;
9091

9192
pub static WeightToFee: u64 = 1;
9293
pub static OperationalFeeMultiplier: u8 = 5;
@@ -130,5 +131,6 @@ impl pallet_sugondat_length_fee_adjustment::Config for Test {
130131
type MinimumMultiplierBlockSize = MinimumMultiplierBlockSize;
131132
type MaximumMultiplierBlockSize = MaximumMultiplierBlockSize;
132133
type SkippedBlocksNumberTerms = SkippedBlocksNumberTerms;
134+
type MaximumSkippedBlocks = MaximumSkippedBlocks;
133135
type LastRelayBlockNumberProvider = MockLastRelayBlockNumberProvider;
134136
}

sugondat/chain/pallets/length-fee-adjustment/src/tests.rs

+35-5
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,9 @@ fn test_no_update_when_prev_is_zero() {
8989

9090
#[test]
9191
fn test_skipped_block_multiplier_update() {
92-
// TODO: change max_skipped_blocks to 7200
93-
// when updating to asynchronous backing
94-
// https://github.com/thrumdev/blobs/issues/166
9592
new_test_ext().execute_with(|| {
96-
let max_skipped_blocks = 3600;
97-
for d in (0..max_skipped_blocks).step_by(max_skipped_blocks as usize / 1000) {
93+
let max_skipped_blocks = <Test as Config>::MaximumSkippedBlocks::get();
94+
for d in (0..max_skipped_blocks).step_by(max_skipped_blocks as usize / 100) {
9895
// using Multiplier::one() only e^(-vnt) is tested
9996
NextLengthMultiplier::<Test>::put(Multiplier::one());
10097
mock::set_last_relay_block_number(1);
@@ -124,6 +121,39 @@ fn test_skipped_block_multiplier_update() {
124121
});
125122
}
126123

124+
#[test]
125+
fn test_max_skipped_block_exceeded() {
126+
new_test_ext().execute_with(|| {
127+
NextLengthMultiplier::<Test>::put(Multiplier::one());
128+
mock::set_last_relay_block_number(1);
129+
130+
let max_skipped_blocks = <Test as Config>::MaximumSkippedBlocks::get();
131+
let relay_data = PersistedValidationData {
132+
parent_head: HeadData(vec![]),
133+
// The previous relay parent was 10 times greater than the expected MaximumSkippedBlocks.
134+
// If the multiplier is updated with that number of skipped blocks
135+
// there's should be a significant divergence in the final result.
136+
// However, we expect it to be bounded by max_skipped_blocks.
137+
relay_parent_number: 1 + 2 + ((max_skipped_blocks * 10) * 2),
138+
relay_parent_storage_root: sp_core::H256::zero(),
139+
max_pov_size: 0,
140+
};
141+
142+
LengthFeeAdjustment::on_validation_data(&relay_data);
143+
144+
let mul = NextLengthMultiplier::<Test>::get();
145+
146+
// calculate expected result using f64::exp and assert on the error rate
147+
let target = Multiplier::from(TargetBlockSize::<Test>::get()).to_float();
148+
let v = <Test as Config>::AdjustmentVariableBlockSize::get().to_float();
149+
let expected_mul =
150+
Multiplier::from_float((-1.0 * target * v * max_skipped_blocks as f64).exp());
151+
152+
//Accepted error is less than 10^(-2)
153+
assert_eq_error_rate!(mul, expected_mul, Multiplier::from_inner(10000000000000000));
154+
});
155+
}
156+
127157
#[test]
128158
fn test_skipped_block_no_prev_data() {
129159
new_test_ext().execute_with(|| {

sugondat/chain/runtimes/sugondat-kusama/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ parameter_types! {
303303
// The accepted error is less than 10^(-2) for an expected
304304
// maximum of 3600 skipped blocks (half a day)
305305
pub SkippedBlocksNumberTerms: u32 = 3;
306+
307+
// Maximum acceptable number of skipped parachain blocks.
308+
pub MaximumSkippedBlocks: u32 = sugondat_primitives::MAX_SKIPPED_BLOCKS;
306309
}
307310

308311
impl pallet_sugondat_length_fee_adjustment::Config for Runtime {
@@ -312,6 +315,7 @@ impl pallet_sugondat_length_fee_adjustment::Config for Runtime {
312315
type MaximumMultiplierBlockSize = MaximumMultiplierBlockSize;
313316
type MinimumMultiplierBlockSize = MinimumMultiplierBlockSize;
314317
type SkippedBlocksNumberTerms = SkippedBlocksNumberTerms;
318+
type MaximumSkippedBlocks = MaximumSkippedBlocks;
315319
type LastRelayBlockNumberProvider = Runtime;
316320
}
317321

sugondat/chain/runtimes/test/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,9 @@ parameter_types! {
370370
// The accepted error is less than 10^(-2) for an expected
371371
// maximum of 3600 skipped blocks (half a day)
372372
pub SkippedBlocksNumberTerms: u32 = 3;
373+
374+
// Maximum acceptable number of skipped parachain blocks.
375+
pub MaximumSkippedBlocks: u32 = sugondat_primitives::MAX_SKIPPED_BLOCKS;
373376
}
374377

375378
impl pallet_sugondat_length_fee_adjustment::Config for Runtime {
@@ -379,6 +382,7 @@ impl pallet_sugondat_length_fee_adjustment::Config for Runtime {
379382
type MaximumMultiplierBlockSize = MaximumMultiplierBlockSize;
380383
type MinimumMultiplierBlockSize = MinimumMultiplierBlockSize;
381384
type SkippedBlocksNumberTerms = SkippedBlocksNumberTerms;
385+
type MaximumSkippedBlocks = MaximumSkippedBlocks;
382386
type LastRelayBlockNumberProvider = Runtime;
383387
}
384388

0 commit comments

Comments
 (0)