/// This module keeps a global wall clock that stores the current Unix time in microseconds. /// It interacts with the other modules in the following ways: /// /// * Genesis: to initialize the timestamp /// * ValidatorSystem, AptosAccount, Reconfiguration: to check if the current state is in the genesis state /// * Block: to reach consensus on the global wall clock time /// /// This module moreover enables code to assert that it is running in genesis (`Self::assert_genesis`) or after /// genesis (`Self::assert_operating`). These are essentially distinct states of the system. Specifically, /// if `Self::assert_operating` succeeds, assumptions about invariants over the global state can be made /// which reflect that the system has been successfully initialized. module aptos_framework::timestamp { use aptos_framework::system_addresses; use std::error; friend aptos_framework::genesis; /// A singleton resource holding the current Unix time in microseconds struct CurrentTimeMicroseconds has key { microseconds: u64, } /// Conversion factor between seconds and microseconds const MICRO_CONVERSION_FACTOR: u64 = 1000000; /// The blockchain is not in the genesis state anymore const ENOT_GENESIS: u64 = 0; /// The blockchain is not in an operating state yet const ENOT_OPERATING: u64 = 1; /// An invalid timestamp was provided const ETIMESTAMP: u64 = 2; /// Marks that time has started and genesis has finished. This can only be called from genesis and with the root /// account. public(friend) fun set_time_has_started(account: &signer) { assert_genesis(); system_addresses::assert_aptos_framework(account); let timer = CurrentTimeMicroseconds { microseconds: 0 }; move_to(account, timer); } #[test_only] public fun set_time_has_started_for_testing(account: &signer) { set_time_has_started(account); } /// Updates the wall clock time by consensus. Requires VM privilege and will be invoked during block prologue. public fun update_global_time( account: &signer, proposer: address, timestamp: u64 ) acquires CurrentTimeMicroseconds { assert_operating(); // Can only be invoked by AptosVM signer. system_addresses::assert_vm(account); let global_timer = borrow_global_mut(@aptos_framework); let now = global_timer.microseconds; if (proposer == @vm_reserved) { // NIL block with null address as proposer. Timestamp must be equal. assert!(now == timestamp, error::invalid_argument(ETIMESTAMP)); } else { // Normal block. Time must advance assert!(now < timestamp, error::invalid_argument(ETIMESTAMP)); }; global_timer.microseconds = timestamp; } /// Gets the current time in microseconds. public fun now_microseconds(): u64 acquires CurrentTimeMicroseconds { assert_operating(); borrow_global(@aptos_framework).microseconds } /// Gets the current time in seconds. public fun now_seconds(): u64 acquires CurrentTimeMicroseconds { now_microseconds() / MICRO_CONVERSION_FACTOR } /// Helper function to determine if Aptos is in genesis state. public fun is_genesis(): bool { !exists(@aptos_framework) } /// Helper function to assert genesis state. public fun assert_genesis() { assert!(is_genesis(), error::invalid_state(ENOT_GENESIS)); } /// Helper function to determine if Aptos is operating. This is the same as `!is_genesis()` and is provided /// for convenience. Testing `is_operating()` is more frequent than `is_genesis()`. public fun is_operating(): bool { exists(@aptos_framework) } /// Helper function to assert operating (!genesis) state. public fun assert_operating() { assert!(is_operating(), error::invalid_state(ENOT_OPERATING)); } #[test_only] public fun update_global_time_for_test(timestamp_microsecs: u64) acquires CurrentTimeMicroseconds { let global_timer = borrow_global_mut(@aptos_framework); let now = global_timer.microseconds; assert!(now < timestamp_microsecs, error::invalid_argument(ETIMESTAMP)); global_timer.microseconds = timestamp_microsecs; } #[test_only] public fun fast_forward_seconds(timestamp_seconds: u64) acquires CurrentTimeMicroseconds { update_global_time_for_test(now_microseconds() + timestamp_seconds * 1000000); } }