Skip to content
Snippets Groups Projects
Unverified Commit aa353283 authored by Dónal Murray's avatar Dónal Murray Committed by GitHub
Browse files

[pallet_broker] Fix `adapt_price` behaviour at zero (#3636)


This fixes the behaviour of `Linear` which is the default implementation
of the `AdaptPrice` trait in the broker pallet. Previously if cores were
offered but not sold in only one sale, the price would be set to zero
and due to the logic being purely multiplicative, the price would stay
at 0 indefinitely.

This could be further paired with a configurable minimum in the broker
pallet itself, which will be a future PR.

This affects the Rococo and Westend Coretime chains, but Kusama has a
different implementation so this isn't required for the Kusama launch. I
actually thought I opened this a while ago.

---------

Co-authored-by: default avatarBastian Köcher <git@kchr.de>
parent 8dc6048d
No related merge requests found
Pipeline #453949 canceled with stages
in 20 minutes and 51 seconds
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
title: "[pallet_broker] Fix `Linear::adapt_price` behavior at zero"
doc:
- audience: Runtime Dev
description: |
This fixes the behaviour of `Linear` which is the default implementation of the `AdaptPrice`
trait in the broker pallet. Previously if cores were offered but not sold in only one sale,
the price would be set to zero and due to the logic being purely multiplicative, the price
would stay at 0 indefinitely.
crates:
- name: pallet-broker
......@@ -19,6 +19,7 @@
use crate::CoreIndex;
use sp_arithmetic::{traits::One, FixedU64};
use sp_runtime::Saturating;
/// Type for determining how to set price.
pub trait AdaptPrice {
......@@ -49,14 +50,24 @@ impl AdaptPrice for () {
pub struct Linear;
impl AdaptPrice for Linear {
fn leadin_factor_at(when: FixedU64) -> FixedU64 {
FixedU64::from(2) - when
FixedU64::from(2).saturating_sub(when)
}
fn adapt_price(sold: CoreIndex, target: CoreIndex, limit: CoreIndex) -> FixedU64 {
if sold <= target {
FixedU64::from_rational(sold.into(), target.into())
// Range of [0.5, 1.0].
FixedU64::from_rational(1, 2).saturating_add(FixedU64::from_rational(
sold.into(),
target.saturating_mul(2).into(),
))
} else {
FixedU64::one() +
FixedU64::from_rational((sold - target).into(), (limit - target).into())
// Range of (1.0, 2].
// Unchecked math: In this branch we know that sold > target. The limit must be >= sold
// by construction, and thus target must be < limit.
FixedU64::one().saturating_add(FixedU64::from_rational(
(sold - target).into(),
(limit - target).into(),
))
}
}
}
......@@ -81,4 +92,23 @@ mod tests {
}
}
}
#[test]
fn linear_bound_check() {
// Using constraints from pallet implementation i.e. `limit >= sold`.
// Check extremes
let limit = 10;
let target = 5;
// Maximally sold: `sold == limit`
assert_eq!(Linear::adapt_price(limit, target, limit), FixedU64::from_float(2.0));
// Ideally sold: `sold == target`
assert_eq!(Linear::adapt_price(target, target, limit), FixedU64::one());
// Minimally sold: `sold == 0`
assert_eq!(Linear::adapt_price(0, target, limit), FixedU64::from_float(0.5));
// Optimistic target: `target == limit`
assert_eq!(Linear::adapt_price(limit, limit, limit), FixedU64::one());
// Pessimistic target: `target == 0`
assert_eq!(Linear::adapt_price(limit, 0, limit), FixedU64::from_float(2.0));
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment