Skip to content

Commit 6206719

Browse files
committed
[framework] Add native function to check protocol feature flags in Move
Adds sui::protocol_config::is_feature_enabled() to allow Move code to query protocol feature flags at runtime. This enables conditional logic and fallbacks based on protocol version capabilities.
1 parent b7d058b commit 6206719

File tree

7 files changed

+232
-0
lines changed

7 files changed

+232
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: Module `sui::protocol_config`
3+
---
4+
5+
This module provides access to protocol configuration feature flags.
6+
Feature flags control the availability of various protocol features and
7+
are enabled/disabled at specific protocol versions during epoch changes.
8+
9+
10+
- [Function `is_feature_enabled`](#sui_protocol_config_is_feature_enabled)
11+
- [Arguments](#@Arguments_0)
12+
- [Returns](#@Returns_1)
13+
- [Aborts](#@Aborts_2)
14+
- [Example (for framework use only)](#@Example_(for_framework_use_only)_3)
15+
16+
17+
<pre><code></code></pre>
18+
19+
20+
21+
<a name="sui_protocol_config_is_feature_enabled"></a>
22+
23+
## Function `is_feature_enabled`
24+
25+
Checks if a specific protocol feature flag is enabled.
26+
27+
Restricted to internal use within the sui-framework package only.
28+
If we need to use it in sui-system, we can add friend declarations.
29+
We should never need to expose this to user packages.
30+
31+
32+
<a name="@Arguments_0"></a>
33+
34+
### Arguments
35+
36+
* <code>feature_flag_name</code> - The name of the feature flag as bytes (e.g., b"enable_vdf")
37+
38+
39+
<a name="@Returns_1"></a>
40+
41+
### Returns
42+
43+
* <code><b>true</b></code> if the feature is enabled in the current protocol version
44+
* <code><b>false</b></code> if the feature is disabled
45+
46+
47+
<a name="@Aborts_2"></a>
48+
49+
### Aborts
50+
51+
* Error code 0: Feature flag name not found
52+
* Error code 1: Invalid feature flag name (not valid UTF-8)
53+
54+
55+
<a name="@Example_(for_framework_use_only)_3"></a>
56+
57+
### Example (for framework use only)
58+
59+
```move
60+
use sui::protocol_config;
61+
62+
if (protocol_config::is_feature_enabled(b"enable_accumulators")) {
63+
// Accumulators are available
64+
};
65+
```
66+
67+
68+
<pre><code><b>public</b>(<a href="../sui/package.md#sui_package">package</a>) <b>fun</b> <a href="../sui/protocol_config.md#sui_protocol_config_is_feature_enabled">is_feature_enabled</a>(feature_flag_name: &vector&lt;u8&gt;): bool
69+
</code></pre>
70+
71+
72+
73+
<details>
74+
<summary>Implementation</summary>
75+
76+
77+
<pre><code><b>public</b>(<a href="../sui/package.md#sui_package">package</a>) <b>native</b> <b>fun</b> <a href="../sui/protocol_config.md#sui_protocol_config_is_feature_enabled">is_feature_enabled</a>(feature_flag_name: &vector&lt;u8&gt;): bool;
78+
</code></pre>
79+
80+
81+
82+
</details>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Mysten Labs, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/// This module provides access to protocol configuration feature flags.
5+
/// Feature flags control the availability of various protocol features and
6+
/// are enabled/disabled at specific protocol versions during epoch changes.
7+
8+
module sui::protocol_config;
9+
10+
/// Checks if a specific protocol feature flag is enabled.
11+
///
12+
/// Restricted to internal use within the sui-framework package only.
13+
/// If we need to use it in sui-system, we can add friend declarations.
14+
/// We should never need to expose this to user packages.
15+
///
16+
/// # Arguments
17+
/// * `feature_flag_name` - The name of the feature flag as bytes (e.g., b"enable_vdf")
18+
///
19+
/// # Returns
20+
/// * `true` if the feature is enabled in the current protocol version
21+
/// * `false` if the feature is disabled
22+
///
23+
/// # Aborts
24+
/// * Error code 0: Feature flag name not found
25+
/// * Error code 1: Invalid feature flag name (not valid UTF-8)
26+
///
27+
/// # Example (for framework use only)
28+
/// ```move
29+
/// use sui::protocol_config;
30+
///
31+
/// if (protocol_config::is_feature_enabled(b"enable_accumulators")) {
32+
/// // Accumulators are available
33+
/// };
34+
/// ```
35+
public(package) native fun is_feature_enabled(feature_flag_name: &vector<u8>): bool;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) Mysten Labs, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#[test_only]
5+
module sui::protocol_config_tests;
6+
7+
use sui::protocol_config;
8+
9+
#[test]
10+
fun test_is_feature_enabled_true() {
11+
let is_enabled = protocol_config::is_feature_enabled(b"advance_epoch_start_time_in_safe_mode");
12+
assert!(is_enabled, 1);
13+
}
14+
15+
#[test]
16+
fun test_is_feature_enabled_false() {
17+
let is_enabled = protocol_config::is_feature_enabled(b"per_command_shared_object_transfer_rules");
18+
assert!(!is_enabled, 1);
19+
}
20+
21+
#[test]
22+
#[expected_failure(abort_code = 0)]
23+
fun test_is_feature_enabled_invalid_flag() {
24+
protocol_config::is_feature_enabled(b"nonexistent_feature_flag_xyz");
25+
}
26+
27+
#[test]
28+
#[expected_failure(abort_code = 1)]
29+
fun test_is_feature_enabled_invalid_utf8() {
30+
// Invalid UTF-8 sequence: 0xFF is not valid UTF-8
31+
let invalid_utf8 = vector[0xFF, 0xFE, 0xFD];
32+
protocol_config::is_feature_enabled(&invalid_utf8);
33+
}
113 Bytes
Binary file not shown.

crates/sui-framework/published_api.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,9 @@ ecvrf_verify
11051105
ed25519_verify
11061106
public fun
11071107
0x2::ed25519
1108+
is_feature_enabled
1109+
public(package) fun
1110+
0x2::protocol_config
11081111
hash_to_input
11091112
public fun
11101113
0x2::vdf

sui-execution/latest/sui-move-natives/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub mod event;
8282
mod funds_accumulator;
8383
mod object;
8484
pub mod object_runtime;
85+
mod protocol_config;
8586
mod random;
8687
pub mod test_scenario;
8788
mod test_utils;
@@ -1245,6 +1246,11 @@ pub fn all_natives(silent: bool, protocol_config: &ProtocolConfig) -> NativeFunc
12451246
"poseidon_bn254_internal",
12461247
make_native!(poseidon::poseidon_bn254_internal),
12471248
),
1249+
(
1250+
"protocol_config",
1251+
"is_feature_enabled",
1252+
make_native!(protocol_config::is_feature_enabled),
1253+
),
12481254
(
12491255
"vdf",
12501256
"vdf_verify_internal",
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright (c) Mysten Labs, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::get_extension;
5+
use crate::object_runtime::ObjectRuntime;
6+
use move_binary_format::errors::PartialVMResult;
7+
use move_vm_runtime::native_functions::NativeContext;
8+
use move_vm_types::{
9+
loaded_data::runtime_types::Type,
10+
natives::function::NativeResult,
11+
pop_arg,
12+
values::{Value, VectorRef},
13+
};
14+
use smallvec::smallvec;
15+
use std::collections::VecDeque;
16+
17+
pub const FEATURE_FLAG_NOT_FOUND_ERROR: u64 = 0;
18+
pub const INVALID_FEATURE_FLAG_NAME_ERROR: u64 = 1;
19+
20+
/***************************************************************************************************
21+
* native fun is_feature_enabled
22+
*
23+
* Implementation of the Move native function `protocol_config::is_feature_enabled(
24+
* feature_flag_name: &vector<u8>): bool`
25+
*
26+
* Checks if a protocol feature flag is enabled in the current protocol version.
27+
* Takes raw bytes for simplicity since this is internal framework use only.
28+
*
29+
* Gas cost: 0 (zero cost for framework-internal use)
30+
**************************************************************************************************/
31+
pub fn is_feature_enabled(
32+
context: &mut NativeContext,
33+
ty_args: Vec<Type>,
34+
mut args: VecDeque<Value>,
35+
) -> PartialVMResult<NativeResult> {
36+
debug_assert!(ty_args.is_empty());
37+
debug_assert!(args.len() == 1);
38+
39+
// Get the bytes directly - Move passes raw vector<u8>
40+
let feature_flag_name_bytes = pop_arg!(args, VectorRef);
41+
let bytes = feature_flag_name_bytes.as_bytes_ref();
42+
43+
// Validate that the feature flag name is valid UTF-8
44+
let feature_flag_name = match String::from_utf8(bytes.to_vec()) {
45+
Ok(s) => s,
46+
Err(_) => {
47+
// Invalid UTF-8 in feature flag name - abort with error
48+
return Ok(NativeResult::err(
49+
context.gas_used(),
50+
INVALID_FEATURE_FLAG_NAME_ERROR,
51+
));
52+
}
53+
};
54+
55+
let protocol_config = &get_extension!(context, ObjectRuntime)?.protocol_config;
56+
57+
// Use the auto-generated lookup_feature method to find the feature flag
58+
let is_enabled = match protocol_config.lookup_feature(feature_flag_name) {
59+
Some(value) => value,
60+
None => {
61+
// Feature flag not found - abort with error
62+
return Ok(NativeResult::err(
63+
context.gas_used(),
64+
FEATURE_FLAG_NOT_FOUND_ERROR,
65+
));
66+
}
67+
};
68+
69+
Ok(NativeResult::ok(
70+
context.gas_used(),
71+
smallvec![Value::bool(is_enabled)],
72+
))
73+
}

0 commit comments

Comments
 (0)