Skip to content

Commit 0c7a0ae

Browse files
[randomness] Add entry function annotation (aptos-labs#12134)
Adds `#[randomness]` annotation which should be used to mark entry functions which use randomness. For example ``` #[randomness] entry fun foo() { let _ = randomness::u64_integer(); } ``` The attribute has the following semantics: 1. It can only be used for entry functions. Using it on other type of functions is not allowed. 2. It can be used on entry functions even if they don't use randomness. 3. If an entry function doesn't have an annotation, but uses randomness, the randomness call fails at runtime.
1 parent 2e8eedc commit 0c7a0ae

File tree

28 files changed

+508
-81
lines changed

28 files changed

+508
-81
lines changed

aptos-move/aptos-vm/src/aptos_vm.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ use crate::{
2020
sharded_block_executor::{executor_client::ExecutorClient, ShardedBlockExecutor},
2121
system_module_names::*,
2222
transaction_metadata::TransactionMetadata,
23-
transaction_validation, verifier, VMExecutor, VMValidator,
23+
transaction_validation, verifier,
24+
verifier::randomness::has_randomness_attribute,
25+
VMExecutor, VMValidator,
2426
};
2527
use anyhow::anyhow;
2628
use aptos_block_executor::txn_commit_hook::NoOpTransactionCommitHook;
2729
use aptos_crypto::HashValue;
2830
use aptos_framework::{
29-
natives::{code::PublishRequest, transaction_context::NativeTransactionContext},
31+
natives::{code::PublishRequest, randomness::RandomnessContext},
3032
RuntimeModuleMetadataV1,
3133
};
3234
use aptos_gas_algebra::{Gas, GasQuantity, NumBytes, Octa};
@@ -733,6 +735,7 @@ impl AptosVM {
733735

734736
fn validate_and_execute_entry_function(
735737
&self,
738+
resolver: &impl AptosMoveResolver,
736739
session: &mut SessionExt,
737740
gas_meter: &mut impl AptosGasMeter,
738741
traversal_context: &mut TraversalContext,
@@ -752,26 +755,27 @@ impl AptosVM {
752755
)])?;
753756
}
754757

