-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Concurrent FungibleAsset balance #11183
Conversation
⏱️ 2h 6m total CI duration on this PR
🚨 1 job on the last run was significantly faster/slower than expected
|
Current dependencies on/for this PR:
This stack of pull requests is managed by Graphite. |
This issue is stale because it has been open 45 days with no activity. Remove the |
struct DepositEventV2 has drop, store { | ||
metadata_address: address, | ||
amount: u64, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct DepositEventV2 has drop, store { | |
metadata_address: address, | |
amount: u64, | |
} | |
struct Deposit has drop, store { | |
metadata: address, | |
amount: u64, | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's agree on the naming convention.hah
642b937
to
21cdef5
Compare
@@ -111,6 +111,13 @@ module aptos_framework::fungible_asset { | |||
frozen: bool, | |||
} | |||
|
|||
#[resource_group_member(group = aptos_framework::object::ObjectGroup)] | |||
/// The store object that holds concurrent fungible asset balance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: . is missing
btw, in Move, can we place annotation after the docstring?
@@ -155,6 +162,14 @@ module aptos_framework::fungible_asset { | |||
frozen: bool, | |||
} | |||
|
|||
fun default_to_concurrent_fungible_supply(): bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add these functions? To me features::concurrent_fungible_assets_enabled()
seems easier to parse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in case we want to add multiple flags, to separately decide which path to take
@@ -289,6 +304,12 @@ module aptos_framework::fungible_asset { | |||
exists<FungibleStore>(store) | |||
} | |||
|
|||
#[view] | |||
/// Return whether the provided address has a store initialized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the comment is wrong, also what is store
?
public fun balance<T: key>(store: Object<T>): u64 acquires FungibleStore, ConcurrentFungibleBalance { | ||
let store_addr = object::object_address(&store); | ||
if (concurrent_fungible_balance_exists(store_addr)) { | ||
let balance = borrow_global<ConcurrentFungibleBalance>(store_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually prefer
let balance = &borrow_global<ConcurrentFungibleBalance>(store_addr).balance;
aggregator_v2::read(balance)
because balance.balance
looks super weird. Either things need to be called differently, or we can access the field directly when we borrow global
if (store_exists(object::object_address(&store))) { | ||
public fun balance<T: key>(store: Object<T>): u64 acquires FungibleStore, ConcurrentFungibleBalance { | ||
let store_addr = object::object_address(&store); | ||
if (concurrent_fungible_balance_exists(store_addr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check here that && store_exists(store_addr)
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be part of concurrent_fungible_balance_exists
function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that should be a general invariant, but not sure we want to/need to explicitly check it here?
@@ -386,22 +424,23 @@ module aptos_framework::fungible_asset { | |||
event::destroy_handle(deposit_events); | |||
event::destroy_handle(withdraw_events); | |||
event::destroy_handle(frozen_events); | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove this newline?
aggregator_v2::add(&mut balance.balance, amount); | ||
} else { | ||
let store = borrow_global_mut<FungibleStore>(store_addr); | ||
store.balance = store.balance + amount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't care about overflows? Interesting, why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let store = borrow_global_mut<FungibleStore>(store_addr); | ||
store.balance = store.balance + amount; | ||
|
||
if (concurrent_fungible_balance_exists(store_addr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto about checking store exists and avoiding balance.balance
let balance = borrow_global_mut<ConcurrentFungibleBalance>(store_addr); | ||
assert!(aggregator_v2::try_sub(&mut balance.balance, amount), error::invalid_argument(EINSUFFICIENT_BALANCE)); | ||
} else { | ||
let store = borrow_global_mut<FungibleStore>(store_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't check store exists here, is the check somewhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. delegate to caller
let store_object_address = object::address_from_extend_ref(ref); | ||
let store_object_signer = object::generate_signer_for_extending(ref); | ||
assert!(features::concurrent_fungible_assets_enabled(), error::invalid_argument(ECONCURRENT_SUPPLY_NOT_ENABLED)); | ||
assert!(exists<FungibleStore>(store_object_address), error::not_found(ESTORE_NOT_FOUND)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reuse store_exists
?
@@ -656,6 +708,25 @@ module aptos_framework::fungible_asset { | |||
move_to(&metadata_object_signer, supply); | |||
} | |||
|
|||
public fun upgrade_store_to_concurrent( | |||
ref: &ExtendRef, |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|
||
<<<<<<< HEAD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@@ -11,18 +11,32 @@ metadata object can be any object that equipped with <code><a href="fungible_ass | |||
- [Resource `ConcurrentSupply`](#0x1_fungible_asset_ConcurrentSupply) | |||
- [Resource `Metadata`](#0x1_fungible_asset_Metadata) | |||
- [Resource `FungibleStore`](#0x1_fungible_asset_FungibleStore) | |||
<<<<<<< HEAD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rerun>?
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
aggregator_v2::add(&mut balance.balance, amount); | ||
} else { | ||
let store = borrow_global_mut<FungibleStore>(store_addr); | ||
store.balance = store.balance + amount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let balance = borrow_global_mut<ConcurrentFungibleBalance>(store_addr); | ||
assert!(aggregator_v2::try_sub(&mut balance.balance, amount), error::invalid_argument(EINSUFFICIENT_BALANCE)); | ||
} else { | ||
let store = borrow_global_mut<FungibleStore>(store_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. delegate to caller
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #11183 +/- ##
=========================================
- Coverage 33.1% 33.1% -0.1%
=========================================
Files 1753 1754 +1
Lines 337871 337934 +63
=========================================
- Hits 112000 111959 -41
- Misses 225871 225975 +104 ☔ View full report in Codecov by Sentry. |
195429b
to
b1f5998
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about strategic inlining to reduce gas bloat?
A lot of these helper functions can easily be inlined, and failing to optimize them here will have adverse consequences downstream because they are inner calls for lots of call flows across the framework
(Each function call comes with a fixed gas cost due to stack allocation, but inline functions are effectively free because they are essentially copy-pasted at compile time)
|
||
fun default_to_concurrent_fungible_supply(): bool { | ||
features::concurrent_fungible_assets_enabled() | ||
} | ||
|
||
fun default_to_concurrent_fungible_balance(): bool { | ||
features::concurrent_fungible_assets_enabled() | ||
} | ||
|
||
fun auto_upgrade_to_concurrent_fungible_balance(): bool { | ||
features::concurrent_fungible_assets_enabled() | ||
} |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
#[view] | ||
/// Return whether the provided address has a concurrent fungible balance initialized, | ||
/// at the fungible store address. | ||
public fun concurrent_fungible_balance_exists(store: address): bool { | ||
exists<ConcurrentFungibleBalance>(store) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[view] | |
/// Return whether the provided address has a concurrent fungible balance initialized, | |
/// at the fungible store address. | |
public fun concurrent_fungible_balance_exists(store: address): bool { | |
exists<ConcurrentFungibleBalance>(store) | |
} | |
#[view] | |
/// Return whether the provided address has a concurrent fungible balance initialized, | |
/// at the fungible store address. | |
public fun concurrent_fungible_balance_exists(store: address): bool { | |
exists<ConcurrentFungibleBalance>(store) | |
} | |
inline fun concurrent_fungible_balance_exists_inline(store: address): bool { | |
exists<ConcurrentFungibleBalance>(store) | |
} | |
inline fun store_exists_inline(store: address): bool { | |
exists<FungibleStore>(store) | |
} |
How about adding inline versions here as well, which can be used in control flow statements?
if (concurrent_fungible_balance_exists(store_addr)) { | ||
let balance_resource = borrow_global<ConcurrentFungibleBalance>(store_addr); | ||
aggregator_v2::read(&balance_resource.balance) | ||
} else if (store_exists(store_addr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (concurrent_fungible_balance_exists(store_addr)) { | |
let balance_resource = borrow_global<ConcurrentFungibleBalance>(store_addr); | |
aggregator_v2::read(&balance_resource.balance) | |
} else if (store_exists(store_addr)) { | |
if (concurrent_fungible_balance_exists_inline(store_addr)) { | |
let balance_resource = borrow_global<ConcurrentFungibleBalance>(store_addr); | |
aggregator_v2::read(&balance_resource.balance) | |
} else if (store_exists_inline(store_addr)) { |
To reduce gas bloat
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are so paranoid, hah
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alnoki has a point, we have many single-block functions, which are extra costs and extra performance losses. Why not inline if we could
|
||
if (concurrent_fungible_balance_exists(addr)) { | ||
let ConcurrentFungibleBalance { balance } = move_from<ConcurrentFungibleBalance>(addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (concurrent_fungible_balance_exists(addr)) { | |
let ConcurrentFungibleBalance { balance } = move_from<ConcurrentFungibleBalance>(addr); | |
if (concurrent_fungible_balance_exists_inline(addr)) { | |
let ConcurrentFungibleBalance { balance } = move_from<ConcurrentFungibleBalance>(addr); |
To reduce gas bloat?
let store = borrow_global_mut<FungibleStore>(store_addr); | ||
store.balance = store.balance + amount; | ||
|
||
if (auto_upgrade_to_concurrent_fungible_balance() || concurrent_fungible_balance_exists(store_addr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (auto_upgrade_to_concurrent_fungible_balance() || concurrent_fungible_balance_exists(store_addr)) { | |
if (auto_upgrade_to_concurrent_fungible_balance() || concurrent_fungible_balance_exists_inline(store_addr)) { |
To reduce gas bloat
|
||
if (auto_upgrade_to_concurrent_fungible_balance() || concurrent_fungible_balance_exists(store_addr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (auto_upgrade_to_concurrent_fungible_balance() || concurrent_fungible_balance_exists(store_addr)) { | |
if (auto_upgrade_to_concurrent_fungible_balance() || concurrent_fungible_balance_exists_inline(store_addr)) { |
To reduce gas bloat
@alnoki I'll include inlines to individual functions, but I'll skip creating duplicate functions for that. once @lightmark changes land as well, we will stress test this, and see if it makes any difference, seems probably minor. |
b1f5998
to
4b7ae39
Compare
I'll add more context on one design choice, and anyone has feedback/thoughts, let me know. With the current code, once this flag is enabled, and stores get migrated, individual store will contain two resources in the resource group: we cannot remove balance field from Alternative would be to have create That is in general doable, except for the
Any thoughts? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
386060c
to
9f49c9c
Compare
7b8045d
to
04873c5
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
b48a610
to
c6b9ae5
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
✅ Forge suite
|
✅ Forge suite
|
Description
Test Plan