@@ -12,14 +12,18 @@ pub mod xcm_config;
12
12
13
13
use cumulus_pallet_parachain_system:: RelayNumberStrictlyIncreases ;
14
14
use cumulus_primitives_core:: { AggregateMessageOrigin , ParaId } ;
15
+ use pallet_transaction_payment:: { Multiplier , MultiplierUpdate } ;
15
16
use polkadot_runtime_common:: xcm_sender:: NoPriceForMessageDelivery ;
16
17
use sp_api:: impl_runtime_apis;
17
18
use sp_core:: { crypto:: KeyTypeId , OpaqueMetadata } ;
18
19
use sp_runtime:: {
19
20
create_runtime_str, generic, impl_opaque_keys,
20
- traits:: { AccountIdLookup , BlakeTwo256 , Block as BlockT } ,
21
+ traits:: {
22
+ AccountIdLookup , BlakeTwo256 , Block as BlockT , Bounded , Convert , SaturatedConversion ,
23
+ Saturating ,
24
+ } ,
21
25
transaction_validity:: { TransactionSource , TransactionValidity } ,
22
- ApplyExtrinsicResult ,
26
+ ApplyExtrinsicResult , FixedPointNumber , Perquintill ,
23
27
} ;
24
28
25
29
use sp_std:: prelude:: * ;
@@ -34,7 +38,7 @@ use frame_support::{
34
38
dispatch:: DispatchClass ,
35
39
genesis_builder_helper:: { build_config, create_default_config} ,
36
40
parameter_types,
37
- traits:: { ConstBool , ConstU32 , ConstU64 , ConstU8 , EitherOfDiverse , TransformOrigin } ,
41
+ traits:: { ConstBool , ConstU32 , ConstU64 , ConstU8 , EitherOfDiverse , Get , TransformOrigin } ,
38
42
weights:: { ConstantMultiplier , Weight } ,
39
43
PalletId ,
40
44
} ;
@@ -45,16 +49,19 @@ use frame_system::{
45
49
use pallet_xcm:: { EnsureXcm , IsVoiceOfBody } ;
46
50
use parachains_common:: message_queue:: { NarrowOriginToSibling , ParaIdToSibling } ;
47
51
48
- use sugondat_primitives:: { AccountId , AuraId , Balance , BlockNumber , Nonce , Signature } ;
52
+ use sugondat_primitives:: {
53
+ AccountId , AuraId , Balance , BlockNumber , Nonce , Signature , MAXIMUM_BLOCK_LENGTH ,
54
+ } ;
49
55
56
+ use pallet_transaction_payment:: TargetedFeeAdjustment ;
50
57
pub use sp_runtime:: { MultiAddress , Perbill , Permill } ;
51
58
use xcm_config:: { KusamaLocation , XcmOriginToTransactDispatchOrigin } ;
52
59
53
60
#[ cfg( any( feature = "std" , test) ) ]
54
61
pub use sp_runtime:: BuildStorage ;
55
62
56
63
// Polkadot imports
57
- use polkadot_runtime_common:: { BlockHashCount , SlowAdjustingFeeUpdate } ;
64
+ use polkadot_runtime_common:: BlockHashCount ;
58
65
59
66
use weights:: { BlockExecutionWeight , ExtrinsicBaseWeight , RocksDbWeight } ;
60
67
@@ -142,7 +149,7 @@ parameter_types! {
142
149
// `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize
143
150
// the lazy contract deletion.
144
151
pub RuntimeBlockLength : BlockLength =
145
- BlockLength :: max_with_normal_ratio( 5 * 1024 * 1024 , NORMAL_DISPATCH_RATIO ) ;
152
+ BlockLength :: max_with_normal_ratio( MAXIMUM_BLOCK_LENGTH , NORMAL_DISPATCH_RATIO ) ;
146
153
pub RuntimeBlockWeights : BlockWeights = BlockWeights :: builder( )
147
154
. base_block( BlockExecutionWeight :: get( ) )
148
155
. for_class( DispatchClass :: all( ) , |weights| {
@@ -267,14 +274,244 @@ impl pallet_balances::Config for Runtime {
267
274
parameter_types ! {
268
275
/// Relay Chain `TransactionByteFee` / 10
269
276
pub const TransactionByteFee : Balance = MILLICENTS ;
277
+
278
+ // Common constants used in all runtimes for SlowAdjustingFeeUpdate
279
+
280
+ /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less
281
+ /// than this will decrease the weight and more will increase.
282
+ pub storage TargetBlockFullness : Perquintill = Perquintill :: from_percent( 25 ) ;
283
+
284
+ /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to
285
+ /// change the fees more rapidly.
286
+ pub AdjustmentVariableBlockFullness : Multiplier = Multiplier :: saturating_from_rational( 75 , 1000_000 ) ;
287
+ /// that combined with `AdjustmentVariable`, we can recover from the minimum.
288
+ /// See `multiplier_can_grow_from_zero`.
289
+ pub MinimumMultiplierBlockFullness : Multiplier = Multiplier :: saturating_from_rational( 1 , 10u128 ) ;
290
+ /// The maximum amount of the multiplier.
291
+ pub MaximumMultiplierBlockFullness : Multiplier = Bounded :: max_value( ) ;
292
+
293
+
294
+ // parameters used by BlobsFeeAdjustment
295
+
296
+ pub storage NextLengthMultiplier : Multiplier = Multiplier :: saturating_from_integer( 1 ) ;
297
+
298
+ pub storage TargetBlockSize : u32 = 820 * 1024 ; // 0.8MiB
299
+ // TODO: update those value accordingly with https://github.com/thrumdev/blobs/issues/16
300
+ pub AdjustmentVariableBlockSize : Multiplier = Multiplier :: saturating_from_rational( 75 , 1000_000 ) ;
301
+ pub MinimumMultiplierBlockSize : Multiplier = Multiplier :: saturating_from_rational( 1 , 10u128 ) ;
302
+ pub MaximumMultiplierBlockSize : Multiplier = Bounded :: max_value( ) ;
303
+
304
+ // A positive number represents the count of consecutive blocks that exceeded
305
+ // the TargetBlockSize, while a negative number represents the count of
306
+ // consecutive blocks that were below the TargetBlockSize - NegativeDeltaTargetBlockFullness.
307
+ pub storage BlockSizeTracker : u32 = 0 ; // 0.8MiB
308
+
309
+ // The number of consecutive blocks after which the TargetBlockSize will increase
310
+ pub storage IncreaseDeltaBlocks : u32 = 10 * DAYS ;
311
+
312
+ // The number of bytes that will be added to TargetBlockSize each update
313
+ pub storage DeltaTargetBlockSize : u32 = 205 * 1024 ; // 0.2MiB
314
+
315
+ //pub storage DecreaseDeltaBlocks: u32 = 10 * DAYS;,
316
+ //pub storage LowerBoundTargetBlockSize
317
+ }
318
+
319
+ /// Parameterized slow adjusting fee updated based on
320
+ /// <https://research.web3.foundation/Polkadot/overview/token-economics#2-slow-adjusting-mechanism>
321
+ //pub type SlowAdjustingFeeUpdate<R> = TargetedFeeAdjustment<
322
+ // R,
323
+ // TargetBlockFullness,
324
+ // AdjustmentVariable,
325
+ // MinimumMultiplier,
326
+ // MaximumMultiplier,
327
+ //>;
328
+
329
+ /// Currently pallet_transaction_payment use the following formula:
330
+ ///
331
+ /// ```
332
+ /// inclusion_fee = base_fee + length_fee + [targeted_fee_adjustment * weight_fee];
333
+ /// ```
334
+ ///
335
+ /// Letting us able to update `targeted_fee_adjustment` at the end of each block
336
+ /// thanks to `FeeMultiplierUpdate`, this associated type is called inside the `on_finalize`
337
+ /// of the transaction_payment pallet with the aim of converting the before `targeted_fee_adjustment`
338
+ /// to a new one based on the congestion of the network
339
+ ///
340
+ /// What this struct does is this PLUS a side effect, the goal is to reach a different formula to
341
+ /// calculate fees:
342
+ ///
343
+ /// ```
344
+ /// inclusion_fee = base_fee + [targeted_length_fee_adjustment * length_fee] + [targeted_weight_fee_adjustment * weight_fee];
345
+ /// ```
346
+ ///
347
+ /// As you can see `targeted_fee_adjustment` becomes `targeted_weight_fee_adjustment` but the behavior
348
+ /// remains the same, the side effect is the changing to the value `targeted_length_fee_adjustment`,
349
+ /// this formula is achievable because inside pallet_transaction_payment the function `compute_fee_raw`
350
+ /// that just computes the final fee associated with an extrinsic uses the associated type `LenghtToFee`
351
+ /// that converts the length of an extrinsic to a fee.
352
+ ///
353
+ /// By default the implementation is a constant multiplication but we want to achieve a dynamic formula
354
+ /// that can adapt based on the usage of the network, this can't solely be done by this struct but needs
355
+ /// to be bundled with a custom implementation of `LenghtToFee`.
356
+ ///
357
+ /// This struct ONLY provide a dynamic update of `targeted_length_fee_adjustment` and `targeted_weight_fee_adjustment`
358
+ /// based on the congestion and usage of the blocks, while the formula si effectively implemented like
359
+ /// explained above only thanks to `LenghtToFee`
360
+ pub struct BlobsFeeAdjustment < T : frame_system:: Config > ( core:: marker:: PhantomData < T > ) ;
361
+
362
+ impl < T : frame_system:: Config > Convert < Multiplier , Multiplier > for BlobsFeeAdjustment < T >
363
+ where
364
+ T : frame_system:: Config ,
365
+ {
366
+ /// This function should be a pure function used to update NextFeeMultiplier
367
+ /// but will also has the side effect of update NextLenghtMultiplier
368
+ fn convert ( previous_fee_multiplier : Multiplier ) -> Multiplier {
369
+ // Update TargetBlockSize if needed
370
+ let all_extrinsic_len = <frame_system:: Pallet < T > >:: all_extrinsics_len ( ) ;
371
+
372
+ if all_extrinsic_len > TargetBlockSize :: get ( ) {
373
+ // Increase the tracker if needed
374
+ let tracker = BlockSizeTracker :: get ( ) ;
375
+
376
+ // If the used_block_size is larger than the TargetBlockSize
377
+ // for more than IncreaseDeltaBlocks consecutive, then the TargetBlockSize
378
+ // will be increased by DeltaTargetBlockSize.
379
+ if tracker + 1 >= IncreaseDeltaBlocks :: get ( ) {
380
+ let current_target_block_size = TargetBlockSize :: get ( ) ;
381
+ TargetBlockSize :: set ( & ( current_target_block_size + DeltaTargetBlockSize :: get ( ) ) ) ;
382
+ BlockSizeTracker :: set ( & 0 ) ;
383
+ }
384
+
385
+ BlockSizeTracker :: set ( & ( tracker + 1 ) ) ;
386
+ } else {
387
+ // The logic for updating to a new TargetBlockSize currently requires IncreaseDeltaBlocks
388
+ // to be constantly larger than TargetBlockSize. However, it might be possible
389
+ // to implement a window where we reset the tracker only if the
390
+ // block size remains below the TargetBlockSize for a certain number of blocks
391
+ BlockSizeTracker :: set ( & 0 ) ;
392
+ }
393
+
394
+ // Update NextLengthMultiplier
395
+
396
+ // To update the value will be used the same formula as TargetedFeeAdjustment,
397
+ // described here: https://research.web3.foundation/Polkadot/overview/token-economics#2-slow-adjusting-mechanism
398
+ //
399
+ // so this is mainly a copy paste of that function because it works on normalized mesurments,
400
+ // so if it is ref_time, proof_size or lenght of the extrinsic the mutliplier will be evaluated properly.
401
+ // The main problem is that TargetedFeeAdjustment::convert uses directly a call to the storage to extract
402
+ // the weight of the current block so there is no way to pass the lenght as input argument,
403
+ // here I will copy paste all the needed part to update properly NextLengthMultiplier
404
+
405
+ // Defensive only. The multiplier in storage should always be at most positive. Nonetheless
406
+ // we recover here in case of errors, because any value below this would be stale and can
407
+ // never change.
408
+
409
+ let previous_len_multiplier = NextLengthMultiplier :: get ( ) ;
410
+ let min_multiplier = MinimumMultiplierBlockSize :: get ( ) ;
411
+ let max_multiplier = MaximumMultiplierBlockSize :: get ( ) ;
412
+ // TODO: why?
413
+ let previous_len_multiplier = previous_len_multiplier. max ( min_multiplier) ;
414
+
415
+ // Pick the limiting dimension. (from TargetedFeeAdjustment::convert)
416
+ //
417
+ // In this case it is the length of all extrinsic, always
418
+ let ( normal_limiting_dimension, max_limiting_dimension) =
419
+ ( all_extrinsic_len, MAXIMUM_BLOCK_LENGTH ) ;
420
+
421
+ let target_block_size = TargetBlockSize :: get ( ) ;
422
+ let adjustment_variable = AdjustmentVariableBlockSize :: get ( ) ;
423
+
424
+ let target_size = ( target_block_size * max_limiting_dimension) as u128 ;
425
+ let block_size = normal_limiting_dimension as u128 ;
426
+
427
+ // determines if the first_term is positive
428
+ let positive = block_size >= target_size;
429
+ let diff_abs = block_size. max ( target_size) - block_size. min ( target_size) ;
430
+
431
+ // defensive only, a test case assures that the maximum weight diff can fit in Multiplier
432
+ // without any saturation.
433
+ let diff = Multiplier :: saturating_from_rational ( diff_abs, max_limiting_dimension. max ( 1 ) ) ;
434
+ let diff_squared = diff. saturating_mul ( diff) ;
435
+
436
+ let v_squared_2 = adjustment_variable. saturating_mul ( adjustment_variable)
437
+ / Multiplier :: saturating_from_integer ( 2 ) ;
438
+
439
+ let first_term = adjustment_variable. saturating_mul ( diff) ;
440
+ let second_term = v_squared_2. saturating_mul ( diff_squared) ;
441
+
442
+ let new_len_multiplier = if positive {
443
+ let excess = first_term
444
+ . saturating_add ( second_term)
445
+ . saturating_mul ( previous_len_multiplier) ;
446
+ previous_len_multiplier
447
+ . saturating_add ( excess)
448
+ . clamp ( min_multiplier, max_multiplier)
449
+ } else {
450
+ // Defensive-only: first_term > second_term. Safe subtraction.
451
+ let negative = first_term
452
+ . saturating_sub ( second_term)
453
+ . saturating_mul ( previous_len_multiplier) ;
454
+ previous_len_multiplier
455
+ . saturating_sub ( negative)
456
+ . clamp ( min_multiplier, max_multiplier)
457
+ } ;
458
+
459
+ NextLengthMultiplier :: set ( & new_len_multiplier) ;
460
+
461
+ // Update NextFeeMultiplier
462
+ //
463
+ // Here is the tricky part, this method return the new value associated with
464
+ // NextFeeMultiplier (in the old fashion) because weight dynamic adjustment is battle tested
465
+ // while previously have updated the `NextLengthMultiplier` used in `LenghtToWeight`
466
+ TargetedFeeAdjustment :: <
467
+ T ,
468
+ TargetBlockFullness ,
469
+ AdjustmentVariableBlockFullness ,
470
+ MinimumMultiplierBlockFullness ,
471
+ MaximumMultiplierBlockFullness ,
472
+ > :: convert ( previous_fee_multiplier)
473
+ }
474
+ }
475
+
476
+ impl < T : frame_system:: Config > MultiplierUpdate for BlobsFeeAdjustment < T > {
477
+ fn min ( ) -> Multiplier {
478
+ MinimumMultiplierBlockFullness :: get ( )
479
+ }
480
+ fn max ( ) -> Multiplier {
481
+ MaximumMultiplierBlockFullness :: get ( )
482
+ }
483
+ fn target ( ) -> Perquintill {
484
+ TargetBlockFullness :: get ( )
485
+ }
486
+ fn variability ( ) -> Multiplier {
487
+ AdjustmentVariableBlockFullness :: get ( )
488
+ }
489
+ }
490
+
491
+ pub struct BlobsLengthToFee < T : frame_system:: Config > ( core:: marker:: PhantomData < T > ) ;
492
+
493
+ impl < T : frame_system:: Config > sp_weights:: WeightToFee for BlobsLengthToFee < T > {
494
+ type Balance = Balance ;
495
+
496
+ fn weight_to_fee ( weight : & Weight ) -> Self :: Balance {
497
+ // really weird but weght.ref_time will contain the length of the extrinsic
498
+ let length_fee = Self :: Balance :: saturated_from ( weight. ref_time ( ) )
499
+ . saturating_mul ( TransactionByteFee :: get ( ) ) ;
500
+ let multiplier = NextLengthMultiplier :: get ( ) ;
501
+
502
+ // final adjusted length fee
503
+ multiplier. saturating_mul_int ( length_fee)
504
+ }
270
505
}
271
506
272
507
impl pallet_transaction_payment:: Config for Runtime {
273
508
type RuntimeEvent = RuntimeEvent ;
274
509
type OnChargeTransaction = pallet_transaction_payment:: CurrencyAdapter < Balances , ( ) > ;
275
510
type WeightToFee = WeightToFee ;
276
- type LengthToFee = ConstantMultiplier < Balance , TransactionByteFee > ;
277
- type FeeMultiplierUpdate = SlowAdjustingFeeUpdate < Self > ;
511
+ //type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
512
+ type LengthToFee = BlobsLengthToFee < Self > ;
513
+ //type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
514
+ type FeeMultiplierUpdate = BlobsFeeAdjustment < Self > ;
278
515
type OperationalFeeMultiplier = ConstU8 < 5 > ;
279
516
}
280
517
0 commit comments