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

Implement AccountComponents #941

Draft
wants to merge 14 commits into
base: next
Choose a base branch
from

Conversation

PhilippGackstatter
Copy link
Contributor

@PhilippGackstatter PhilippGackstatter commented Oct 29, 2024

TODO

closes #935

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! Not a review, but I took a quick look and left some comments inline.

Comment on lines 9 to 22
// TODO Document everything, add section separators.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccountComponent {
pub(crate) code: Library,
pub(crate) storage_slots: Vec<StorageSlot>,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Not for this PR, but one thing that may be good to add here is a filed which specifies whether the component is valid for all accounts or only for special type of accounts (e.g., a fungible faucet). This way, we can prevent errors when trying to add non-faucet components to faucets etc.

Let's create an issue for this.

Copy link
Contributor

Choose a reason for hiding this comment

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

On the other hand, if it is not too difficult, we may consider doing it in this PR as it may simplify account construction as mentioned in #941 (comment).

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 added an AccountComponentType::{Faucet, Any} now to address this. I'm not sure if Any is correct or sufficient though. Some components like authentication can be added to any account, so it seems correct to have it there. But maybe a third category like Regular (or something more descriptive) is needed for things like BasicWallet?
Then any account instantiated from multiple components would fail if any Faucet and Regular components are mixed?

Copy link
Contributor

Choose a reason for hiding this comment

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

Another way to do this could be to use a BTreeSet<AccountType> and explicitly specify the types of account a component can be applied to. Then, we can have convenience methods like is_valid_for(account_type) and is_only_for_faucet().

Comment on lines 95 to 99
// TODO: Document.
pub fn from_components(
components: &[AccountComponent],
account_type: AccountType,
) -> Result<Self, AccountError> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Once everything is ready, this will replace AccountCode::new(), right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's replaced almost everywhere now, only internal references left to cleanup 👍

Comment on lines +143 to +147
component_storage_offset = component_storage_offset.checked_add(component_storage_size)
.expect("account procedure info constructor should return an error if the addition overflows");
Copy link
Contributor

Choose a reason for hiding this comment

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

We also need to check that the offset does not exceed 255 (I believe) as this is the maximum number of storage slots per account.

Comment on lines 101 to 105
// TODO: Document.
pub fn from_components(
seed: Word,
account_type: AccountType,
components: &[AccountComponent],
) -> Result<Self, AccountError> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will replace Account::new() right?

Also, a couple of thoughts:

  • If we have a way to infer account type from the underlying components (i.e., if it is a faucet or not), we can avoid passing it as a parameter.
  • If we do pass account type as a parameter, we need to add a check to make sure the generated ID matches this type.

Comment on lines 53 to 80
// TODO Document.
pub fn from_components(
components: &[AccountComponent],
) -> Result<AccountStorage, AccountError> {
let storage_slots = components
.iter()
.flat_map(|component| component.storage_slots())
.cloned()
.collect();

Self::new(storage_slots)
}

pub fn from_components_with_faucet_metadata(
components: &[AccountComponent],
faucet_metadata: Word,
) -> Result<AccountStorage, AccountError> {
let mut storage_slots = vec![StorageSlot::Value(faucet_metadata)];
storage_slots
.extend(components.iter().flat_map(|component| component.storage_slots()).cloned());

Self::new(storage_slots)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Potentially, I'd move this logic into the account constructor.

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 agree that would be nice, but given the dependence of the AccountId on the code and storage, I don't know how we could efficiently rewrite places like these:

let account_code = AccountCode::from_components(&components)?;
let account_storage = AccountStorage::from_components(&components)?;
let account_seed = AccountId::get_account_seed(
init_seed,
AccountType::FungibleFaucet,
account_storage_mode,
account_code.commitment(),
account_storage.commitment(),
)?;
let account = Account::new(account_seed, account_code, account_storage)?;

We can of course call Account::from_components on the same components again, but that will redo work we've just done (including MastForest::merge which is expensive).

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.

2 participants