Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
99f6904
feat(contract): auto-expire unused launcher image hashes
barakeinav1 Jun 15, 2026
d7c0c65
fix(contract): validate config TTL on init, dedup dummy_config value
barakeinav1 Jul 2, 2026
a8694aa
docs(contract): clarify overflow, re-vote, and capability-token behavior
barakeinav1 Jul 2, 2026
cb955fb
docs: correct attestation validity window (1 day, not 7) in comments …
barakeinav1 Jul 2, 2026
074a701
Merge branch 'main' into feat/auto-remove-launcher-hashes
barakeinav1 Jul 5, 2026
c435dc5
refactor(contract): collapse launcher timestamps to single last_used;…
barakeinav1 Jul 7, 2026
9759f11
style: rustfmt the enlarging_ttl test
barakeinav1 Jul 7, 2026
d329413
refactor(contract): add_or_refresh returns AddOutcome; sync design do…
barakeinav1 Jul 8, 2026
13fbc1f
Merge branch 'main' into feat/auto-remove-launcher-hashes
barakeinav1 Jul 9, 2026
6e3039e
docs(contract): compact refresh-on-use comment; TODO for 3.13.0 migra…
barakeinav1 Jul 9, 2026
096dfb1
docs(contract): drop broken public->private intra-doc link on AddOutcome
barakeinav1 Jul 9, 2026
d725003
Merge branch 'main' into feat/auto-remove-launcher-hashes
barakeinav1 Jul 9, 2026
e80673a
Merge remote-tracking branch 'origin/main' into feat/auto-remove-laun…
barakeinav1 Jul 12, 2026
07de77b
refactor(contract): address review nits on launcher image handling
barakeinav1 Jul 12, 2026
2aa024e
refactor(contract): log on is_expired overflow; fix stale 'added' tes…
barakeinav1 Jul 12, 2026
c95e32d
docs(contract): drop public->private intra-doc link on AllowedLaunche…
barakeinav1 Jul 13, 2026
e1d8955
Merge branch 'main' into feat/auto-remove-launcher-hashes
barakeinav1 Jul 15, 2026
04254ac
Merge remote-tracking branch 'origin/main' into feat/auto-remove-laun…
barakeinav1 Jul 20, 2026
37c0218
docs(contract): drop/shorten comments that restate the code
barakeinav1 Jul 21, 2026
eb593e5
test: add add_participant_no_expiry helper; trim two more comments
barakeinav1 Jul 22, 2026
df57fd8
Merge remote-tracking branch 'origin/main' into feat/auto-remove-laun…
barakeinav1 Jul 22, 2026
4485904
fix(contract): apply launcher expiry + refresh to WithConstraints mocks
barakeinav1 Jul 23, 2026
3fc93c7
Merge remote-tracking branch 'origin/main' into feat/auto-remove-laun…
barakeinav1 Jul 28, 2026
883dfad
Address claude[bot] review: docs, tests, and small cleanups
barakeinav1 Jul 28, 2026
797407a
test: add assert_matches exemption comments for PromiseOrValue
barakeinav1 Jul 28, 2026
6ffd125
test: mock-path participant gate — non-participant submission does no…
barakeinav1 Jul 28, 2026
1748925
Merge remote-tracking branch 'origin/main' into feat/auto-remove-laun…
barakeinav1 Jul 30, 2026
02a05c3
refactor(contract): store launcher expires_at; address review comments
barakeinav1 Jul 30, 2026
503a627
test(migration): cover the combined 3.13.0 migration path
barakeinav1 Jul 30, 2026
9cf1bd1
docs(design): update design doc to the expires_at model
barakeinav1 Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/contract/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ These functions require the caller to be a participant or candidate.
| `version()` | Returns the contract version. | `String` | TBD | TBD |
| `update_config(config: ConfigV1)` | Updates the contract configuration for `V1`. | `()` | TBD | TBD |
| `allowed_docker_image_hashes()` | Returns all currently allowed MPC Docker image hashes with their eviction expiry, newest first. | `Vec<AllowedMpcDockerImageHash>` | TBD | TBD |
| `allowed_launcher_image_hashes()` | Returns all currently allowed launcher image hashes. | `Vec<LauncherImageHash>` | TBD | TBD |
| `allowed_launcher_compose_hashes()` | Returns all currently allowed launcher compose hashes (derived from launcher + MPC image pairs). | `Vec<LauncherDockerComposeHash>` | TBD | TBD |
| `allowed_launcher_image_hashes()` | Returns the non-expired allowed launcher image hashes (the most-recently-used entry only when all are expired). | `Vec<LauncherImageHash>` | TBD | TBD |
| `allowed_launcher_compose_hashes()` | Returns the non-expired allowed launcher compose hashes (derived from launcher + MPC image pairs; the most-recently-used entry only when all are expired). | `Vec<LauncherDockerComposeHash>` | TBD | TBD |
| `launcher_hash_votes()` | Returns current launcher hash votes, showing each participant's vote. | `LauncherHashVotes` | TBD | TBD |
| `code_hash_votes()` | Returns current code hash votes, showing each participant's vote. | `CodeHashesVotes` | TBD | TBD |
| `allowed_os_measurements()` | Returns all currently allowed OS measurement sets. | `Vec<ContractExpectedMeasurements>` | TBD | TBD |
Expand Down
25 changes: 25 additions & 0 deletions crates/contract/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const DEFAULT_VERIFIER_TERA_GAS: u64 = 200;
/// Prepaid gas for the `resolve_verification` callback. Carries the bulk of the
/// post-DCAP work (allowlist match, RTMR3 replay, app-compose validation, store).
const DEFAULT_RESOLVE_VERIFICATION_TERA_GAS: u64 = 60;
/// Default TTL after which a launcher image hash unused by any participant is evicted.
pub(crate) const DEFAULT_LAUNCHER_HASH_UNUSED_TTL_SECONDS: u64 = 14 * 24 * 60 * 60; // 14 days
/// Prepaid gas for a `clean_expired_launcher_hashes` call.
const DEFAULT_CLEAN_EXPIRED_LAUNCHER_HASHES_TERA_GAS: u64 = 5;

