Search code examples
rustsubstrate

Substrate frame V2 how to use pallet_timestamp


Following the substrate tutorial and declared the pallet configuration as follows In pallet lib.rs

use pallet_timestamp as timestamp;
    #[pallet::config]
    pub trait Config: frame_system::Config + pallet_timestamp::Config{
        type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
    }

Configuration in Caego.toml

pallet-timestamp = { version = '3.0', default-features = false}

std = [
    'codec/std',
    'frame-support/std',
    'frame-system/std',
    'sp-runtime/std',
    'pallet-timestamp/std',
    'log/std',
]

I need to get the timestamp using pallet_timestamp

#[pallet::call]
impl<T: Config> Pallet<T> {

        #[pallet::weight(0)]
        pub fn update_recoed(origin: OriginFor<T>, record: Vec<u8>) -> DispatchResultWithPostInfo {
            let pallet_time = <timestamp::Module<T>>::get(); // Error
            Ok(().into())
        }
}

How to access the time in Substrate Pallet V2?


Solution

  • Rather than use the pallet directly as you are showing, you should instead use one of the two traits made available by the pallet and loose coupling of the pallets.

    The two traits I am mentioning can be found in the pallet_timestamp source code:

    impl<T: Config> Time for Pallet<T> {
        type Moment = T::Moment;
    
        /// Before the first set of now with inherent the value returned is zero.
        fn now() -> Self::Moment {
            Self::now()
        }
    }
    
    /// Before the timestamp inherent is applied, it returns the time of previous block.
    ///
    /// On genesis the time returned is not valid.
    impl<T: Config> UnixTime for Pallet<T> {
        fn now() -> core::time::Duration {
            // now is duration since unix epoch in millisecond as documented in
            // `sp_timestamp::InherentDataProvider`.
            let now = Self::now();
            sp_std::if_std! {
                if now == T::Moment::zero() {
                    log::error!(
                        target: "runtime::timestamp",
                        "`pallet_timestamp::UnixTime::now` is called at genesis, invalid value returned: 0",
                    );
                }
            }
            core::time::Duration::from_millis(now.saturated_into::<u64>())
        }
    }
    

    To use this, you should do the following in your new pallet:

    1. Update your config to have a new configuration which uses one of these traits. You do NOT need to tightly couple your pallet to pallet_timestamp:
    use frame_support::traits::UnixTime;
    
    #[pallet::config]
    pub trait Config: frame_system::Config {
        type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
        type TimeProvider: UnixTime;
    }
    
    1. Then, anywhere in your pallet, you can call T::TimeProvider::now() to return the unix time in milliseconds as a u64.
    let time: u64 = T::TimeProvider::now().as_secs();
    
    1. Then for this to work, you need to plug the pallet_timstamp pallet as your "TimeProvider". You do that by configuring this when you impl your my_pallet::Config:
    impl my_pallet::Config for Runtime {
        type Event = Event;
        type TimeProvider = pallet_timestamp::Pallet<Runtime>;
        // Or more easily just `Timestamp` assuming you used that name in `construct_runtime!`
    }