Skip to content

Commit

Permalink
[RFC] Add epoch_start_timestamp_ms to system object (MystenLabs#7518)
Browse files Browse the repository at this point in the history
This PR exposes timestamp of epoch start to the smart contracts in move,
by putting this timestamp in the system object.

This can be useful for smart contract that needs some very coarse time
before we have more granular timestamps.
  • Loading branch information
andll authored Jan 24, 2023
1 parent 95b7493 commit d38bf93
Show file tree
Hide file tree
Showing 18 changed files with 124 additions and 26 deletions.
1 change: 1 addition & 0 deletions crates/sui-adapter/src/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ fn advance_epoch<S: BackingPackageStore + ParentSync + ChildObjectResolver>(
CallArg::Pure(bcs::to_bytes(&STORAGE_FUND_REINVEST_RATE).unwrap()),
CallArg::Pure(bcs::to_bytes(&REWARD_SLASHING_RATE).unwrap()),
CallArg::Pure(bcs::to_bytes(&STAKE_SUBSIDY_RATE).unwrap()),
CallArg::Pure(bcs::to_bytes(&change_epoch.epoch_start_timestamp_ms).unwrap()),
],
gas_status.create_move_gas_status(),
tx_ctx,
Expand Down
20 changes: 18 additions & 2 deletions crates/sui-config/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,13 @@ fn build_unsigned_genesis_data(
sui_framework::get_sui_framework(),
];

let objects = create_genesis_objects(&mut genesis_ctx, &modules, objects, validators);
let objects = create_genesis_objects(
&mut genesis_ctx,
&modules,
objects,
validators,
parameters.timestamp_ms,
);

let (genesis_transaction, genesis_effects, objects) = create_genesis_transaction(objects);
let (checkpoint, checkpoint_contents) =
Expand Down Expand Up @@ -819,6 +825,7 @@ fn create_genesis_objects(
modules: &[Vec<CompiledModule>],
input_objects: &[Object],
validators: &[GenesisValidatorInfo],
epoch_start_timestamp_ms: u64,
) -> Vec<Object> {
let mut store = InMemoryStorage::new(Vec::new());

Expand All @@ -841,7 +848,14 @@ fn create_genesis_objects(
store.insert_object(object.to_owned());
}

generate_genesis_system_object(&mut store, &move_vm, validators, genesis_ctx).unwrap();
generate_genesis_system_object(
&mut store,
&move_vm,
validators,
genesis_ctx,
epoch_start_timestamp_ms,
)
.unwrap();

store
.into_inner()
Expand Down Expand Up @@ -924,6 +938,7 @@ pub fn generate_genesis_system_object(
move_vm: &MoveVM,
committee: &[GenesisValidatorInfo],
genesis_ctx: &mut TxContext,
epoch_start_timestamp_ms: u64,
) -> Result<()> {
let genesis_digest = genesis_ctx.digest();
let mut temporary_store =
Expand Down Expand Up @@ -989,6 +1004,7 @@ pub fn generate_genesis_system_object(
CallArg::Pure(bcs::to_bytes(&stakes).unwrap()),
CallArg::Pure(bcs::to_bytes(&gas_prices).unwrap()),
CallArg::Pure(bcs::to_bytes(&commission_rates).unwrap()),
CallArg::Pure(bcs::to_bytes(&epoch_start_timestamp_ms).unwrap()),
],
SuiGasStatus::new_unmetered().create_move_gas_status(),
genesis_ctx,
Expand Down
2 changes: 2 additions & 0 deletions crates/sui-config/tests/snapshot_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use insta::assert_yaml_snapshot;
use multiaddr::Multiaddr;
use rand::rngs::StdRng;
use rand::SeedableRng;
use sui_config::genesis::GenesisChainParameters;
use sui_config::ValidatorInfo;
use sui_config::{genesis::Builder, genesis_config::GenesisConfig};
use sui_types::base_types::{ObjectID, SuiAddress};
Expand Down Expand Up @@ -81,6 +82,7 @@ fn populated_genesis_snapshot_matches() {
let genesis = Builder::new()
.add_objects(objects)
.add_validator(validator, pop)
.with_parameters(GenesisChainParameters { timestamp_ms: 10 })
.add_validator_signature(&key)
.build();
assert_yaml_snapshot!(genesis.validator_set());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,4 +506,4 @@ stake_subsidy:
value: 0
current_epoch_amount: 1000000
safe_mode: false

epoch_start_timestamp_ms: 10
4 changes: 3 additions & 1 deletion crates/sui-core/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use sui_types::event::{Event, EventID};
use sui_types::gas::{GasCostSummary, SuiGasStatus};
use sui_types::messages_checkpoint::{
CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber,
CheckpointSummary,
CheckpointSummary, CheckpointTimestamp,
};
use sui_types::messages_checkpoint::{CheckpointRequest, CheckpointResponse};
use sui_types::object::{Owner, PastObjectRead};
Expand Down Expand Up @@ -2576,6 +2576,7 @@ impl AuthorityState {
&self,
epoch_store: &Arc<AuthorityPerEpochStore>,
gas_cost_summary: &GasCostSummary,
epoch_start_timestamp_ms: CheckpointTimestamp,
timeout: Duration,
transaction_certifier: &dyn TransactionCertifier,
) -> anyhow::Result<VerifiedCertificate> {
Expand All @@ -2592,6 +2593,7 @@ impl AuthorityState {
gas_cost_summary.storage_cost,
gas_cost_summary.computation_cost,
gas_cost_summary.storage_rebate,
epoch_start_timestamp_ms,
);
// If we fail to sign the transaction locally for whatever reason, it's not recoverable.
self.handle_transaction_impl(tx.clone(), epoch_store)
Expand Down
33 changes: 20 additions & 13 deletions crates/sui-core/src/checkpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,11 +562,27 @@ impl CheckpointBuilder {
"Received {} checkpoint user signatures from consensus",
signatures.len()
);
let sequence_number = last_checkpoint
.as_ref()
.map(|(_, c)| c.sequence_number + 1)
.unwrap_or_default();
let timestamp_ms = details.timestamp_ms;
if let Some((_, last_checkpoint)) = &last_checkpoint {
if last_checkpoint.timestamp_ms > timestamp_ms {
error!("Unexpected decrease of checkpoint timestamp, sequence: {}, previous: {}, current: {}",
sequence_number, last_checkpoint.timestamp_ms, timestamp_ms);
}
}

let epoch_rolling_gas_cost_summary =
self.get_epoch_total_gas_cost(last_checkpoint.as_ref().map(|(_, c)| c), &effects);
if last_checkpoint_of_epoch {
self.augment_epoch_last_checkpoint(&epoch_rolling_gas_cost_summary, &mut effects)
.await?;
self.augment_epoch_last_checkpoint(
&epoch_rolling_gas_cost_summary,
timestamp_ms,
&mut effects,
)
.await?;
}

let contents =
Expand All @@ -583,17 +599,6 @@ impl CheckpointBuilder {
.unwrap_or(num_txns);

let previous_digest = last_checkpoint.as_ref().map(|(_, c)| c.digest());
let sequence_number = last_checkpoint
.as_ref()
.map(|(_, c)| c.sequence_number + 1)
.unwrap_or_default();
let timestamp_ms = details.timestamp_ms;
if let Some((_, last_checkpoint)) = &last_checkpoint {
if last_checkpoint.timestamp_ms > timestamp_ms {
error!("Unexpected decrease of checkpoint timestamp, sequence: {}, previous: {}, current: {}",
sequence_number, last_checkpoint.timestamp_ms, timestamp_ms);
}
}
let summary = CheckpointSummary::new(
epoch,
sequence_number,
Expand Down Expand Up @@ -655,6 +660,7 @@ impl CheckpointBuilder {
async fn augment_epoch_last_checkpoint(
&self,
epoch_total_gas_cost: &GasCostSummary,
epoch_start_timestamp_ms: CheckpointTimestamp,
effects: &mut Vec<TransactionEffects>,
) -> anyhow::Result<()> {
let timer = Instant::now();
Expand All @@ -663,6 +669,7 @@ impl CheckpointBuilder {
.create_advance_epoch_tx_cert(
&self.epoch_store,
epoch_total_gas_cost,
epoch_start_timestamp_ms,
Duration::from_secs(60), // TODO: Is 60s enough?
self.transaction_certifier.deref(),
)
Expand Down
1 change: 1 addition & 0 deletions crates/sui-core/tests/staged/sui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ ChangeEpoch:
- storage_charge: U64
- computation_charge: U64
- storage_rebate: U64
- epoch_start_timestamp_ms: U64
CircularObjectOwnership:
STRUCT:
- object:
Expand Down
4 changes: 3 additions & 1 deletion crates/sui-framework/docs/genesis.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ It will create a singleton SuiSystemState object, which contains
all the information we need in the system.


<pre><code><b>fun</b> <a href="genesis.md#0x2_genesis_create">create</a>(validator_pubkeys: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_network_pubkeys: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_worker_pubkeys: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_proof_of_possessions: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_sui_addresses: <a href="">vector</a>&lt;<b>address</b>&gt;, validator_names: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_descriptions: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_image_urls: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_project_urls: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_net_addresses: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_consensus_addresses: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_worker_addresses: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_stakes: <a href="">vector</a>&lt;u64&gt;, validator_gas_prices: <a href="">vector</a>&lt;u64&gt;, validator_commission_rates: <a href="">vector</a>&lt;u64&gt;, ctx: &<b>mut</b> <a href="tx_context.md#0x2_tx_context_TxContext">tx_context::TxContext</a>)
<pre><code><b>fun</b> <a href="genesis.md#0x2_genesis_create">create</a>(validator_pubkeys: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_network_pubkeys: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_worker_pubkeys: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_proof_of_possessions: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_sui_addresses: <a href="">vector</a>&lt;<b>address</b>&gt;, validator_names: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_descriptions: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_image_urls: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_project_urls: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_net_addresses: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_consensus_addresses: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_worker_addresses: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, validator_stakes: <a href="">vector</a>&lt;u64&gt;, validator_gas_prices: <a href="">vector</a>&lt;u64&gt;, validator_commission_rates: <a href="">vector</a>&lt;u64&gt;, epoch_start_timestamp_ms: u64, ctx: &<b>mut</b> <a href="tx_context.md#0x2_tx_context_TxContext">tx_context::TxContext</a>)
</code></pre>


Expand All @@ -100,6 +100,7 @@ all the information we need in the system.
validator_stakes: <a href="">vector</a>&lt;u64&gt;,
validator_gas_prices: <a href="">vector</a>&lt;u64&gt;,
validator_commission_rates: <a href="">vector</a>&lt;u64&gt;,
epoch_start_timestamp_ms: u64,
ctx: &<b>mut</b> TxContext,
) {
<b>let</b> sui_supply = <a href="sui.md#0x2_sui_new">sui::new</a>(ctx);
Expand Down Expand Up @@ -165,6 +166,7 @@ all the information we need in the system.
<a href="genesis.md#0x2_genesis_INIT_MAX_VALIDATOR_COUNT">INIT_MAX_VALIDATOR_COUNT</a>,
<a href="genesis.md#0x2_genesis_INIT_MIN_VALIDATOR_STAKE">INIT_MIN_VALIDATOR_STAKE</a>,
<a href="genesis.md#0x2_genesis_INIT_STAKE_SUBSIDY_AMOUNT">INIT_STAKE_SUBSIDY_AMOUNT</a>,
epoch_start_timestamp_ms,
);
}
</code></pre>
Expand Down
41 changes: 39 additions & 2 deletions crates/sui-framework/docs/sui_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- [Function `advance_epoch`](#0x2_sui_system_advance_epoch)
- [Function `advance_epoch_safe_mode`](#0x2_sui_system_advance_epoch_safe_mode)
- [Function `epoch`](#0x2_sui_system_epoch)
- [Function `epoch_start_timestamp_ms`](#0x2_sui_system_epoch_start_timestamp_ms)
- [Function `validator_delegate_amount`](#0x2_sui_system_validator_delegate_amount)
- [Function `validator_stake_amount`](#0x2_sui_system_validator_stake_amount)
- [Function `get_reporters_of`](#0x2_sui_system_get_reporters_of)
Expand Down Expand Up @@ -179,6 +180,12 @@ The top-level object containing all information of the Sui system.
TODO: Down the road we may want to save a few states such as pending gas rewards, so that we could
redistribute them.
</dd>
<dt>
<code>epoch_start_timestamp_ms: u64</code>
</dt>
<dd>
Unix timestamp of the current epoch start
</dd>
</dl>


Expand Down Expand Up @@ -346,7 +353,7 @@ Create a new SuiSystemState object and make it shared.
This function will be called only once in genesis.


<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="sui_system.md#0x2_sui_system_create">create</a>(validators: <a href="">vector</a>&lt;<a href="validator.md#0x2_validator_Validator">validator::Validator</a>&gt;, sui_supply: <a href="balance.md#0x2_balance_Supply">balance::Supply</a>&lt;<a href="sui.md#0x2_sui_SUI">sui::SUI</a>&gt;, storage_fund: <a href="balance.md#0x2_balance_Balance">balance::Balance</a>&lt;<a href="sui.md#0x2_sui_SUI">sui::SUI</a>&gt;, max_validator_candidate_count: u64, min_validator_stake: u64, initial_stake_subsidy_amount: u64)
<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="sui_system.md#0x2_sui_system_create">create</a>(validators: <a href="">vector</a>&lt;<a href="validator.md#0x2_validator_Validator">validator::Validator</a>&gt;, sui_supply: <a href="balance.md#0x2_balance_Supply">balance::Supply</a>&lt;<a href="sui.md#0x2_sui_SUI">sui::SUI</a>&gt;, storage_fund: <a href="balance.md#0x2_balance_Balance">balance::Balance</a>&lt;<a href="sui.md#0x2_sui_SUI">sui::SUI</a>&gt;, max_validator_candidate_count: u64, min_validator_stake: u64, initial_stake_subsidy_amount: u64, epoch_start_timestamp_ms: u64)
</code></pre>


Expand All @@ -362,6 +369,7 @@ This function will be called only once in genesis.
max_validator_candidate_count: u64,
min_validator_stake: u64,
initial_stake_subsidy_amount: u64,
epoch_start_timestamp_ms: u64,
) {
<b>let</b> validators = <a href="validator_set.md#0x2_validator_set_new">validator_set::new</a>(validators);
<b>let</b> reference_gas_price = <a href="validator_set.md#0x2_validator_set_derive_reference_gas_price">validator_set::derive_reference_gas_price</a>(&validators);
Expand All @@ -380,6 +388,7 @@ This function will be called only once in genesis.
validator_report_records: <a href="vec_map.md#0x2_vec_map_empty">vec_map::empty</a>(),
<a href="stake_subsidy.md#0x2_stake_subsidy">stake_subsidy</a>: <a href="stake_subsidy.md#0x2_stake_subsidy_create">stake_subsidy::create</a>(initial_stake_subsidy_amount),
safe_mode: <b>false</b>,
epoch_start_timestamp_ms,
};
<a href="transfer.md#0x2_transfer_share_object">transfer::share_object</a>(state);
}
Expand Down Expand Up @@ -1005,7 +1014,7 @@ gas coins.
4. Update all validators.


<pre><code><b>public</b> entry <b>fun</b> <a href="sui_system.md#0x2_sui_system_advance_epoch">advance_epoch</a>(self: &<b>mut</b> <a href="sui_system.md#0x2_sui_system_SuiSystemState">sui_system::SuiSystemState</a>, new_epoch: u64, storage_charge: u64, computation_charge: u64, storage_rebate: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, stake_subsidy_rate: u64, ctx: &<b>mut</b> <a href="tx_context.md#0x2_tx_context_TxContext">tx_context::TxContext</a>)
<pre><code><b>public</b> entry <b>fun</b> <a href="sui_system.md#0x2_sui_system_advance_epoch">advance_epoch</a>(self: &<b>mut</b> <a href="sui_system.md#0x2_sui_system_SuiSystemState">sui_system::SuiSystemState</a>, new_epoch: u64, storage_charge: u64, computation_charge: u64, storage_rebate: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, stake_subsidy_rate: u64, epoch_start_timestamp_ms: u64, ctx: &<b>mut</b> <a href="tx_context.md#0x2_tx_context_TxContext">tx_context::TxContext</a>)
</code></pre>


Expand All @@ -1024,11 +1033,14 @@ gas coins.
// into storage fund, in basis point.
reward_slashing_rate: u64, // how much rewards are slashed <b>to</b> punish a <a href="validator.md#0x2_validator">validator</a>, in bps.
stake_subsidy_rate: u64, // what percentage of the total <a href="stake.md#0x2_stake">stake</a> do we mint <b>as</b> <a href="stake.md#0x2_stake">stake</a> subsidy.
epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
ctx: &<b>mut</b> TxContext,
) {
// Validator will make a special system call <b>with</b> sender set <b>as</b> 0x0.
<b>assert</b>!(<a href="tx_context.md#0x2_tx_context_sender">tx_context::sender</a>(ctx) == @0x0, 0);

self.epoch_start_timestamp_ms = epoch_start_timestamp_ms;

<b>let</b> bps_denominator_u64 = (<a href="sui_system.md#0x2_sui_system_BASIS_POINT_DENOMINATOR">BASIS_POINT_DENOMINATOR</a> <b>as</b> u64);
// Rates can't be higher than 100%.
<b>assert</b>!(
Expand Down Expand Up @@ -1198,6 +1210,31 @@ since epochs are ever-increasing and epoch changes are intended to happen every



</details>

<a name="0x2_sui_system_epoch_start_timestamp_ms"></a>

## Function `epoch_start_timestamp_ms`

Returns unix timestamp of the start of current epoch


<pre><code><b>public</b> <b>fun</b> <a href="sui_system.md#0x2_sui_system_epoch_start_timestamp_ms">epoch_start_timestamp_ms</a>(self: &<a href="sui_system.md#0x2_sui_system_SuiSystemState">sui_system::SuiSystemState</a>): u64
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="sui_system.md#0x2_sui_system_epoch_start_timestamp_ms">epoch_start_timestamp_ms</a>(self: &<a href="sui_system.md#0x2_sui_system_SuiSystemState">SuiSystemState</a>): u64 {
self.epoch_start_timestamp_ms
}
</code></pre>



</details>

<a name="0x2_sui_system_validator_delegate_amount"></a>
Expand Down
5 changes: 4 additions & 1 deletion crates/sui-framework/sources/governance/genesis.move
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module sui::genesis {
validator_stakes: vector<u64>,
validator_gas_prices: vector<u64>,
validator_commission_rates: vector<u64>,
epoch_start_timestamp_ms: u64,
ctx: &mut TxContext,
) {
let sui_supply = sui::new(ctx);
Expand Down Expand Up @@ -108,6 +109,7 @@ module sui::genesis {
INIT_MAX_VALIDATOR_COUNT,
INIT_MIN_VALIDATOR_STAKE,
INIT_STAKE_SUBSIDY_AMOUNT,
epoch_start_timestamp_ms,
);
}

Expand All @@ -123,7 +125,8 @@ module sui::genesis {
storage_fund,
INIT_MAX_VALIDATOR_COUNT,
INIT_MIN_VALIDATOR_STAKE,
INIT_STAKE_SUBSIDY_AMOUNT
INIT_STAKE_SUBSIDY_AMOUNT,
0,
)
}
}
Loading

0 comments on commit d38bf93

Please sign in to comment.