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

[wip] account contract type #12876

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 79 additions & 28 deletions core/primitives-core/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::serialize::dec_format;
use crate::types::{Balance, Nonce, StorageUsage};
use borsh::{BorshDeserialize, BorshSerialize};
pub use near_account_id as id;
use near_account_id::AccountId;
use near_schema_checker_lib::ProtocolSchema;
use std::io;

Expand Down Expand Up @@ -67,13 +68,41 @@ impl AccountV1 {
AccountV2 {
amount: self.amount,
locked: self.locked,
code_hash: self.code_hash,
contract_type: AccountContractType::LocalContractHash(self.code_hash),
storage_usage: self.storage_usage,
}
}
}

// TODO(global-contract): add new field
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
PartialEq,
Eq,
Debug,
Clone,
ProtocolSchema,
)]
pub enum AccountContractType {
None,
LocalContractHash(CryptoHash),
GlobalContractHash(CryptoHash),
GlobalContractByAccount(AccountId, CryptoHash),
}

impl From<AccountContractType> for CryptoHash {
fn from(contract: AccountContractType) -> Self {
match contract {
AccountContractType::None => CryptoHash::default(),
AccountContractType::LocalContractHash(hash)
| AccountContractType::GlobalContractHash(hash)
| AccountContractType::GlobalContractByAccount(_, hash) => hash,
}
}
}

