Skip to content
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

near and storage tracing - wip #7

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft

Conversation

robert-zaremba
Copy link
Contributor

No description provided.

pub amount: Balance,
/// NEAR sent to the exchange.
/// Used for storage and trading.
pub ynear: Balance,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renaming amount -> ynear to enhance code readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will use near_amount

@@ -193,6 +188,8 @@ impl Contract {
deposits.add(token_out.as_ref().clone(), amount_out);
self.deposited_amounts.insert(&sender_id, &deposits);
self.pools.replace(pool_id, &pool);
deposits.update_storage(start_storage);
self.deposited_amounts.insert(&sender_id, &deposits);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To verify: I think we need to insert 2 times:

  • once in line 194 (prev)
  • second time here.
    This is because we won't trace properly new storage until we insert the record into the storage tree.
    Alternative would be to refactor the AccountDeposit and move ynear to another, top-level map.

pub(crate) fn update_storage(&self, from: &AccountDeposit, tx_start_storage: StorageUsage) {
let mut d = self.get_account_depoists(from);
d.update_storage(tx_start_storage);
self.deposited_amounts.insert(from, &d);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about renaming self.deposited_amounts to self.deposits?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to accounts

@@ -109,7 +109,7 @@ impl Contract {
let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL");
// Add amounts given to liquidity first. It will return the balanced amounts.
pool.add_liquidity(&sender_id, &mut amounts);
let mut deposits = self.deposited_amounts.get(&sender_id).unwrap_or_default();
let mut deposits = self.get_account_depoists(&sender_id);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add liquidity should early fail if account is not registered.

storage_cost <= env::attached_deposit(),
"ERR_STORAGE_DEPOSIT"
);
// TODO: update deposit handling
let refund = env::attached_deposit() - storage_cost;
if refund > 0 {
Promise::new(env::predecessor_account_id()).transfer(refund);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refund won't work, because I added assert_one_yocto().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover - it's easier to standarize here to use internal storage tracking + assert_one_yocto, rather than asking user for unknown required NEAR attachment.

const MIN_ACCOUNT_DEPOSIT_LENGTH: u128 = MAX_ACCOUNT_LENGTH + 16 + 4;
/// Minimum Account Storage used for account registration.
/// 64 (AccountID bytes) + 2*8 (int32) + byte
pub const INIT_ACCOUNT_STORAGE: StorageUsage = 64 + 16 + 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@ilblackdragon ilblackdragon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I'm not 100% sure you actually handled the upgrading - i see direct self.account.get calls.
I think the easiest way is to keep account_deposit as old field and create new lookup map with VersionedAccount. And just when loading - check back if it exists and upgrade.

And let's have a test_upgrade to actually test this upgrade with an old contract that has some state.

ref-exchange/src/account_deposit.rs Outdated Show resolved Hide resolved
/// Account deposits information and storage cost.
#[derive(BorshSerialize, BorshDeserialize, Default)]
#[cfg_attr(feature = "test", derive(Clone))]
pub struct AccountDepositV2 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's rename to Account?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v1 structure is already named AccountDeposit. So - do you suggest to rename both?

return a;
}
// migrate from V1
a.storage_used = U64_STORAGE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this is (MIN_ACCOUNT_DEPOSIT_LENGTH + self.tokens.len() as u128 * (MAX_ACCOUNT_LENGTH + 16)) * env::storage_byte_cost() (old storage_usage)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW - we don't multiply by env::storage_byte_cost() here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I remember why I don't include the AccountDeposit storage here, please see the comment below (#7 (comment))

* env::storage_byte_cost()
let s = self.storage_used
+ INIT_ACCOUNT_STORAGE // empty account storage
+ (ACC_ID_STORAGE + U64_STORAGE) * self.tokens.len() as u64; // self.tokens storage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just count this inside storage_used? so storage_usage * cost is just self.storage_used?
also it seems like you are missing cost of storage in general here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because, in self.storage_used we only account storage used outside of this structure. This is to avoid "double" storing the account. See here: #7 (comment)

#[payable]
pub fn deposit_near(&mut self) {
let sender_id = env::predecessor_account_id();
let mut acc = self.get_account(&sender_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we register here if not registered? it seems like this will be easier to use than storage_deposit in general case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about it. We have a standard for user / account registration. This function is to make it more clear to deposit more NEAR and not confuse with registration. However if you think that by allowing a registration here, we will improve UX then we can do that.

// pub const NEAR: AccountId = "".to_string();

#[derive(BorshDeserialize, BorshSerialize)]
pub enum AccountDeposit {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like more VersionedAccount and Account for the current version.
This way everywhere in the code except in the places where it's used - it's just Account. And VersionedAccount is where need to store/load/upgrade

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, you want to have a LegacyAccount and Account? What if we will do another migration? I think having a consecutive versions in struct name is more clear. We will mark all old version Legacy in the comments.

@robert-zaremba
Copy link
Contributor Author

Hm, I'm not 100% sure you actually handled the upgrading - i see direct self.account.get calls.
I think the easiest way is to keep account_deposit as old field and create new lookup map with VersionedAccount. And just when loading - check back if it exists and upgrade.

I've asked @evgenykuzyakov about possible strategies few weeks ago. I think if we won't use indexer then then doing byte computation for figuring out the structure version is too error prone.

So, depending which strategy we will take. If we want to do it lazy (so user will do migration when he will use the account next time) then we will need to duplicate the accounts - if we will use indexer then we will do a migration function. We had a chat about it in telegram. Here I wanted to verify the AccountDeposit structure and update.

@referencedev
Copy link
Contributor

#27 adds storage handling without needing to upgrade Account data structure. This fixes the issue short term and removes need to keep track storage_used from it for now.

marco-sundsk added a commit that referenced this pull request May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants