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(primitives): Add versioning to Account #4089

Merged
merged 27 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
28691eb
- Introducing account versioning again
EgorKulikov Mar 12, 2021
a6f3156
Merge branch 'master' into account-versioning
EgorKulikov Mar 12, 2021
48d81b4
Update 30-add-account-versioning.py
EgorKulikov Mar 12, 2021
01afe8f
toml fix
EgorKulikov Mar 12, 2021
f2106e1
Merge branch 'master' into account-versioning
EgorKulikov Mar 12, 2021
a305202
Merge branch 'master' into account-versioning
EgorKulikov Mar 12, 2021
7dcbd8c
Merge branch 'master' into account-versioning
EgorKulikov Mar 12, 2021
05e660d
Change name for migration script
EgorKulikov Mar 12, 2021
4fc155c
Merge remote-tracking branch 'origin/account-versioning' into account…
EgorKulikov Mar 12, 2021
05429cb
Merge branch 'master' into account-versioning
chefsale Mar 12, 2021
06f0e20
Merge branch 'master' into account-versioning
EgorKulikov Mar 13, 2021
e5d1ce2
Merge branch 'master' into account-versioning
EgorKulikov Mar 14, 2021
5d9f609
Merge branch 'master' into account-versioning
EgorKulikov Mar 15, 2021
94225ee
Merge branch 'master' into account-versioning
EgorKulikov Mar 16, 2021
1e55d4f
Merge branch 'master' into account-versioning
EgorKulikov Mar 16, 2021
54a0a91
Merge branch 'master' into account-versioning
EgorKulikov Mar 16, 2021
07e2560
Account struct fields made private
EgorKulikov Mar 17, 2021
f0d6e6b
Merge branch 'master' into account-versioning
EgorKulikov Mar 17, 2021
826cc39
Missing method calls
EgorKulikov Mar 17, 2021
a1a2fc8
Merge branch 'master' into account-versioning
EgorKulikov Mar 17, 2021
9842d2a
new istead of struct init
EgorKulikov Mar 17, 2021
e3b01b9
Merge remote-tracking branch 'origin/account-versioning' into account…
EgorKulikov Mar 17, 2021
f15b04c
Merge branch 'master' into account-versioning
EgorKulikov Mar 17, 2021
8c07e34
Merge branch 'master' into account-versioning
chefsale Mar 17, 2021
c5746ca
Merge branch 'master' into account-versioning
EgorKulikov Mar 17, 2021
bf7ea32
Merge branch 'master' into account-versioning
EgorKulikov Mar 17, 2021
998a1ff
Merge branch 'master' into account-versioning
chefsale Mar 17, 2021
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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,13 @@ metric_recorder = ["neard/metric_recorder"]
delay_detector = ["neard/delay_detector"]
rosetta_rpc = ["neard/rosetta_rpc"]
nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"]
nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features", "protocol_feature_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_access_key_nonce_range"]
nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features", "protocol_feature_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_access_key_nonce_range", "protocol_feature_add_account_versions"]
protocol_feature_forward_chunk_parts = ["neard/protocol_feature_forward_chunk_parts"]
protocol_feature_evm = ["neard/protocol_feature_evm", "testlib/protocol_feature_evm", "runtime-params-estimator/protocol_feature_evm"]
protocol_feature_alt_bn128 = ["neard/protocol_feature_alt_bn128", "testlib/protocol_feature_alt_bn128", "runtime-params-estimator/protocol_feature_alt_bn128"]
protocol_feature_block_header_v3 = ["near-primitives/protocol_feature_block_header_v3", "near-chain/protocol_feature_block_header_v3", "neard/protocol_feature_block_header_v3"]
protocol_feature_access_key_nonce_range = ["neard/protocol_feature_access_key_nonce_range"]
protocol_feature_add_account_versions = ["near-primitives/protocol_feature_add_account_versions"]

