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

RPC: add actual_amount into account/ rpc call #1974

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 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
33 changes: 18 additions & 15 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde::Serialize;

use near_crypto::{InMemorySigner, KeyType, PublicKey, SecretKey, Signature, Signer};
use near_pool::types::PoolIterator;
use near_primitives::account::{AccessKey, Account};
use near_primitives::account::AccessKey;
use near_primitives::block::{Approval, Block};
use near_primitives::challenge::{ChallengesResult, SlashedValidator};
use near_primitives::errors::InvalidTxError;
Expand All @@ -27,7 +27,8 @@ use near_primitives::types::{
StateChangesRequest, StateRoot, StateRootNode, ValidatorStake, ValidatorStats,
};
use near_primitives::views::{
AccessKeyInfoView, AccessKeyList, EpochValidatorInfo, QueryResponse, QueryResponseKind,
AccessKeyInfoView, AccessKeyList, AccountView, EpochValidatorInfo, QueryResponse,
QueryResponseKind,
};
use near_store::test_utils::create_test_store;
use near_store::{
Expand Down Expand Up @@ -671,20 +672,22 @@ impl RuntimeAdapter for KeyValueRuntime {
match path[0] {
"account" => {
let account_id = path[1].to_string();
let account_id2 = account_id.clone();
let amount = self
.state
.read()
.unwrap()
.get(&state_root)
.map_or_else(|| 0, |state| *state.amounts.get(&account_id2).unwrap_or(&0));
Ok(QueryResponse {
kind: QueryResponseKind::ViewAccount(
Account {
amount: 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,
storage_paid_at: 0,
}
.into(),
),
kind: QueryResponseKind::ViewAccount(AccountView {
amount,
rent: 0,
locked: 0,
code_hash: CryptoHash::default(),
storage_usage: 0,
storage_paid_at: 0,
}),
block_height,
})
}
Expand Down
44 changes: 42 additions & 2 deletions core/primitives/src/account.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
use borsh::{BorshDeserialize, BorshSerialize};

use crate::serialize::u128_dec_format;

use crate::hash::CryptoHash;
use crate::types::{AccountId, Balance, BlockHeight, Nonce, StorageUsage};

/// Per account information stored in the state.
#[derive(BorshSerialize, BorshDeserialize, Serialize, PartialEq, Eq, Debug, Clone)]
#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct Account {
/// The total not locked tokens.
#[serde(with = "u128_dec_format")]
pub amount: Balance,
/// The amount locked due to staking
#[serde(with = "u128_dec_format")]
pub locked: Balance,
/// Hash of the code stored in the storage for this account.
pub code_hash: CryptoHash,
/// Storage used by the given account.
/// Storage used by the given account (in bytes).
pub storage_usage: StorageUsage,
/// Last height at which the storage was paid for.
pub storage_paid_at: BlockHeight,
Expand All @@ -24,6 +28,42 @@ impl Account {
}
}

/// Calculates the storage and the name rent for the given account
/// for period from `account.storage_paid_at` to the current `block_height`
pub fn calculate_rent(
account_id: &AccountId,
account: &Account,
block_height: BlockHeight,
account_length_baseline_cost_per_block: Balance,
storage_cost_byte_per_block: Balance,
) -> Balance {
u128::from(block_height.saturating_sub(account.storage_paid_at))
* rent_per_block(
account_id,
account,
account_length_baseline_cost_per_block,
storage_cost_byte_per_block,
)
}

/// Calculates an account rent per block
pub fn rent_per_block(
account_id: &AccountId,
account: &Account,
account_length_baseline_cost_per_block: Balance,
storage_cost_byte_per_block: Balance,
) -> Balance {
let account_length_cost_per_block = if account_id.len() > 10 {
0
} else {
account_length_baseline_cost_per_block / 3_u128.pow(account_id.len() as u32 - 2)
};

let storage_cost_per_block = u128::from(account.storage_usage) * storage_cost_byte_per_block;

account_length_cost_per_block + storage_cost_per_block
}

/// 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
2 changes: 1 addition & 1 deletion core/primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub type MerkleHash = CryptoHash;
pub type ValidatorId = u64;
/// Mask which validators participated in multi sign.
pub type ValidatorMask = Vec<bool>;
/// StorageUsage is used to count the amount of storage used by a contract.
/// StorageUsage is used to count the amount of storage used by a contract (in bytes).
pub type StorageUsage = u64;
/// StorageUsageChange is used to count the storage usage within a single contract call.
pub type StorageUsageChange = i64;
Expand Down
2 changes: 1 addition & 1 deletion core/primitives/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ where
/// it shows its json representation. It is used to display complex
/// objects using tracing.
///
/// ```
/// ```ignore
/// tracing::debug!(target: "diagnostic", value=%ser(&object));
/// ```
pub fn ser<'a, T>(object: &'a T) -> Serializable<'a, T>
Expand Down
33 changes: 29 additions & 4 deletions core/primitives/src/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use chrono::{DateTime, Utc};
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::{PublicKey, Signature};

use crate::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission};
use crate::account::{
calculate_rent, AccessKey, AccessKeyPermission, Account, FunctionCallPermission,
};
use crate::block::{Approval, Block, BlockHeader, BlockHeaderInnerLite, BlockHeaderInnerRest};
use crate::challenge::{Challenge, ChallengesResult};
use crate::errors::TxExecutionError;
Expand All @@ -32,23 +34,46 @@ use crate::types::{
/// A view of the account
#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct AccountView {
/// A balance from storage
#[serde(with = "u128_dec_format")]
pub amount: Balance,
/// Storage rent to pay on next transaction
#[serde(with = "u128_dec_format")]
pub rent: Balance,
/// The amount locked due to staking
#[serde(with = "u128_dec_format")]
pub locked: Balance,
/// Hash of the code stored in the storage for this account.
pub code_hash: CryptoHash,
/// Storage used by the given account (in bytes).
pub storage_usage: StorageUsage,
/// Last height at which the storage was paid for.
pub storage_paid_at: BlockHeight,
}