#[derive(
BorshSerialize,
BorshDeserialize,
Expand All @@ -90,8 +119,8 @@ pub struct AccountV2 {
amount: Balance,
/// The amount locked due to staking.
locked: Balance,
/// Hash of the code stored in the storage for this account.
code_hash: CryptoHash,
/// Contract code in storage for this account, if any.
contract_type: AccountContractType,
/// Storage used by the given account, includes account id, this struct, access keys and other data.
storage_usage: StorageUsage,
}
Expand Down Expand Up @@ -134,7 +163,15 @@ impl Account {
pub fn code_hash(&self) -> CryptoHash {
match self {
Self::V1(account) => account.code_hash,
Self::V2(account) => account.code_hash,
Self::V2(account) => account.contract_type.clone().into(),
}
}

#[inline]
pub fn contract(&self) -> AccountContractType {
match self {
Self::V1(account) => AccountContractType::LocalContractHash(account.code_hash),
Self::V2(account) => account.contract_type.clone(),
}
}

Expand Down Expand Up @@ -171,10 +208,15 @@ impl Account {
}

#[inline]
pub fn set_code_hash(&mut self, code_hash: CryptoHash) {
pub fn set_local_code_hash(&mut self, code_hash: CryptoHash) {
match self {
Self::V1(account) => account.code_hash = code_hash,
Self::V2(account) => account.code_hash = code_hash,
Self::V2(account) => match account.contract_type {
AccountContractType::None | AccountContractType::LocalContractHash(_) => {
account.contract_type = AccountContractType::LocalContractHash(code_hash)
}
_ => panic!("Can't modify global code hash"),
},
}
}

Expand All @@ -195,8 +237,8 @@ struct SerdeAccount {
amount: Balance,
#[serde(with = "dec_format")]
locked: Balance,
code_hash: CryptoHash,
storage_usage: StorageUsage,
contract: AccountContractType,
/// Version of Account in re migrations and similar.
#[serde(default)]
version: AccountVersion,
Expand All @@ -212,13 +254,13 @@ impl<'de> serde::Deserialize<'de> for Account {
AccountVersion::V1 => Ok(Account::V1(AccountV1 {
amount: account_data.amount,
locked: account_data.locked,
code_hash: account_data.code_hash,
code_hash: account_data.contract.into(),
storage_usage: account_data.storage_usage,
})),
AccountVersion::V2 => Ok(Account::V2(AccountV2 {
amount: account_data.amount,
locked: account_data.locked,
code_hash: account_data.code_hash,
contract_type: account_data.contract,
storage_usage: account_data.storage_usage,
})),
}
Expand All @@ -234,8 +276,8 @@ impl serde::Serialize for Account {
let repr = SerdeAccount {
amount: self.amount(),
locked: self.locked(),
code_hash: self.code_hash(),
storage_usage: self.storage_usage(),
contract: self.contract(),
version,
};
repr.serialize(serializer)
Expand Down Expand Up @@ -387,26 +429,31 @@ mod tests {

#[test]
fn test_v1_account_serde_serialization() {
let old_account = AccountV1 {
amount: 1_000_000,
locked: 1_000_000,
code_hash: CryptoHash::hash_bytes(&[42]),
storage_usage: 100,
};
let amount = 1_000_000;
let locked = 1_000_000;
let code_hash = CryptoHash::hash_bytes(&[42]);
let storage_usage = 100;

let old_account = Account::V1(AccountV1 {
amount: amount.clone(),
locked: locked.clone(),
code_hash: code_hash.clone(),
storage_usage: storage_usage.clone(),
});

let serialized_account = serde_json::to_string(&old_account).unwrap();
let expected_serde_repr = SerdeAccount {
amount: old_account.amount,
locked: old_account.locked,
code_hash: old_account.code_hash,
storage_usage: old_account.storage_usage,
amount,
locked,
contract: AccountContractType::LocalContractHash(code_hash),
storage_usage,
version: AccountVersion::V1,
};
let actual_serde_repr: SerdeAccount = serde_json::from_str(&serialized_account).unwrap();
assert_eq!(actual_serde_repr, expected_serde_repr);

let new_account: Account = serde_json::from_str(&serialized_account).unwrap();
assert_eq!(new_account, Account::V1(old_account));
assert_eq!(new_account, old_account);

let new_serialized_account = serde_json::to_string(&new_account).unwrap();
let deserialized_account: Account = serde_json::from_str(&new_serialized_account).unwrap();
Expand All @@ -415,15 +462,15 @@ mod tests {

#[test]
fn test_v1_account_borsh_serialization() {
let old_account = AccountV1 {
let old_account = Account::V1(AccountV1 {
amount: 100,
locked: 200,
code_hash: CryptoHash::hash_bytes(&[42]),
storage_usage: 300,
};
});
let old_bytes = borsh::to_vec(&old_account).unwrap();
let new_account = <Account as BorshDeserialize>::deserialize(&mut &old_bytes[..]).unwrap();
assert_eq!(new_account, Account::V1(old_account));
assert_eq!(new_account, old_account);

let new_bytes = borsh::to_vec(&new_account).unwrap();
assert_eq!(new_bytes, old_bytes);
Expand All @@ -437,17 +484,19 @@ mod tests {
let account_v2 = AccountV2 {
amount: 10_000_000,
locked: 100_000,
code_hash: CryptoHash::hash_bytes(&[42]),
storage_usage: 1000,
contract_type: AccountContractType::GlobalContractHash(CryptoHash::hash_bytes(&[
42, 42, 32,
])),
};
let account = Account::V2(account_v2.clone());

let serialized_account = serde_json::to_string(&account).unwrap();
let expected_serde_repr = SerdeAccount {
amount: account_v2.amount,
locked: account_v2.locked,
code_hash: account_v2.code_hash,
storage_usage: account_v2.storage_usage,
contract: account_v2.contract_type,
version: AccountVersion::V2,
};
let actual_serde_repr: SerdeAccount = serde_json::from_str(&serialized_account).unwrap();
Expand All @@ -462,8 +511,10 @@ mod tests {
let account_v2 = AccountV2 {
amount: 10_000_000,
locked: 100_000,
code_hash: CryptoHash::hash_bytes(&[42]),
storage_usage: 1000,
contract_type: AccountContractType::GlobalContractHash(CryptoHash::hash_bytes(&[
42, 42, 32,
])),
};
let account = Account::V2(account_v2);
let serialized_account = borsh::to_vec(&account).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ pub fn create_nodes_from_seeds(seeds: Vec<String>) -> Vec<NodeConfig> {
if let StateRecord::Account { account_id, account } = record {
if account_id == &seed {
found_account_record = true;
account.set_code_hash(*ContractCode::new(code.to_vec(), None).hash());
account.set_local_code_hash(*ContractCode::new(code.to_vec(), None).hash());
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
}
Err(VMRunnerError::ExternalError(any_err)) => {
let err: ExternalError =
any_err.downcast().expect("Downcasting AnyError should not fail");

Check warning on line 130 in runtime/runtime/src/actions.rs

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (Downcasting)
return Err(match err {
ExternalError::StorageError(err) => err.into(),
ExternalError::ValidatorError(err) => RuntimeError::ValidatorError(err),
Expand Down Expand Up @@ -598,7 +598,7 @@
))
})?,
);
account.set_code_hash(*code.hash());
account.set_local_code_hash(*code.hash());
// Legacy: populate the mapping from `AccountId => sha256(code)` thus making contracts part of
// The State. For the time being we are also relying on the `TrieUpdate` to actually write the
// contracts into the storage as part of the commit routine, however no code should be relying
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ mod tests {
account_id.clone(),
&ContractCode::new(code.clone(), Some(code_hash)),
);
initial_account.set_code_hash(code_hash);
initial_account.set_local_code_hash(code_hash);
initial_account.set_storage_usage(
initial_account.storage_usage().checked_add(code.len() as u64).unwrap(),
);
Expand Down
2 changes: 1 addition & 1 deletion test-utils/testlib/src/runtime_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn add_contract(genesis: &mut Genesis, account_id: &AccountId, code: Vec<u8>
if let StateRecord::Account { account_id: record_account_id, ref mut account } = record {
if record_account_id == account_id {
is_account_record_found = true;
account.set_code_hash(hash);
account.set_local_code_hash(hash);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tools/amend-genesis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl AccountRecords {
// records. Set the storage usage to reflect whatever's in the original records, and at the
// end we will add to the storage usage with any extra keys added for this account
account.set_storage_usage(existing.storage_usage());
account.set_code_hash(existing.code_hash());
account.set_local_code_hash(existing.code_hash());
if self.amount_needed {
set_total_balance(account, existing);
}
Expand Down
Loading