/// Config for V2 of the contract.
#[near(serializers=[borsh, json])]
Expand Down Expand Up @@ -81,6 +85,10 @@ pub(crate) struct Config {
pub(crate) verifier_tera_gas: u64,
/// Prepaid gas for the `resolve_verification` callback.
pub(crate) resolve_verification_tera_gas: u64,
/// TTL after which a launcher image hash unused by any participant is evicted.
pub(crate) launcher_hash_unused_ttl_seconds: u64,
/// Prepaid gas for a `clean_expired_launcher_hashes` call.
pub(crate) clean_expired_launcher_hashes_tera_gas: u64,
}

impl Default for Config {
Expand Down Expand Up @@ -110,6 +118,23 @@ impl Default for Config {
DEFAULT_REMOVE_NON_PARTICIPANT_TEE_VERIFIER_VOTES_TERA_GAS,
verifier_tera_gas: DEFAULT_VERIFIER_TERA_GAS,
resolve_verification_tera_gas: DEFAULT_RESOLVE_VERIFICATION_TERA_GAS,
launcher_hash_unused_ttl_seconds: DEFAULT_LAUNCHER_HASH_UNUSED_TTL_SECONDS,
clean_expired_launcher_hashes_tera_gas: DEFAULT_CLEAN_EXPIRED_LAUNCHER_HASHES_TERA_GAS,
}
}
}

impl Config {
/// Invariant: a launcher hash backing a still-valid attestation must never expire,
/// so its unused-TTL must be at least the attestation validity window.
pub(crate) fn validate(&self) -> Result<(), &'static str> {
if self.launcher_hash_unused_ttl_seconds
< mpc_attestation::attestation::DEFAULT_EXPIRATION_DURATION_SECONDS
{
return Err(
"launcher_hash_unused_ttl_seconds must be >= DEFAULT_EXPIRATION_DURATION_SECONDS",
);
}
Ok(())
}
}
34 changes: 27 additions & 7 deletions crates/contract/src/dto_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,12 @@ impl IntoInterfaceType<dtos::ProposedUpdates> for &ProposedUpdates {
}
}

impl From<near_mpc_contract_interface::types::InitConfig> for Config {
fn from(config_ext: near_mpc_contract_interface::types::InitConfig) -> Self {
impl TryFrom<near_mpc_contract_interface::types::InitConfig> for Config {
type Error = &'static str;

fn try_from(
config_ext: near_mpc_contract_interface::types::InitConfig,
) -> Result<Self, Self::Error> {
let mut config = super::Config::default();

if let Some(v) = config_ext.key_event_timeout_blocks {
Expand Down Expand Up @@ -501,8 +505,15 @@ impl From<near_mpc_contract_interface::types::InitConfig> for Config {
if let Some(v) = config_ext.resolve_verification_tera_gas {
config.resolve_verification_tera_gas = v;
}
if let Some(v) = config_ext.launcher_hash_unused_ttl_seconds {
config.launcher_hash_unused_ttl_seconds = v;
}
if let Some(v) = config_ext.clean_expired_launcher_hashes_tera_gas {
config.clean_expired_launcher_hashes_tera_gas = v;
}

config
config.validate()?;
Ok(config)
}
}

Expand Down Expand Up @@ -533,13 +544,17 @@ impl From<&Config> for near_mpc_contract_interface::types::Config {
.remove_non_participant_tee_verifier_votes_tera_gas,
verifier_tera_gas: value.verifier_tera_gas,
resolve_verification_tera_gas: value.resolve_verification_tera_gas,
launcher_hash_unused_ttl_seconds: value.launcher_hash_unused_ttl_seconds,
clean_expired_launcher_hashes_tera_gas: value.clean_expired_launcher_hashes_tera_gas,
}
}
}

impl From<near_mpc_contract_interface::types::Config> for Config {
fn from(value: near_mpc_contract_interface::types::Config) -> Self {
Config {
impl TryFrom<near_mpc_contract_interface::types::Config> for Config {
type Error = &'static str;

fn try_from(value: near_mpc_contract_interface::types::Config) -> Result<Self, Self::Error> {
let config = Config {
key_event_timeout_blocks: value.key_event_timeout_blocks,
tee_upgrade_deadline_duration_seconds: value.tee_upgrade_deadline_duration_seconds,
contract_upgrade_deposit_tera_gas: value.contract_upgrade_deposit_tera_gas,
Expand All @@ -564,7 +579,12 @@ impl From<near_mpc_contract_interface::types::Config> for Config {
.remove_non_participant_tee_verifier_votes_tera_gas,
verifier_tera_gas: value.verifier_tera_gas,
resolve_verification_tera_gas: value.resolve_verification_tera_gas,
}
launcher_hash_unused_ttl_seconds: value.launcher_hash_unused_ttl_seconds,
clean_expired_launcher_hashes_tera_gas: value.clean_expired_launcher_hashes_tera_gas,
};

config.validate()?;
Ok(config)
}
}

Expand Down
Loading
Loading