Configurable Module Constants

To declare constant values within a runtime, it is necessary to import the Get trait from the support module


# #![allow(unused_variables)]
#fn main() {
use support::traits::Get;
#}

Constants can be declared in the pub trait block of the module using the Get<T> syntax for any type T.


# #![allow(unused_variables)]
#fn main() {
pub trait Trait: system::Trait {
    type Event: From<Event> + Into<<Self as system::Trait>::Event>;

    type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

    type MaxAddend: Get<u32>;

    // frequency with which the this value is deleted
    type ClearFrequency: Get<Self::BlockNumber>;
}
#}

In order to make these constants accessible within the module, it is necessary to declare them with the const syntax in the decl_module block. Usually constants are declared at the top of this block, under fn deposit_event.


# #![allow(unused_variables)]
#fn main() {
decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        fn deposit_event() = default;

        const MaxAddend: u32 = T::MaxAddend::get();

        const ClearFrequency: T::BlockNumber = T::ClearFrequency::get();
    }
}
#}

This example manipulates a single value in storage declared as SingleValue.


# #![allow(unused_variables)]
#fn main() {
decl_storage! {
    trait Store for Module<T: Trait> as Example {
        SingleValue get(single_value): u32;
    }
}
#}

SingleValue is set to 0 every ClearFrequency number of blocks. This logic is in the on_finalize block and is covered in deeper detail in the Blockchain Event Loop recipe.


# #![allow(unused_variables)]
#fn main() {
fn on_finalize(n: T::BlockNumber) {
    if (n % T::ClearFrequency::get()).is_zero() {
        let c_val = <SingleValue>::get();
        <SingleValue>::put(0u32); // is this cheaper than killing?
        Self::deposit_event(Event::Cleared(c_val));
    }
}
#}

Signed transactions may invoke the add_value runtime method to increase SingleValue as long as each call adds less than MaxAddend. There is no anti-sybil mechanism so a user could just split a larger request into multiple smaller requests to overcome the MaxAddend, but overflow is still handled appropriately.


# #![allow(unused_variables)]
#fn main() {
fn add_value(origin, val_to_add: u32) -> Result {
    let _ = ensure_signed(origin)?;
    ensure!(val_to_add <= T::MaxAddend::get(), "value must be <= maximum add amount constant");

    // previous single value
    let c_val = <SingleValue>::get();

    // checks for overflow
    let result = match c_val.checked_add(val_to_add) {
        Some(r) => r,
        None => return Err("Addition overflowed"),
    };
    <SingleValue>::put(result);
    Self::deposit_event(Event::Added(c_val, val_to_add, result));
    Ok(())
}
#}

In more complex patterns, the constant value may be used as a static, base value that is scaled by a multiplier to incorporate stateful context for calculating some dynamic fee (ie floating transaction fees).