755-
let is_friend_or_private = session.load_function_def_is_friend_or_private(
758+
let (function, is_friend_or_private) = session.load_function_and_is_friend_or_private_def(
756759
entry_fn.module(),
757760
entry_fn.function(),
758761
entry_fn.ty_args(),
759762
)?;
760-
if is_friend_or_private {
763+
764+
if is_friend_or_private && has_randomness_attribute(resolver, session, entry_fn)? {
761765
let txn_context = session
762766
.get_native_extensions()
763-
.get_mut::<NativeTransactionContext>();
764-
txn_context.set_is_friend_or_private_entry_func();
767+
.get_mut::<RandomnessContext>();
768+
txn_context.mark_unbiasable();
765769
}
766770

767-
let function =
768-
session.load_function(entry_fn.module(), entry_fn.function(), entry_fn.ty_args())?;
771+
let struct_constructors_enabled =
772+
self.features().is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS);
769773
let args = verifier::transaction_arg_validation::validate_combine_signer_and_txn_args(
770774
session,
771775
senders,
772776
entry_fn.args().to_vec(),
773777
&function,
774-
self.features().is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS),
778+
struct_constructors_enabled,
775779
)?;
776780
session.execute_entry_function(
777781
entry_fn.module(),
@@ -820,6 +824,7 @@ impl AptosVM {
820824
TransactionPayload::EntryFunction(entry_fn) => {
821825
session.execute(|session| {
822826
self.validate_and_execute_entry_function(
827+
resolver,
823828
session,
824829
gas_meter,
825830
traversal_context,
@@ -921,6 +926,7 @@ impl AptosVM {
921926
aptos_try!({
922927
return_on_failure!(session.execute(|session| self
923928
.execute_multisig_entry_function(
929+
resolver,
924930
session,
925931
gas_meter,
926932
traversal_context,
@@ -1042,6 +1048,7 @@ impl AptosVM {
10421048
MultisigTransactionPayload::EntryFunction(entry_function) => {
10431049
session.execute(|session| {
10441050
self.execute_multisig_entry_function(
1051+
resolver,
10451052
session,
10461053
gas_meter,
10471054
traversal_context,
@@ -1142,6 +1149,7 @@ impl AptosVM {
11421149

11431150
fn execute_multisig_entry_function(
11441151
&self,
1152+
resolver: &impl AptosMoveResolver,
11451153
session: &mut SessionExt,
11461154
gas_meter: &mut impl AptosGasMeter,
11471155
traversal_context: &mut TraversalContext,
@@ -1152,6 +1160,7 @@ impl AptosVM {
11521160
// If txn args are not valid, we'd still consider the transaction as executed but
11531161
// failed. This is primarily because it's unrecoverable at this point.
11541162
self.validate_and_execute_entry_function(
1163+
resolver,
11551164
session,
11561165
gas_meter,
11571166
traversal_context,

aptos-move/aptos-vm/src/natives.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,11 @@ fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) {
227227

228228
exts.add(NativeTableContext::new([0u8; 32], &*DUMMY_RESOLVER));
229229
exts.add(NativeCodeContext::default());
230-
let mut txn_context = NativeTransactionContext::new(vec![1], vec![1], ChainId::test().id());
231-
txn_context.set_is_friend_or_private_entry_func();
232-
exts.add(txn_context); // We use the testing environment chain ID here
230+
exts.add(NativeTransactionContext::new(
231+
vec![1],
232+
vec![1],
233+
ChainId::test().id(),
234+
));
233235
exts.add(NativeAggregatorContext::new(
234236
[0; 32],
235237
&*DUMMY_RESOLVER,
@@ -238,5 +240,8 @@ fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) {
238240
exts.add(NativeRistrettoPointContext::new());
239241
exts.add(AlgebraContext::new());
240242
exts.add(NativeEventContext::default());
241-
exts.add(RandomnessContext::new());
243+
244+
let mut randomness_ctx = RandomnessContext::new();
245+
randomness_ctx.mark_unbiasable();
246+
exts.add(randomness_ctx);
242247
}

aptos-move/aptos-vm/src/verifier/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33
pub(crate) mod event_validation;
44
pub(crate) mod module_init;
5+
pub(crate) mod randomness;
56
pub(crate) mod resource_groups;
67
pub mod transaction_arg_validation;
78
pub(crate) mod view_function;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright © Aptos Foundation
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::move_vm_ext::{AptosMoveResolver, SessionExt};
5+
use aptos_types::transaction::EntryFunction;
6+
use move_binary_format::errors::VMResult;
7+
8+
/// Returns true if function has an attribute that it uses randomness.
9+
pub(crate) fn has_randomness_attribute(
10+
resolver: &impl AptosMoveResolver,
11+
session: &mut SessionExt,
12+
entry_fn: &EntryFunction,
13+
) -> VMResult<bool> {
14+
let module = session
15+
.get_move_vm()
16+
.load_module(entry_fn.module(), resolver)?;
17+
let metadata = aptos_framework::get_metadata_from_compiled_module(&module);
18+
if let Some(metadata) = metadata {
19+
Ok(metadata
20+
.fun_attributes
21+
.get(entry_fn.function().as_str())
22+
.map(|attrs| attrs.iter().any(|attr| attr.is_randomness()))
23+
.unwrap_or(false))
24+
} else {
25+
Ok(false)
26+
}
27+
}

aptos-move/e2e-move-tests/src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mod object_code_deployment;
3535
mod offer_rotation_capability;
3636
mod offer_signer_capability;
3737
mod per_category_gas_limits;
38+
mod randomness_test_and_abort;
3839
mod resource_groups;
3940
mod rotate_auth_key;
4041
mod scripts;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "randomness_invalid_test_non_entry"
3+
version = "0.0.0"
4+
5+
[dependencies]
6+
AptosFramework = { local = "../../../../../framework/aptos-framework" }
7+
AptosStdlib = { local = "../../../../../framework/aptos-stdlib" }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module 0x1::invalid {
2+
#[randomness]
3+
public entry fun foo() {
4+
// Do nothing.
5+
}
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "randomness_invalid_test_public_entry"
3+
version = "0.0.0"
4+
5+
[dependencies]
6+
AptosFramework = { local = "../../../../../framework/aptos-framework" }
7+
AptosStdlib = { local = "../../../../../framework/aptos-stdlib" }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module 0x1::invalid {
2+
#[randomness]
3+
public fun foo() {
4+
// Do nothing.
5+
}
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "randomness_test"
3+
version = "0.0.0"
4+
5+
[dependencies]
6+
AptosFramework = { local = "../../../../../framework/aptos-framework" }
7+
AptosStdlib = { local = "../../../../../framework/aptos-stdlib" }

0 commit comments

Comments
 (0)