0x1::Timestamp
The module implements onchain timestamp oracle. Timestamp is updated on each block. It always steps forward, and never come backward.
CurrentTimeMilliseconds
TimeHasStarted
initialize
update_global_time
now_seconds
now_milliseconds
set_time_has_started
is_genesis
assert_genesis
use 0x1::CoreAddresses;
use 0x1::Errors;
CurrentTimeMilliseconds
struct CurrentTimeMilliseconds has key
milliseconds: u64
TimeHasStarted
A singleton resource used to determine whether time has started. This is called at the end of genesis.
struct TimeHasStarted has key
dummy_field: bool
const EINVALID_TIMESTAMP: u64 = 14;
const ENOT_GENESIS: u64 = 12;
const ENOT_INITIALIZED: u64 = 101;
Conversion factor between seconds and milliseconds
const MILLI_CONVERSION_FACTOR: u64 = 1000;
initialize
public fun initialize(account: &signer, genesis_timestamp: u64)
public fun initialize(account: &signer, genesis_timestamp: u64) {
// Only callable by the Genesis address
CoreAddresses::assert_genesis_address(account);
let milli_timer = CurrentTimeMilliseconds {milliseconds: genesis_timestamp};
move_to<CurrentTimeMilliseconds>(account, milli_timer);
}
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if exists<CurrentTimeMilliseconds>(Signer::address_of(account));
ensures exists<CurrentTimeMilliseconds>(Signer::address_of(account));
update_global_time
public fun update_global_time(account: &signer, timestamp: u64)
public fun update_global_time(account: &signer, timestamp: u64) acquires CurrentTimeMilliseconds {
CoreAddresses::assert_genesis_address(account);
//Do not update time before time start.
let global_milli_timer = borrow_global_mut<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
assert!(timestamp > global_milli_timer.milliseconds, Errors::invalid_argument(EINVALID_TIMESTAMP));
global_milli_timer.milliseconds = timestamp;
}
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
aborts_if timestamp <= global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds;
ensures global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds == timestamp;
now_seconds
public fun now_seconds(): u64
public fun now_seconds(): u64 acquires CurrentTimeMilliseconds {
now_milliseconds() / MILLI_CONVERSION_FACTOR
}
aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
ensures result == now_milliseconds() / MILLI_CONVERSION_FACTOR;
fun spec_now_seconds(): u64 {
global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds / MILLI_CONVERSION_FACTOR
}
now_milliseconds
public fun now_milliseconds(): u64
public fun now_milliseconds(): u64 acquires CurrentTimeMilliseconds {
borrow_global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds
}
aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
ensures result == global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds;
fun spec_now_millseconds(): u64 {
global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds
}
set_time_has_started
Marks that time has started and genesis has finished. This can only be called from genesis.
public fun set_time_has_started(account: &signer)
public fun set_time_has_started(account: &signer) {
CoreAddresses::assert_genesis_address(account);
// Current time must have been initialized.
assert!(
exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()),
Errors::invalid_state(ENOT_INITIALIZED)
);
move_to(account, TimeHasStarted{});
}
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists<CurrentTimeMilliseconds>(Signer::address_of(account));
aborts_if exists<TimeHasStarted>(Signer::address_of(account));
ensures exists<TimeHasStarted>(Signer::address_of(account));
is_genesis
Helper function to determine if the blockchain is in genesis state.
public fun is_genesis(): bool
public fun is_genesis(): bool {
!exists<TimeHasStarted>(CoreAddresses::GENESIS_ADDRESS())
}
aborts_if false;
ensures result == !exists<TimeHasStarted>(CoreAddresses::GENESIS_ADDRESS());
assert_genesis
Helper function to assert genesis state.
public fun assert_genesis()
public fun assert_genesis() {
assert!(is_genesis(), Errors::invalid_state(ENOT_GENESIS));
}
pragma opaque = true;
include AbortsIfNotGenesis;
Helper schema to specify that a function aborts if not in genesis.
schema AbortsIfNotGenesis {
aborts_if !is_genesis();
}
schema AbortsIfTimestampNotExists {
aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
}
pragma verify;
pragma aborts_if_is_strict;