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

feat: global contract support for accounts #12877

Merged
merged 27 commits into from
Feb 10, 2025

Conversation

stedfn
Copy link
Contributor

@stedfn stedfn commented Feb 5, 2025

This PR introduces a new AccountContract field in the AccountV2 struct, replacing code_hash and being defined as follows:

pub enum AccountContract {
    None,
    Local(CryptoHash),
    Global(CryptoHash),
    GlobalByAccount(AccountId),
}

It is being used to differentiate between the types of contracts stored for the Account, if any.

To maintain backward compatibility, two new optional fields for global contracts are also added in the SerdeAccount struct.

Part of #12716

@stedfn stedfn requested a review from pugachAG February 5, 2025 16:42
@stedfn stedfn marked this pull request as ready for review February 5, 2025 16:42
@stedfn stedfn requested a review from a team as a code owner February 5, 2025 16:42
Copy link

codecov bot commented Feb 5, 2025

Codecov Report

Attention: Patch coverage is 88.47584% with 31 lines in your changes missing coverage. Please review.

Project coverage is 70.44%. Comparing base (20ea311) to head (1ae6226).
Report is 7 commits behind head on master.

Files with missing lines Patch % Lines
core/primitives-core/src/account.rs 89.37% 14 Missing and 3 partials ⚠️
core/primitives/src/views.rs 69.23% 4 Missing ⚠️
integration-tests/src/node/mod.rs 0.00% 3 Missing ⚠️
runtime/runtime/src/state_viewer/mod.rs 85.71% 0 Missing and 2 partials ⚠️
chain/rosetta-rpc/src/lib.rs 0.00% 1 Missing ⚠️
runtime/runtime/src/lib.rs 80.00% 1 Missing ⚠️
runtime/runtime/src/verifier.rs 0.00% 1 Missing ⚠️
tools/amend-genesis/src/lib.rs 83.33% 0 Missing and 1 partial ⚠️
tools/fork-network/src/cli.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #12877      +/-   ##
==========================================
+ Coverage   70.41%   70.44%   +0.03%     
==========================================
  Files         854      854              
  Lines      174571   174765     +194     
  Branches   174571   174765     +194     
==========================================
+ Hits       122927   123117     +190     
- Misses      46408    46409       +1     
- Partials     5236     5239       +3     
Flag Coverage Δ
backward-compatibility 0.35% <0.00%> (-0.01%) ⬇️
db-migration 0.35% <0.00%> (-0.01%) ⬇️
genesis-check 1.42% <19.60%> (+0.01%) ⬆️
linux 70.04% <88.47%> (+0.04%) ⬆️
linux-nightly 70.08% <88.47%> (+0.03%) ⬆️
pytests 1.73% <19.60%> (+0.01%) ⬆️
sanity-checks 1.54% <19.60%> (+0.01%) ⬆️
unittests 70.27% <88.47%> (+0.03%) ⬆️
upgradability 0.35% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
None,
LocalContract(CryptoHash),
GlobalContract(CryptoHash),
GlobalContractByAccount(AccountId, CryptoHash),
Copy link
Contributor

Choose a reason for hiding this comment

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

what does CryptoHash correspond to here?

Copy link
Contributor Author

@stedfn stedfn Feb 6, 2025

Choose a reason for hiding this comment

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

The hash of the contract deployed from the AccountId. I was thinking we need to know if the account has an older contract version deployed from the AccountId

Copy link
Contributor

Choose a reason for hiding this comment

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

We do not want to store that information as part of user's account. That is not needed, but also we would have to update all accounts when the contract is updated which is not feasible.

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 would have to update all accounts when the contract is updated which is not feasible

actually aren't automated upgrades a security concern? shouldn't users manually upgrade after they check the new code?

Copy link
Contributor

Choose a reason for hiding this comment

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

nope, user accepts such risk when using contract deployed by AccountId, otherwise they should use global contract hash

core/primitives-core/src/account.rs Show resolved Hide resolved
core/primitives-core/src/account.rs Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
Self::V1(account) => account.code_hash = code_hash,
Self::V2(account) => account.code_hash = code_hash,
Self::V1(_) => {
let account_v2 = AccountV2 {
Copy link
Contributor

Choose a reason for hiding this comment

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

AccountV2 has serialization overhead comparing to V1, so we should avoid conversion when possible. So please add additional check for contract being None or Local and do not convert to v2 in such cases. Also would be nice to add tests for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should it also get downgraded if possible?

Copy link
Contributor

Choose a reason for hiding this comment

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

good question! let's not do that for now to keep it simple since I don't expect that to happen frequently

}

impl AccountContract {
pub fn to_code_hash(&self) -> CryptoHash {
Copy link
Contributor

Choose a reason for hiding this comment

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

replacing all previous usages of Account::code_hash with to_code_hash is very dangerous since existing clients only expect local code to be there. For example runtime might issues storage reads for TrieKey::ContractCode which would not be correct for global contract. Please replace this with fn local_code(&self) -> Option<CryptoHash> and update clients accordingly.

core/primitives/src/views.rs Outdated Show resolved Hide resolved
runtime/runtime/src/verifier.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
@@ -136,7 +136,7 @@ impl ReceiptPreparationPipeline {
}
Action::FunctionCall(function_call) => {
let Some(account) = &**account else { continue };
let code_hash = account.code_hash();
let Some(code_hash) = account.contract().local_code() else { continue }; // TODO: deal with global contract call
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pugachAG I am supposed to deal with global contract function calls here right?

Copy link
Contributor

Choose a reason for hiding this comment

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

add todo! referencing #12884

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 made it a comment with a continue because a test was failing

@pugachAG
Copy link
Contributor

pugachAG commented Feb 6, 2025

please add a detailed description for this PR

core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives/src/views.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@pugachAG pugachAG left a comment

Choose a reason for hiding this comment

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

overall LGTM, a couple more nits to address

@@ -45,6 +46,7 @@ nightly = [
"near-jsonrpc/nightly",
"near-network/nightly",
"near-o11y/nightly",
"near-primitives-core/nightly",
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need dependency updates?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this script was complaining

core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
core/primitives-core/src/account.rs Outdated Show resolved Hide resolved
@@ -208,7 +208,7 @@ mod test {
}
}
fn hash(chunk: &[u8]) -> String {
crate::CryptoHash::from(chunk.try_into().unwrap()).to_string()
crate::CryptoHash::try_from(chunk).unwrap().to_string()
Copy link
Contributor

Choose a reason for hiding this comment

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

does this change belong to this pr? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh not anymore, will revert. It was needed before when I added a new From trait implementation for CryptoHash because the compiler did not know which from implementation to use

test-utils/testlib/src/runtime_utils.rs Outdated Show resolved Hide resolved
let (global_contract_hash, global_contract_account_id) = match account.contract() {
AccountContract::Global(contract) => (Some(contract), None),
AccountContract::GlobalByAccount(account_id) => (None, Some(account_id)),
_ => (None, None),
Copy link
Contributor

Choose a reason for hiding this comment

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

please explicitly list all other variants, using _ => is a dangerous patter since adding new enum variant which might be relevant here can be missed


#[inline]
pub fn local_contract_hash(&self) -> Option<CryptoHash> {
match self.contract() {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: in the current implementation calling self.contract() results in potentially copying AccountId, would be nice to address that somehow

@stedfn stedfn added this pull request to the merge queue Feb 10, 2025
Merged via the queue into master with commit e01e2cf Feb 10, 2025
27 of 29 checks passed
@stedfn stedfn deleted the stefan/global_contract_account_support branch February 10, 2025 09:08
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