impl From<Account> for AccountView {
fn from(account: Account) -> Self {
impl AccountView {
/// Calculates spendable amount and transforms into the AccountView
pub fn from_account(
account_id: &AccountId,
account: &Account,
block_height: BlockHeight,
account_length_baseline_cost_per_block: Balance,
storage_cost_byte_per_block: Balance,
) -> AccountView {
let rent = calculate_rent(
account_id,
account,
block_height,
account_length_baseline_cost_per_block,
storage_cost_byte_per_block,
);
AccountView {
amount: account.amount,
locked: account.locked,
rent,
code_hash: account.code_hash,
storage_usage: account.storage_usage,
storage_paid_at: account.storage_paid_at,
locked: account.locked,
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions genesis-tools/genesis-csv-to-json/src/csv_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use csv::ReaderBuilder;
use near::config::AccountInfo;
use near_crypto::{KeyType, PublicKey};
use near_network::PeerInfo;
use near_primitives::account::Account;
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum};
use near_primitives::serialize::to_base64;
use near_primitives::transaction::{Action, FunctionCallAction};
use near_primitives::types::{AccountId, Balance, Gas};
use near_primitives::utils::{create_nonce_with_nonce, is_valid_account_id};
use near_primitives::views::{AccessKeyPermissionView, AccessKeyView, AccountView};
use near_primitives::views::{AccessKeyPermissionView, AccessKeyView};
use node_runtime::StateRecord;
use serde::{Deserialize, Serialize};
use std::fs::File;
Expand Down Expand Up @@ -196,7 +197,7 @@ fn account_records(row: &Row, gas_price: Balance) -> Vec<StateRecord> {

let mut res = vec![StateRecord::Account {
account_id: row.account_id.clone(),
account: AccountView {
account: Account {
amount: row.amount,
locked: row.validator_stake,
code_hash: smart_contract_hash.into(),
Expand Down
5 changes: 2 additions & 3 deletions genesis-tools/genesis-populate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ use tempdir::TempDir;
use near::{get_store_path, GenesisConfig, NightshadeRuntime};
use near_chain::{Block, Chain, ChainStore, RuntimeAdapter, Tip};
use near_crypto::{InMemorySigner, KeyType};
use near_primitives::account::AccessKey;
use near_primitives::account::{AccessKey, Account};
use near_primitives::block::genesis_chunks;
use near_primitives::contract::ContractCode;
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::serialize::to_base64;
use near_primitives::types::{AccountId, Balance, ChunkExtra, EpochId, ShardId, StateRoot};
use near_primitives::views::AccountView;
use near_store::{
create_store, get_account, set_access_key, set_account, set_code, ColState, Store, TrieUpdate,
};
Expand Down Expand Up @@ -252,7 +251,7 @@ impl GenesisBuilder {
self.state_updates.remove(&shard_id).expect("State update should have been added");

let signer = InMemorySigner::from_seed(&account_id, KeyType::ED25519, &account_id);
let account = AccountView {
let account = Account {
amount: testing_init_balance,
locked: testing_init_stake,
code_hash: self.additional_accounts_code_hash.clone(),
Expand Down
5 changes: 2 additions & 3 deletions near/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@ use near_network::test_utils::open_port;
use near_network::types::{PROTOCOL_VERSION, ROUTED_MESSAGE_TTL};
use near_network::utils::blacklist_from_vec;
use near_network::NetworkConfig;
use near_primitives::account::AccessKey;
use near_primitives::account::{AccessKey, Account};
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::serialize::{to_base64, u128_dec_format};
use near_primitives::types::{
AccountId, Balance, BlockHeightDelta, Gas, NumBlocks, NumSeats, NumShards, ShardId,
};
use near_primitives::utils::{generate_random_string, get_num_seats_per_shard};
use near_primitives::views::AccountView;
use near_telemetry::TelemetryConfig;
use node_runtime::config::RuntimeConfig;
use node_runtime::StateRecord;
Expand Down Expand Up @@ -659,7 +658,7 @@ fn state_records_account_with_key(
vec![
StateRecord::Account {
account_id: account_id.to_string(),
account: AccountView {
account: Account {
amount,
locked: staked,
code_hash,
Expand Down
33 changes: 23 additions & 10 deletions near/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use near_primitives::types::{
ValidatorStats,
};
use near_primitives::utils::{prefix_for_access_key, ACCOUNT_DATA_SEPARATOR};
use near_primitives::views::AccountView;
use near_primitives::views::{
AccessKeyInfoView, CallResult, EpochValidatorInfo, QueryError, QueryResponse,
QueryResponseKind, ViewStateResult,
Expand Down Expand Up @@ -911,13 +912,25 @@ impl RuntimeAdapter for NightshadeRuntime {
return Err("Path must contain at least single token".into());
}
match path_parts[0] {
"account" => match self.view_account(*state_root, &AccountId::from(path_parts[1])) {
Ok(r) => Ok(QueryResponse {
kind: QueryResponseKind::ViewAccount(r.into()),
block_height,
}),
Err(e) => Err(e),
},
"account" => {
let account_id = AccountId::from(path_parts[1]);
match self.view_account(*state_root, &account_id) {
Ok(account) => {
let runtime_config = &self.genesis_config.runtime_config;
Ok(QueryResponse {
kind: QueryResponseKind::ViewAccount(AccountView::from_account(
&account_id,
&account,
block_height,
runtime_config.account_length_baseline_cost_per_block,
runtime_config.storage_cost_byte_per_block,
)),
block_height,
})
}
Err(e) => Err(e),
}
}
"call" => {
let mut logs = vec![];
match self.call_function(
Expand Down Expand Up @@ -1183,6 +1196,7 @@ mod test {
use near_chain::{ReceiptResult, RuntimeAdapter, Tip};
use near_client::BlockProducer;
use near_crypto::{InMemorySigner, KeyType, Signer};
use near_primitives::account::Account;
use near_primitives::block::WeightAndScore;
use near_primitives::challenge::{ChallengesResult, SlashedValidator};
use near_primitives::hash::{hash, CryptoHash};
Expand All @@ -1197,7 +1211,7 @@ mod test {
};
use near_primitives::utils::key_for_account;
use near_primitives::views::{
AccountView, CurrentEpochValidatorInfo, EpochValidatorInfo, NextEpochValidatorInfo,
CurrentEpochValidatorInfo, EpochValidatorInfo, NextEpochValidatorInfo,
};
use near_store::create_store;
use node_runtime::adapter::ViewRuntimeAdapter;
Expand Down Expand Up @@ -1413,12 +1427,11 @@ mod test {
self.step(vec![transactions], vec![true], ChallengesResult::default());
}

pub fn view_account(&self, account_id: &str) -> AccountView {
pub fn view_account(&self, account_id: &str) -> Account {
let shard_id = self.runtime.account_id_to_shard_id(&account_id.to_string());
self.runtime
.view_account(self.state_roots[shard_id as usize], &account_id.to_string())
.unwrap()
.into()
}

/// Compute per epoch per validator reward and per epoch protocol treasury reward
Expand Down
Loading