# enable this to build neard with wasmer 1.0 runner
# now if none of wasmer0_default, wasmer1_default or wasmtime_default is enabled, wasmer0 would be default
Expand Down
12 changes: 6 additions & 6 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,15 +796,15 @@ impl RuntimeAdapter for KeyValueRuntime {
match request {
QueryRequest::ViewAccount { account_id, .. } => Ok(QueryResponse {
kind: QueryResponseKind::ViewAccount(
Account {
amount: self.state.read().unwrap().get(&state_root).map_or_else(
Account::new(
self.state.read().unwrap().get(&state_root).map_or_else(
|| 0,
|state| *state.amounts.get(account_id).unwrap_or(&0),
),
locked: 0,
code_hash: CryptoHash::default(),
storage_usage: 0,
}
0,
CryptoHash::default(),
0,
)
.into(),
),
block_height,
Expand Down
3 changes: 2 additions & 1 deletion chain/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@ delay_detector = ["near-chain/delay_detector", "near-network/delay_detector", "d
protocol_feature_forward_chunk_parts = ["near-primitives/protocol_feature_forward_chunk_parts", "near-network/protocol_feature_forward_chunk_parts", "near-chunks/protocol_feature_forward_chunk_parts"]
protocol_feature_block_header_v3 = ["near-primitives/protocol_feature_block_header_v3", "near-chain/protocol_feature_block_header_v3"]
protocol_feature_access_key_nonce_range = ["near-chain/protocol_feature_access_key_nonce_range"]
protocol_feature_add_account_versions = ["near-primitives/protocol_feature_add_account_versions"]
nightly_protocol = []
nightly_protocol_features = ["nightly_protocol", "near-chain/nightly_protocol_features", "protocol_feature_forward_chunk_parts", "protocol_feature_block_header_v3", "protocol_feature_access_key_nonce_range"]
nightly_protocol_features = ["nightly_protocol", "near-chain/nightly_protocol_features", "protocol_feature_forward_chunk_parts", "protocol_feature_block_header_v3", "protocol_feature_access_key_nonce_range", "protocol_feature_add_account_versions"]
19 changes: 19 additions & 0 deletions chain/client/tests/challenges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ fn test_verify_chunk_invalid_state_challenge() {
let merkle_proofs = Block::compute_chunk_headers_root(block.chunks().iter()).1;
assert_eq!(prev_merkle_proofs[0], challenge_body.prev_merkle_proof);
assert_eq!(merkle_proofs[0], challenge_body.merkle_proof);
#[cfg(not(feature = "protocol_feature_add_account_versions"))]
assert_eq!(
challenge_body.partial_state.0,
vec![
Expand All @@ -419,6 +420,24 @@ fn test_verify_chunk_invalid_state_challenge() {
]
],
);
#[cfg(feature = "protocol_feature_add_account_versions")]
assert_eq!(
challenge_body.partial_state.0,
vec![
vec![
1, 5, 0, 103, 136, 41, 229, 191, 222, 128, 157, 188, 48, 241, 45, 16, 109, 89,
11, 71, 68, 27, 183, 107, 203, 67, 148, 6, 107, 149, 201, 181, 97, 233, 212,
171, 30, 7, 228, 175, 99, 17, 113, 5, 94, 136, 200, 39, 136, 37, 110, 166, 241,
148, 128, 55, 131, 173, 97, 98, 201, 68, 82, 244, 223, 70, 86, 164, 5, 0, 0, 0,
0, 0, 0
],
vec![
3, 1, 0, 0, 0, 16, 154, 102, 233, 139, 210, 140, 249, 11, 123, 207, 177, 159,
114, 249, 144, 220, 49, 241, 60, 112, 44, 187, 65, 32, 97, 193, 60, 115, 103,
197, 230, 198, 216, 5, 0, 0, 0, 0, 0, 0
]
],
);
}
let challenge =
Challenge::produce(ChallengeBody::ChunkState(challenge_body), &validator_signer);
Expand Down
8 changes: 1 addition & 7 deletions chain/rosetta-rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,13 +376,7 @@ async fn account_balance(
Err(crate::errors::ErrorKind::NotFound(_)) => (
block.header.hash,
block.header.height,
near_primitives::account::Account {
amount: 0,
locked: 0,
storage_usage: 0,
code_hash: Default::default(),
}
.into(),
near_primitives::account::Account::new(0, 0, Default::default(), 0).into(),
),
Err(err) => return Err(err.into()),
};
Expand Down
6 changes: 3 additions & 3 deletions chain/rosetta-rpc/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ fn get_liquid_balance_for_storage(
mut account: near_primitives::account::Account,
runtime_config: &near_primitives::runtime::config::RuntimeConfig,
) -> near_primitives::types::Balance {
account.amount = 0;
account.set_amount(0);
near_primitives::runtime::get_insufficient_storage_stake(&account, &runtime_config)
.expect("get_insufficient_storage_stake never fails when state is consistent")
.unwrap_or(0)
Expand All @@ -289,8 +289,8 @@ impl RosettaAccountBalances {
runtime_config: &near_primitives::runtime::config::RuntimeConfig,
) -> Self {
let account = account.into();
let amount = account.amount;
let locked = account.locked;
let amount = account.amount();
let locked = account.locked();
let liquid_for_storage = get_liquid_balance_for_storage(account, runtime_config);

Self { liquid_for_storage, liquid: amount.saturating_sub(liquid_for_storage), locked }
Expand Down
2 changes: 1 addition & 1 deletion core/chain-configs/src/genesis_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ pub fn get_initial_supply(records: &[StateRecord]) -> Balance {
let mut total_supply = 0;
for record in records {
if let StateRecord::Account { account, .. } = record {
total_supply += account.amount + account.locked;
total_supply += account.amount() + account.locked();
}
}
total_supply
Expand Down
1 change: 1 addition & 0 deletions core/primitives-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ lazy_static = "1.4"
[features]
default = []
costs_counting = []
protocol_feature_add_account_versions = []
protocol_feature_evm = []
protocol_feature_alt_bn128 = []
237 changes: 231 additions & 6 deletions core/primitives-core/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use serde::{Deserialize, Serialize};
use crate::hash::CryptoHash;
use crate::serialize::{option_u128_dec_format, u128_dec_format_compatible};
use crate::types::{AccountId, Balance, Nonce, StorageUsage};
#[cfg(feature = "protocol_feature_add_account_versions")]
use borsh::maybestd::io::Error;

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
/// Per account information stored in the state.
#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct Account {
Expand All @@ -20,6 +23,189 @@ pub struct Account {
pub storage_usage: StorageUsage,
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct AccountV1 {
/// The total not locked tokens.
#[serde(with = "u128_dec_format_compatible")]
pub amount: Balance,
/// The amount locked due to staking.
#[serde(with = "u128_dec_format_compatible")]
pub locked: Balance,
/// Hash of the code stored in the storage for this account.
pub code_hash: CryptoHash,
/// Storage used by the given account, includes account id, this struct, access keys and other data.
pub storage_usage: StorageUsage,
}
EgorKulikov marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(feature = "protocol_feature_add_account_versions")]
#[derive(BorshSerialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub enum Account {
AccountV1(AccountV1),
}

impl Account {
#[cfg(not(feature = "protocol_feature_add_account_versions"))]
pub fn new(
amount: Balance,
locked: Balance,
code_hash: CryptoHash,
storage_usage: StorageUsage,
) -> Self {
Account { amount, locked, code_hash, storage_usage }
}

#[cfg(feature = "protocol_feature_add_account_versions")]
pub fn new(
amount: Balance,
locked: Balance,
code_hash: CryptoHash,
storage_usage: StorageUsage,
) -> Self {
Account::AccountV1(AccountV1 { amount, locked, code_hash, storage_usage })
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn amount(&self) -> Balance {
self.amount
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn amount(&self) -> Balance {
match self {
Account::AccountV1(acc) => acc.amount,
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn locked(&self) -> Balance {
self.locked
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn locked(&self) -> Balance {
match self {
Account::AccountV1(acc) => acc.locked,
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn code_hash(&self) -> CryptoHash {
self.code_hash
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn code_hash(&self) -> CryptoHash {
match self {
Account::AccountV1(acc) => acc.code_hash,
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn storage_usage(&self) -> StorageUsage {
self.storage_usage
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn storage_usage(&self) -> StorageUsage {
match self {
Account::AccountV1(acc) => acc.storage_usage,
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn set_amount(&mut self, amount: Balance) {
self.amount = amount;
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn set_amount(&mut self, amount: Balance) {
match self {
Account::AccountV1(acc) => {
acc.amount = amount;
}
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn set_locked(&mut self, locked: Balance) {
self.locked = locked;
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn set_locked(&mut self, locked: Balance) {
match self {
Account::AccountV1(acc) => {
acc.locked = locked;
}
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn set_code_hash(&mut self, code_hash: CryptoHash) {
self.code_hash = code_hash;
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn set_code_hash(&mut self, code_hash: CryptoHash) {
match self {
Account::AccountV1(acc) => {
acc.code_hash = code_hash;
}
}
}

#[cfg(not(feature = "protocol_feature_add_account_versions"))]
#[inline]
pub fn set_storage_usage(&mut self, storage_usage: StorageUsage) {
self.storage_usage = storage_usage;
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[inline]
pub fn set_storage_usage(&mut self, storage_usage: StorageUsage) {
match self {
Account::AccountV1(acc) => {
acc.storage_usage = storage_usage;
}
}
}
}

#[cfg(feature = "protocol_feature_add_account_versions")]
impl BorshDeserialize for Account {
fn deserialize(buf: &mut &[u8]) -> Result<Self, Error> {
if buf.len() == std::mem::size_of::<AccountV1>() {
// This should only ever happen if we have pre-transition account serialized in state
// See test_account_size
Ok(Account::AccountV1(<AccountV1 as BorshDeserialize>::deserialize(buf)?))
} else {
#[derive(BorshDeserialize)]
enum DeserializableAccount {
AccountV1(AccountV1),
};
let deserialized_account = DeserializableAccount::deserialize(buf)?;
match deserialized_account {
DeserializableAccount::AccountV1(account) => Ok(Account::AccountV1(account)),
}
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

It worth moving it up to line 46, so you don't forget to add a field to DeserializableAccount.

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 guess adding new version will lead to changing new, and that will fail serialization/deserialization tests


/// Access key provides limited access to an account. Each access key belongs to some account and
/// is identified by a unique (within the account) public key. One account may have large number of
/// access keys. Access keys allow to act on behalf of the account by restricting transactions
Expand Down Expand Up @@ -96,13 +282,52 @@ mod tests {

#[test]
fn test_account_serialization() {
let acc = Account {
amount: 1_000_000,
locked: 1_000_000,
code_hash: CryptoHash::default(),
storage_usage: 100,
};
let acc = Account::new(1_000_000, 1_000_000, CryptoHash::default(), 100);
let bytes = acc.try_to_vec().unwrap();
#[cfg(not(feature = "protocol_feature_add_account_versions"))]
assert_eq!(to_base(&hash(&bytes)), "EVk5UaxBe8LQ8r8iD5EAxVBs6TJcMDKqyH7PBuho6bBJ");
#[cfg(feature = "protocol_feature_add_account_versions")]
{
assert_eq!(to_base(&hash(&bytes)), "7HBKnu8VPDaVgj6jbGvdVgTzPG3uBdZ97WGhoYpKT7hZ");
match acc {
Account::AccountV1(account) => {
let pbytes = account.try_to_vec().unwrap();
assert_eq!(
to_base(&hash(&pbytes)),
"EVk5UaxBe8LQ8r8iD5EAxVBs6TJcMDKqyH7PBuho6bBJ"
);
}
}
}
}

#[test]
#[cfg(feature = "protocol_feature_add_account_versions")]
fn test_account_size() {
let new_account = Account::new(0, 0, CryptoHash::default(), 0);
let old_account =
AccountV1 { amount: 0, locked: 0, code_hash: CryptoHash::default(), storage_usage: 0 };
let new_bytes = new_account.try_to_vec().unwrap();
let old_bytes = old_account.try_to_vec().unwrap();
assert!(new_bytes.len() > old_bytes.len());
assert_eq!(old_bytes.len(), std::mem::size_of::<AccountV1>());
}

#[test]
#[cfg(feature = "protocol_feature_add_account_versions")]
fn test_account_deserialization() {
let old_account = AccountV1 {
amount: 100,
locked: 200,
code_hash: CryptoHash::default(),
storage_usage: 300,
};
let mut old_bytes = &old_account.try_to_vec().unwrap()[..];
let new_account = <Account as BorshDeserialize>::deserialize(&mut old_bytes).unwrap();
assert_eq!(new_account, Account::AccountV1(old_account));
let mut new_bytes = &new_account.try_to_vec().unwrap()[..];
let deserialized_account =
<Account as BorshDeserialize>::deserialize(&mut new_bytes).unwrap();
assert_eq!(deserialized_account, new_account);
}
}
Loading