Skip to content

Commit

Permalink
Use native implementation to optimize object derived address computation
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-aptos committed Apr 2, 2024
1 parent 3eb19c4 commit d6a53a8
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ crate::gas_schedule::macros::define_gas_parameters!(
[aggregator_v2_string_concat_per_byte: InternalGasPerByte, { 12.. =>"aggregator_v2.string_concat.per_byte" }, 3],

[object_exists_at_base: InternalGas, { 7.. => "object.exists_at.base" }, 919],
// Based on SHA3-256's cost
[object_user_derived_address_base: InternalGas, { 16.. => "object.user_derived_address.base" }, 14704],

Check warning on line 295 in aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs#L293-L295

Added lines #L293 - L295 were not covered by tests
// These are dummy value, they copied from storage gas in aptos-core/aptos-vm/src/aptos_vm_impl.rs
[object_exists_at_per_byte_loaded: InternalGasPerByte, { 7.. => "object.exists_at.per_byte_loaded" }, 183],
[object_exists_at_per_item_loaded: InternalGas, { 7.. => "object.exists_at.per_item_loaded" }, 1470],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ pub enum FeatureFlag {
MaxObjectNestingCheck,
KeylessAccountsWithPasskeys,
MultisigV2Enhancement,
ObjectNativeDerivedAddress,
}

fn generate_features_blob(writer: &CodeWriter, data: &[u64]) {
Expand Down Expand Up @@ -266,6 +267,9 @@ impl From<FeatureFlag> for AptosFeatureFlag {
AptosFeatureFlag::KEYLESS_ACCOUNTS_WITH_PASSKEYS
},
FeatureFlag::MultisigV2Enhancement => AptosFeatureFlag::MULTISIG_V2_ENHANCEMENT,
FeatureFlag::ObjectNativeDerivedAddress => {
AptosFeatureFlag::OBJECT_NATIVE_DERIVED_ADDRESS
},
}
}
}
Expand Down Expand Up @@ -355,6 +359,9 @@ impl From<AptosFeatureFlag> for FeatureFlag {
FeatureFlag::KeylessAccountsWithPasskeys
},
AptosFeatureFlag::MULTISIG_V2_ENHANCEMENT => FeatureFlag::MultisigV2Enhancement,
AptosFeatureFlag::OBJECT_NATIVE_DERIVED_ADDRESS => {
FeatureFlag::ObjectNativeDerivedAddress
},
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions aptos-move/aptos-vm/src/move_vm_ext/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use aptos_framework::natives::{
code::NativeCodeContext,
cryptography::{algebra::AlgebraContext, ristretto255_point::NativeRistrettoPointContext},
event::NativeEventContext,
object::NativeObjectContext,
randomness::RandomnessContext,
state_storage::NativeStateStorageContext,
transaction_context::NativeTransactionContext,
Expand Down Expand Up @@ -211,6 +212,7 @@ impl MoveVmExt {
extensions.add(NativeCodeContext::default());
extensions.add(NativeStateStorageContext::new(resolver));
extensions.add(NativeEventContext::default());
extensions.add(NativeObjectContext::default());

Check warning on line 215 in aptos-move/aptos-vm/src/move_vm_ext/vm.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-vm/src/move_vm_ext/vm.rs#L215

Added line #L215 was not covered by tests

// The VM code loader has bugs around module upgrade. After a module upgrade, the internal
// cache needs to be flushed to work around those bugs.
Expand Down
2 changes: 2 additions & 0 deletions aptos-move/aptos-vm/src/natives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ pub fn configure_for_unit_test() {

#[cfg(feature = "testing")]
fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) {
use aptos_framework::natives::object::NativeObjectContext;
use aptos_table_natives::NativeTableContext;

exts.add(NativeTableContext::new([0u8; 32], &*DUMMY_RESOLVER));
Expand All @@ -240,6 +241,7 @@ fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) {
exts.add(NativeRistrettoPointContext::new());
exts.add(AlgebraContext::new());
exts.add(NativeEventContext::default());
exts.add(NativeObjectContext::default());

let mut randomness_ctx = RandomnessContext::new();
randomness_ctx.mark_unbiasable();
Expand Down
35 changes: 31 additions & 4 deletions aptos-move/framework/aptos-framework/doc/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ make it so that a reference to a global object can be returned from a function.
- [Function `is_object`](#0x1_object_is_object)
- [Function `object_exists`](#0x1_object_object_exists)
- [Function `create_object_address`](#0x1_object_create_object_address)
- [Function `create_user_derived_object_address_impl`](#0x1_object_create_user_derived_object_address_impl)
- [Function `create_user_derived_object_address`](#0x1_object_create_user_derived_object_address)
- [Function `create_guid_object_address`](#0x1_object_create_guid_object_address)
- [Function `exists_at`](#0x1_object_exists_at)
Expand Down Expand Up @@ -801,6 +802,28 @@ Derives an object address from source material: sha3_256([creator address | seed



</details>

<a id="0x1_object_create_user_derived_object_address_impl"></a>

## Function `create_user_derived_object_address_impl`



<pre><code><b>public</b> <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object_address_impl">create_user_derived_object_address_impl</a>(source: <b>address</b>, derive_from: <b>address</b>): <b>address</b>
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>native</b> <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object_address_impl">create_user_derived_object_address_impl</a>(source: <b>address</b>, derive_from: <b>address</b>): <b>address</b>;
</code></pre>



</details>

<a id="0x1_object_create_user_derived_object_address"></a>
Expand All @@ -820,10 +843,14 @@ Derives an object address from the source address and an object: sha3_256([sourc


<pre><code><b>public</b> <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object_address">create_user_derived_object_address</a>(source: <b>address</b>, derive_from: <b>address</b>): <b>address</b> {
<b>let</b> bytes = <a href="../../aptos-stdlib/../move-stdlib/doc/bcs.md#0x1_bcs_to_bytes">bcs::to_bytes</a>(&source);
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_append">vector::append</a>(&<b>mut</b> bytes, <a href="../../aptos-stdlib/../move-stdlib/doc/bcs.md#0x1_bcs_to_bytes">bcs::to_bytes</a>(&derive_from));
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_push_back">vector::push_back</a>(&<b>mut</b> bytes, <a href="object.md#0x1_object_OBJECT_DERIVED_SCHEME">OBJECT_DERIVED_SCHEME</a>);
<a href="../../aptos-stdlib/doc/from_bcs.md#0x1_from_bcs_to_address">from_bcs::to_address</a>(<a href="../../aptos-stdlib/../move-stdlib/doc/hash.md#0x1_hash_sha3_256">hash::sha3_256</a>(bytes))
<b>if</b> (std::features::object_native_derived_address_enabled()) {
<a href="object.md#0x1_object_create_user_derived_object_address_impl">create_user_derived_object_address_impl</a>(source, derive_from)
} <b>else</b> {
<b>let</b> bytes = <a href="../../aptos-stdlib/../move-stdlib/doc/bcs.md#0x1_bcs_to_bytes">bcs::to_bytes</a>(&source);
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_append">vector::append</a>(&<b>mut</b> bytes, <a href="../../aptos-stdlib/../move-stdlib/doc/bcs.md#0x1_bcs_to_bytes">bcs::to_bytes</a>(&derive_from));
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_push_back">vector::push_back</a>(&<b>mut</b> bytes, <a href="object.md#0x1_object_OBJECT_DERIVED_SCHEME">OBJECT_DERIVED_SCHEME</a>);
<a href="../../aptos-stdlib/doc/from_bcs.md#0x1_from_bcs_to_address">from_bcs::to_address</a>(<a href="../../aptos-stdlib/../move-stdlib/doc/hash.md#0x1_hash_sha3_256">hash::sha3_256</a>(bytes))
}
}
</code></pre>

Expand Down
38 changes: 34 additions & 4 deletions aptos-move/framework/aptos-framework/sources/object.move
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,18 @@ module aptos_framework::object {
from_bcs::to_address(hash::sha3_256(bytes))
}

public native fun create_user_derived_object_address_impl(source: address, derive_from: address): address;

/// Derives an object address from the source address and an object: sha3_256([source | object addr | 0xFC]).
public fun create_user_derived_object_address(source: address, derive_from: address): address {
let bytes = bcs::to_bytes(&source);
vector::append(&mut bytes, bcs::to_bytes(&derive_from));
vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME);
from_bcs::to_address(hash::sha3_256(bytes))
if (std::features::object_native_derived_address_enabled()) {
create_user_derived_object_address_impl(source, derive_from)
} else {
let bytes = bcs::to_bytes(&source);
vector::append(&mut bytes, bcs::to_bytes(&derive_from));
vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME);
from_bcs::to_address(hash::sha3_256(bytes))
}
}

/// Derives an object from an Account GUID.
Expand Down Expand Up @@ -766,6 +772,30 @@ module aptos_framework::object {
assert!(auid1 == auid2, 0);
}

#[test(fx = @std)]
fun test_correct_derived_object_address(fx: signer) {
use std::features;
let feature = features::get_object_native_derived_address_feature();

let source = @0x12345;
let derive_from = @0x7890;

features::change_feature_flags_for_testing(&fx, vector[], vector[feature]);
let in_move = object::create_user_derived_object_address(source, derive_from);

features::change_feature_flags_for_testing(&fx, vector[feature], vector[]);
let in_native = object::create_user_derived_object_address(source, derive_from);

assert!(in_move == in_native, 0);

let bytes = bcs::to_bytes(&source);
vector::append(&mut bytes, bcs::to_bytes(&derive_from));
vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME);
let directly = from_bcs::to_address(hash::sha3_256(bytes));

assert!(directly == in_native, 0);
}

#[test(creator = @0x123)]
fun test_burn_and_unburn(creator: &signer) acquires ObjectCore, TombStone {
let (hero_constructor, hero) = create_hero(creator);
Expand Down
57 changes: 57 additions & 0 deletions aptos-move/framework/move-stdlib/doc/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ return true.
- [Function `keyless_accounts_with_passkeys_feature_enabled`](#0x1_features_keyless_accounts_with_passkeys_feature_enabled)
- [Function `get_multisig_v2_enhancement_feature`](#0x1_features_get_multisig_v2_enhancement_feature)
- [Function `multisig_v2_enhancement_feature_enabled`](#0x1_features_multisig_v2_enhancement_feature_enabled)
- [Function `get_object_native_derived_address_feature`](#0x1_features_get_object_native_derived_address_feature)
- [Function `object_native_derived_address_enabled`](#0x1_features_object_native_derived_address_enabled)
- [Function `change_feature_flags`](#0x1_features_change_feature_flags)
- [Function `change_feature_flags_internal`](#0x1_features_change_feature_flags_internal)
- [Function `change_feature_flags_for_next_epoch`](#0x1_features_change_feature_flags_for_next_epoch)
Expand Down Expand Up @@ -576,6 +578,15 @@ Whether deploying to objects is enabled.



<a id="0x1_features_OBJECT_NATIVE_DERIVED_ADDRESS"></a>



<pre><code><b>const</b> <a href="features.md#0x1_features_OBJECT_NATIVE_DERIVED_ADDRESS">OBJECT_NATIVE_DERIVED_ADDRESS</a>: u64 = 56;
</code></pre>



<a id="0x1_features_OPERATOR_BENEFICIARY_CHANGE"></a>

Whether allow changing beneficiaries for operators.
Expand Down Expand Up @@ -2423,6 +2434,52 @@ Lifetime: transient



</details>

<a id="0x1_features_get_object_native_derived_address_feature"></a>

## Function `get_object_native_derived_address_feature`



<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_get_object_native_derived_address_feature">get_object_native_derived_address_feature</a>(): u64
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_get_object_native_derived_address_feature">get_object_native_derived_address_feature</a>(): u64 { <a href="features.md#0x1_features_OBJECT_NATIVE_DERIVED_ADDRESS">OBJECT_NATIVE_DERIVED_ADDRESS</a> }
</code></pre>



</details>

<a id="0x1_features_object_native_derived_address_enabled"></a>

## Function `object_native_derived_address_enabled`



<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_object_native_derived_address_enabled">object_native_derived_address_enabled</a>(): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_object_native_derived_address_enabled">object_native_derived_address_enabled</a>(): bool <b>acquires</b> <a href="features.md#0x1_features_Features">Features</a> {
<a href="features.md#0x1_features_is_enabled">is_enabled</a>(<a href="features.md#0x1_features_OBJECT_NATIVE_DERIVED_ADDRESS">OBJECT_NATIVE_DERIVED_ADDRESS</a>)
}
</code></pre>



</details>

<a id="0x1_features_change_feature_flags"></a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,13 @@ module std::features {
is_enabled(MULTISIG_V2_ENHANCEMENT)
}

const OBJECT_NATIVE_DERIVED_ADDRESS: u64 = 56;

public fun get_object_native_derived_address_feature(): u64 { OBJECT_NATIVE_DERIVED_ADDRESS }

public fun object_native_derived_address_enabled(): bool acquires Features {
is_enabled(OBJECT_NATIVE_DERIVED_ADDRESS)
}

// ============================================================================================
// Feature Flag Implementation
Expand Down
57 changes: 55 additions & 2 deletions aptos-move/framework/src/natives/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use aptos_native_interface::{
safely_assert_eq, safely_pop_arg, RawSafeNative, SafeNativeBuilder, SafeNativeContext,
SafeNativeResult,
};
use aptos_types::transaction::authenticator::AuthenticationKey;
use better_any::{Tid, TidAble};
use move_core_types::{
account_address::AccountAddress,
gas_algebra::{InternalGas, InternalGasPerByte},
Expand All @@ -16,7 +18,21 @@ use move_vm_types::{
loaded_data::runtime_types::Type, natives::function::PartialVMError, values::Value,
};
use smallvec::{smallvec, SmallVec};
use std::collections::VecDeque;
use std::{
cell::RefCell,
collections::{HashMap, VecDeque},
};

/// Cached emitted module events.
#[derive(Default, Tid)]
pub struct NativeObjectContext {
// TODO - if further optimizations is important, we can consider if:
// - caching all (or just some derive_from) locations is useful
// - if it is faster to use BTreeMap or HashMap, given the lenghts of the addresses
// - if it is worth moving to native/caching other address deriving as well
derived_from_object_addresses:
RefCell<HashMap<(AccountAddress, AccountAddress), AccountAddress>>,
}

/***************************************************************************************************
* native exists_at<T>
Expand Down Expand Up @@ -60,14 +76,51 @@ fn native_exists_at(
Ok(smallvec![Value::bool(exists)])
}

/***************************************************************************************************
* native fun create_user_derived_object_address_impl
*
* gas cost: base_cost
*
**************************************************************************************************/
fn native_create_user_derived_object_address_impl(
context: &mut SafeNativeContext,
ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
debug_assert!(ty_args.is_empty());
debug_assert!(args.len() == 2);

Check warning on line 91 in aptos-move/framework/src/natives/object.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/object.rs#L85-L91

Added lines #L85 - L91 were not covered by tests

context.charge(OBJECT_USER_DERIVED_ADDRESS_BASE)?;

Check warning on line 93 in aptos-move/framework/src/natives/object.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/object.rs#L93

Added line #L93 was not covered by tests

let object_context = context.extensions().get::<NativeObjectContext>();
let derive_from = safely_pop_arg!(args, AccountAddress);
let source = safely_pop_arg!(args, AccountAddress);

Check warning on line 97 in aptos-move/framework/src/natives/object.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/object.rs#L95-L97

Added lines #L95 - L97 were not covered by tests

let derived_address = *object_context
.derived_from_object_addresses
.borrow_mut()
.entry((derive_from, source))
.or_insert_with(|| {
AuthenticationKey::object_address_from_object(&source, &derive_from).account_address()
});

Ok(smallvec![Value::address(derived_address)])
}

Check warning on line 108 in aptos-move/framework/src/natives/object.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/object.rs#L99-L108

Added lines #L99 - L108 were not covered by tests

/***************************************************************************************************
* module
*
**************************************************************************************************/
pub fn make_all(
builder: &SafeNativeBuilder,
) -> impl Iterator<Item = (String, NativeFunction)> + '_ {
let natives = [("exists_at", native_exists_at as RawSafeNative)];
let natives = [
("exists_at", native_exists_at as RawSafeNative),
(
"create_user_derived_object_address_impl",
native_create_user_derived_object_address_impl,
),
];

builder.make_named_natives(natives)
}
13 changes: 4 additions & 9 deletions aptos-move/framework/src/natives/transaction_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use aptos_native_interface::{
};
use aptos_types::transaction::authenticator::AuthenticationKey;
use better_any::{Tid, TidAble};
use move_core_types::account_address::AccountAddress;
use move_vm_runtime::native_functions::NativeFunction;
use move_vm_types::{loaded_data::runtime_types::Type, values::Value};
use smallvec::{smallvec, SmallVec};
Expand Down Expand Up @@ -80,16 +79,12 @@ fn native_generate_unique_address(
.get_mut::<NativeTransactionContext>();
transaction_context.auid_counter += 1;

let hash_vec = AuthenticationKey::auid(
let auid = AuthenticationKey::auid(

Check warning on line 82 in aptos-move/framework/src/natives/transaction_context.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/transaction_context.rs#L82

Added line #L82 was not covered by tests
transaction_context.txn_hash.clone(),
transaction_context.auid_counter,
);
Ok(smallvec![Value::address(AccountAddress::new(
hash_vec
.to_vec()
.try_into()
.expect("Unable to convert hash vector into [u8]")
))])
)
.account_address();
Ok(smallvec![Value::address(auid)])

Check warning on line 87 in aptos-move/framework/src/natives/transaction_context.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/transaction_context.rs#L85-L87

Added lines #L85 - L87 were not covered by tests
}

/***************************************************************************************************
Expand Down
Loading

0 comments on commit d6a53a8

Please sign in to comment.