round_state.move

Tracks the current window number and anchors checkpoint hashes on-chain. All nodes read RoundState to synchronize on the current window.

Shared Object

RoundState — created at package publish; shared with all nodes.

Key Types

public struct RoundState has key {
    id: UID,
    current_window: u64,
    genesis_ms: u64,             // Timestamp of window 0
    checkpoint_hash: vector<u8>, // SHA-256 hash of latest anchored checkpoint
    checkpoint_window: u64,      // Window at which the checkpoint was anchored
    admin: address,
}

Window Derivation

The current window is derived from the current Sui clock timestamp:

$$\text{window} = \left\lfloor \frac{\text{now_ms} - \text{genesis_ms}}{\text{window_duration_ms}} \right\rfloor$$

This is deterministic — all nodes compute the same window from the same timestamp and genesis, without any coordinator.

Entry Functions

advance_window

public entry fun advance_window(
    state: &mut RoundState,
    hparams: &slcl::hparams::Hparams,
    clock: &sui::clock::Clock,
    ctx: &mut TxContext,
)

Advances current_window to the current derived window. Called by any node at window boundaries.

anchor_checkpoint

public entry fun anchor_checkpoint(
    state: &mut RoundState,
    checkpoint_hash: vector<u8>,
    window: u64,
    clock: &sui::clock::Clock,
    ctx: &mut TxContext,
)

Records a new checkpoint hash on-chain. Called by the aggregator every checkpoint_frequency windows. The checkpoint_hash is SHA-256 of the serialized checkpoint bytes.

Miners read this hash to verify they loaded the correct checkpoint before training.

score_ledger.move reads this hash to verify that submitted scores reference the current checkpoint.

View Functions

public fun current_window(state: &RoundState): u64
public fun get_checkpoint_hash(state: &RoundState): &vector<u8>
public fun get_checkpoint_window(state: &RoundState): u64

Error Codes

Code Constant Meaning
1 E_WINDOW_NOT_ADVANCED Attempted to anchor checkpoint before advancing window
2 E_CHECKPOINT_TOO_OLD Checkpoint window is behind current window

Checkpoint Lifecycle

Every checkpoint_frequency windows:

Aggregator:
  1. Downloads top-G miner gradients
  2. Aggregates into merged model state
  3. Uploads checkpoint bytes to R2
  4. Computes SHA-256 hash of checkpoint bytes
  5. Calls anchor_checkpoint on-chain

Miners (next window):
  1. Read checkpoint_hash from RoundState
  2. Download checkpoint bytes from R2
  3. Verify SHA-256(bytes) == checkpoint_hash
  4. Load model weights from bytes

The on-chain hash prevents a malicious aggregator from serving a different model than what was committed.