From 1074e29e306ce2d1ce46988f1af93e4ae58e4049 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Thu, 6 Apr 2023 13:58:13 +0900 Subject: [PATCH 1/9] feat: use namespace -> codehash map instead of single code hash --- core/primitives-core/src/account.rs | 25 ++++--- core/primitives-core/src/lib.rs | 2 + core/primitives-core/src/namespace.rs | 54 ++++++++++++++++ core/primitives-core/src/routing_table.rs | 79 +++++++++++++++++++++++ core/primitives/src/lib.rs | 1 + core/primitives/src/trie_key.rs | 13 +++- core/primitives/src/types.rs | 3 + core/store/src/lib.rs | 5 ++ core/store/src/trie/split_state.rs | 3 +- 9 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 core/primitives-core/src/namespace.rs create mode 100644 core/primitives-core/src/routing_table.rs diff --git a/core/primitives-core/src/account.rs b/core/primitives-core/src/account.rs index 6b8e77260ad..eedeeba5bb5 100644 --- a/core/primitives-core/src/account.rs +++ b/core/primitives-core/src/account.rs @@ -1,8 +1,10 @@ use crate::hash::CryptoHash; +use crate::namespace::Namespace; use crate::serialize::dec_format; use crate::types::{Balance, Nonce, StorageUsage}; use borsh::{BorshDeserialize, BorshSerialize}; pub use near_account_id as id; +use std::collections::HashMap; use std::io; #[derive( @@ -36,7 +38,7 @@ pub struct Account { #[serde(with = "dec_format")] locked: Balance, /// Hash of the code stored in the storage for this account. - code_hash: CryptoHash, + code_hashes: HashMap, /// Storage used by the given account, includes account id, this struct, access keys and other data. storage_usage: StorageUsage, /// Version of Account in re migrations and similar @@ -55,7 +57,7 @@ impl Account { code_hash: CryptoHash, storage_usage: StorageUsage, ) -> Self { - Account { amount, locked, code_hash, storage_usage, version: AccountVersion::V1 } + Account { amount, locked, code_hashes: [(Namespace::default(), code_hash)].into_iter().collect(), storage_usage, version: AccountVersion::V1 } } #[inline] @@ -70,7 +72,12 @@ impl Account { #[inline] pub fn code_hash(&self) -> CryptoHash { - self.code_hash + self.code_hashes.get(&Namespace::default()).cloned().unwrap_or_default() + } + + #[inline] + pub fn code_hashes(&self) -> &HashMap { + &self.code_hashes } #[inline] @@ -95,7 +102,7 @@ impl Account { #[inline] pub fn set_code_hash(&mut self, code_hash: CryptoHash) { - self.code_hash = code_hash; + self.code_hashes.insert(Namespace::default(), code_hash); } #[inline] @@ -112,7 +119,7 @@ impl Account { struct LegacyAccount { amount: Balance, locked: Balance, - code_hash: CryptoHash, + code_hashes: HashMap, storage_usage: StorageUsage, } @@ -124,7 +131,7 @@ impl BorshDeserialize for Account { Ok(Account { amount: deserialized_account.amount, locked: deserialized_account.locked, - code_hash: deserialized_account.code_hash, + code_hashes: deserialized_account.code_hashes, storage_usage: deserialized_account.storage_usage, version: AccountVersion::V1, }) @@ -137,7 +144,7 @@ impl BorshSerialize for Account { AccountVersion::V1 => LegacyAccount { amount: self.amount, locked: self.locked, - code_hash: self.code_hash, + code_hashes: self.code_hashes.clone(), storage_usage: self.storage_usage, } .serialize(writer), @@ -256,14 +263,14 @@ mod tests { let old_account = LegacyAccount { amount: 100, locked: 200, - code_hash: CryptoHash::default(), + code_hashes: HashMap::default(), storage_usage: 300, }; let mut old_bytes = &old_account.try_to_vec().unwrap()[..]; let new_account = ::deserialize(&mut old_bytes).unwrap(); assert_eq!(new_account.amount, old_account.amount); assert_eq!(new_account.locked, old_account.locked); - assert_eq!(new_account.code_hash, old_account.code_hash); + assert_eq!(new_account.code_hashes, old_account.code_hashes); assert_eq!(new_account.storage_usage, old_account.storage_usage); assert_eq!(new_account.version, AccountVersion::V1); let mut new_bytes = &new_account.try_to_vec().unwrap()[..]; diff --git a/core/primitives-core/src/lib.rs b/core/primitives-core/src/lib.rs index 8b24882a6a8..e085a922cbc 100644 --- a/core/primitives-core/src/lib.rs +++ b/core/primitives-core/src/lib.rs @@ -5,8 +5,10 @@ pub mod account; pub mod config; pub mod contract; pub mod hash; +pub mod namespace; pub mod parameter; pub mod profile; +pub mod routing_table; pub mod runtime; pub mod serialize; pub mod types; diff --git a/core/primitives-core/src/namespace.rs b/core/primitives-core/src/namespace.rs new file mode 100644 index 00000000000..3646138ce08 --- /dev/null +++ b/core/primitives-core/src/namespace.rs @@ -0,0 +1,54 @@ +use std::ops::Deref; + +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +// TODO: Character restraints (e.g. only alphanumeric) + +#[derive( + BorshSerialize, + BorshDeserialize, + Serialize, + Deserialize, + PartialEq, + PartialOrd, + Eq, + Ord, + Clone, + Debug, + Default, + Hash, +)] +pub struct Namespace(String); + +impl From for Namespace { + fn from(value: String) -> Self { + Self(value) + } +} + +impl From<&str> for Namespace { + fn from(value: &str) -> Self { + Self(value.to_string()) + } +} + +impl From for String { + fn from(value: Namespace) -> Self { + value.0 + } +} + +impl AsRef for Namespace { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl Deref for Namespace { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/core/primitives-core/src/routing_table.rs b/core/primitives-core/src/routing_table.rs new file mode 100644 index 00000000000..3bf06cbd4a6 --- /dev/null +++ b/core/primitives-core/src/routing_table.rs @@ -0,0 +1,79 @@ +use std::collections::HashMap; + +use borsh::{BorshDeserialize, BorshSerialize}; + +use crate::namespace::Namespace; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Default)] +pub struct RoutingTable { + table: HashMap, +} + +impl RoutingTable { + pub fn new() -> Self { + Default::default() + } + + pub fn merge(&mut self, other: RoutingTable) { + self.table.extend(other.table); + } + + pub fn add( + &mut self, + incoming_method_name: String, + target_namespace: Namespace, + target_method_name: String, + ) { + self.table.insert(incoming_method_name, (target_namespace, target_method_name)); + } + + pub fn resolve(&self, incoming_method_name: &str) -> Option<&(Namespace, String)> { + self.table.get(incoming_method_name) + } + + pub fn inverse_resolve( + &self, + target_namespace: &Namespace, + target_method_name: &str, + ) -> Option<&String> { + self.table + .iter() + .find(|(_, (namespace, method_name))| { + namespace == target_namespace && method_name == target_method_name + }) + .map(|(incoming_method_name, _)| incoming_method_name) + } +} + +#[cfg(test)] +mod tests { + use crate::namespace::Namespace; + + use super::RoutingTable; + + #[test] + fn routing_table_merge() { + let mut table_a = RoutingTable::new(); + let mut table_b = RoutingTable::new(); + + let namespace_a: Namespace = "namespace_a".into(); + let namespace_b: Namespace = "namespace_b".into(); + + table_a.add("method_a".to_string(), namespace_a.clone(), "method_a".to_string()); + table_a.add("method_b".to_string(), namespace_a.clone(), "method_b".to_string()); + + table_b.add("method_b".to_string(), namespace_b.clone(), "method_b".to_string()); + table_b.add("method_c".to_string(), namespace_b.clone(), "method_c".to_string()); + + table_a.merge(table_b); + + assert_eq!( + table_a.resolve("method_a"), + Some(&(namespace_a.clone(), "method_a".to_string())) + ); + assert_eq!( + table_a.resolve("method_b"), + Some(&(namespace_b.clone(), "method_b".to_string())) + ); + } +} diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index ce028b8c1b4..94888f13569 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -5,6 +5,7 @@ pub use near_primitives_core::contract; pub use near_primitives_core::hash; pub use near_primitives_core::num_rational; pub use near_primitives_core::profile; +pub use near_primitives_core::routing_table; pub use near_primitives_core::serialize; pub mod block; diff --git a/core/primitives/src/trie_key.rs b/core/primitives/src/trie_key.rs index cced62860ff..098e1037cef 100644 --- a/core/primitives/src/trie_key.rs +++ b/core/primitives/src/trie_key.rs @@ -38,8 +38,9 @@ pub(crate) mod col { pub const DELAYED_RECEIPT: u8 = 8; /// This column id is used when storing Key-Value data from a contract on an `account_id`. pub const CONTRACT_DATA: u8 = 9; + pub const ROUTING_TABLE: u8 = 10; /// All columns - pub const NON_DELAYED_RECEIPT_COLUMNS: [(u8, &str); 8] = [ + pub const NON_DELAYED_RECEIPT_COLUMNS: [(u8, &str); 9] = [ (ACCOUNT, "Account"), (CONTRACT_CODE, "ContractCode"), (ACCESS_KEY, "AccessKey"), @@ -48,6 +49,7 @@ pub(crate) mod col { (PENDING_DATA_COUNT, "PendingDataCount"), (POSTPONED_RECEIPT, "PostponedReceipt"), (CONTRACT_DATA, "ContractData"), + (ROUTING_TABLE, "RoutingTable"), ]; } @@ -86,6 +88,7 @@ pub enum TrieKey { /// Used to store a key-value record `Vec` within a contract deployed on a given `AccountId` /// and a given key. ContractData { account_id: AccountId, key: Vec }, + RoutingTable { account_id: AccountId }, } /// Provides `len` function. @@ -142,7 +145,8 @@ impl TrieKey { + account_id.len() + ACCOUNT_DATA_SEPARATOR.len() + key.len() - } + }, + TrieKey::RoutingTable { account_id } => col::ROUTING_TABLE.len() + account_id.len(), } } @@ -202,6 +206,10 @@ impl TrieKey { buf.push(ACCOUNT_DATA_SEPARATOR); buf.extend(key); } + TrieKey::RoutingTable { account_id } => { + buf.push(col::ROUTING_TABLE); + buf.extend(account_id.as_ref().as_bytes()); + } }; debug_assert_eq!(expected_len, buf.len() - start_len); } @@ -225,6 +233,7 @@ impl TrieKey { TrieKey::DelayedReceiptIndices => None, TrieKey::DelayedReceipt { .. } => None, TrieKey::ContractData { account_id, .. } => Some(account_id.clone()), + TrieKey::RoutingTable { account_id } => Some(account_id.clone()), } } } diff --git a/core/primitives/src/types.rs b/core/primitives/src/types.rs index 93145d16e30..5cded7416c7 100644 --- a/core/primitives/src/types.rs +++ b/core/primitives/src/types.rs @@ -334,6 +334,9 @@ impl StateChanges { }, )); } + TrieKey::RoutingTable { .. } => { + // TODO: implement + } // The next variants considered as unnecessary as too low level TrieKey::ReceivedData { .. } => {} TrieKey::PostponedReceiptId { .. } => {} diff --git a/core/store/src/lib.rs b/core/store/src/lib.rs index 146df3db90b..afd14196ee3 100644 --- a/core/store/src/lib.rs +++ b/core/store/src/lib.rs @@ -7,6 +7,7 @@ use std::{fmt, io}; use borsh::{BorshDeserialize, BorshSerialize}; use metadata::{DbKind, DbVersion, KIND_KEY, VERSION_KEY}; +use near_primitives::routing_table::RoutingTable; use once_cell::sync::Lazy; use strum; @@ -854,6 +855,10 @@ pub fn get_code( trie.get(&key).map(|opt| opt.map(|code| ContractCode::new(code, code_hash))) } +pub fn get_routing_table(trie: &dyn TrieAccess, account_id: &AccountId) -> Result, StorageError> { + get(trie, &TrieKey::RoutingTable { account_id: account_id.clone() }) +} + /// Removes account, code and all access keys associated to it. pub fn remove_account( state_update: &mut TrieUpdate, diff --git a/core/store/src/trie/split_state.rs b/core/store/src/trie/split_state.rs index 4f0af2f8580..7cde5e9a448 100644 --- a/core/store/src/trie/split_state.rs +++ b/core/store/src/trie/split_state.rs @@ -73,7 +73,8 @@ impl ShardTries { | TrieKey::PostponedReceiptId { receiver_id: account_id, .. } | TrieKey::PendingDataCount { receiver_id: account_id, .. } | TrieKey::PostponedReceipt { receiver_id: account_id, .. } - | TrieKey::ContractData { account_id, .. } => { + | TrieKey::ContractData { account_id, .. } + | TrieKey::RoutingTable { account_id } => { let new_shard_uid = account_id_to_shard_id(account_id); // we can safely unwrap here because the caller of this function guarantees trie_updates contains all shard_uids for the new shards let trie_update = trie_updates.get_mut(&new_shard_uid).unwrap(); From bb2aaf7bab2bab8a5f1fe161fa4a2dee421d6bb6 Mon Sep 17 00:00:00 2001 From: Jacob Date: Mon, 10 Apr 2023 15:25:03 +0900 Subject: [PATCH 2/9] chore: storage updates, namespace table in routing table --- chain/chain/src/store.rs | 6 +- core/primitives-core/src/routing_table.rs | 78 ++++++++---- core/primitives/src/trie_key.rs | 120 +++++++++++++++--- core/primitives/src/types.rs | 4 +- core/store/src/flat/delta.rs | 6 +- core/store/src/lib.rs | 32 ++++- core/store/src/trie/split_state.rs | 2 +- .../src/tests/runtime/state_viewer.rs | 2 +- runtime/runtime/src/actions.rs | 2 +- tools/state-viewer/src/contract_accounts.rs | 4 +- 10 files changed, 200 insertions(+), 56 deletions(-) diff --git a/chain/chain/src/store.rs b/chain/chain/src/store.rs index 74b3fc6d4c5..c55612277dc 100644 --- a/chain/chain/src/store.rs +++ b/chain/chain/src/store.rs @@ -796,9 +796,9 @@ impl ChainStore { StateChangesRequest::ContractCodeChanges { account_ids } => { let mut changes = StateChanges::new(); for account_id in account_ids { - let data_key = TrieKey::ContractCode { account_id: account_id.clone() }; - let storage_key = KeyForStateChanges::from_trie_key(block_hash, &data_key); - let changes_per_key = storage_key.find_exact_iter(&self.store); + let data_key = trie_key_parsers::get_raw_prefix_for_contract_code(account_id, &[]); + let storage_key = KeyForStateChanges::from_raw_key(block_hash, &data_key); + let changes_per_key = storage_key.find_iter(&self.store); changes.extend(StateChanges::from_contract_code_changes(changes_per_key)?); } changes diff --git a/core/primitives-core/src/routing_table.rs b/core/primitives-core/src/routing_table.rs index 3bf06cbd4a6..41efaa0faba 100644 --- a/core/primitives-core/src/routing_table.rs +++ b/core/primitives-core/src/routing_table.rs @@ -2,11 +2,25 @@ use std::collections::HashMap; use borsh::{BorshDeserialize, BorshSerialize}; -use crate::namespace::Namespace; +use crate::{hash::CryptoHash, namespace::Namespace}; #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Default)] pub struct RoutingTable { - table: HashMap, + namespace_table: HashMap, + method_resolution_table: HashMap, +} + +pub struct RegisteredNamespace<'a> { + registered_to: &'a mut RoutingTable, + namespace: Namespace, +} + +impl<'a> RegisteredNamespace<'a> { + pub fn add(&mut self, incoming_method_name: String, target_method_name: String) { + self.registered_to + .method_resolution_table + .insert(incoming_method_name, (self.namespace.clone(), target_method_name)); + } } impl RoutingTable { @@ -14,29 +28,42 @@ impl RoutingTable { Default::default() } - pub fn merge(&mut self, other: RoutingTable) { - self.table.extend(other.table); + pub fn namespace<'s>(&'s mut self, namespace: Namespace) -> Option> { + if self.namespace_table.contains_key(&namespace) { + Some(RegisteredNamespace { registered_to: self, namespace }) + } else { + None + } } - pub fn add( + pub fn register_namespace( &mut self, - incoming_method_name: String, - target_namespace: Namespace, - target_method_name: String, - ) { - self.table.insert(incoming_method_name, (target_namespace, target_method_name)); + namespace: Namespace, + code_hash: CryptoHash, + ) -> RegisteredNamespace { + self.namespace_table.insert(namespace.clone(), code_hash); + RegisteredNamespace { registered_to: self, namespace } } - pub fn resolve(&self, incoming_method_name: &str) -> Option<&(Namespace, String)> { - self.table.get(incoming_method_name) + pub fn unregister_namespace(&mut self, namespace: &Namespace) { + self.namespace_table.remove(namespace); } - pub fn inverse_resolve( + pub fn merge(&mut self, other: RoutingTable) { + self.namespace_table.extend(other.namespace_table); + self.method_resolution_table.extend(other.method_resolution_table); + } + + pub fn resolve_method(&self, incoming_method_name: &str) -> Option<&(Namespace, String)> { + self.method_resolution_table.get(incoming_method_name) + } + + pub fn inverse_resolve_method( &self, target_namespace: &Namespace, target_method_name: &str, ) -> Option<&String> { - self.table + self.method_resolution_table .iter() .find(|(_, (namespace, method_name))| { namespace == target_namespace && method_name == target_method_name @@ -59,21 +86,28 @@ mod tests { let namespace_a: Namespace = "namespace_a".into(); let namespace_b: Namespace = "namespace_b".into(); - table_a.add("method_a".to_string(), namespace_a.clone(), "method_a".to_string()); - table_a.add("method_b".to_string(), namespace_a.clone(), "method_b".to_string()); + let method_a = "method_a".to_string(); + let method_b = "method_b".to_string(); + let method_c = "method_c".to_string(); + + let mut ta_a = table_a.register_namespace(namespace_a.clone(), Default::default()); + let mut tb_b = table_b.register_namespace(namespace_b.clone(), Default::default()); + + ta_a.add(method_a.clone(), method_a.clone()); + ta_a.add(method_b.clone(), method_b.clone()); - table_b.add("method_b".to_string(), namespace_b.clone(), "method_b".to_string()); - table_b.add("method_c".to_string(), namespace_b.clone(), "method_c".to_string()); + tb_b.add(method_b.clone(), method_b.clone()); + tb_b.add(method_c.clone(), method_c.clone()); table_a.merge(table_b); assert_eq!( - table_a.resolve("method_a"), - Some(&(namespace_a.clone(), "method_a".to_string())) + table_a.resolve_method(&method_a), + Some(&(namespace_a.clone(), method_a.clone())), ); assert_eq!( - table_a.resolve("method_b"), - Some(&(namespace_b.clone(), "method_b".to_string())) + table_a.resolve_method("method_b"), + Some(&(namespace_b.clone(), method_b.clone())), ); } } diff --git a/core/primitives/src/trie_key.rs b/core/primitives/src/trie_key.rs index 098e1037cef..f9e54b79d8d 100644 --- a/core/primitives/src/trie_key.rs +++ b/core/primitives/src/trie_key.rs @@ -3,6 +3,7 @@ use std::mem::size_of; use borsh::{BorshDeserialize, BorshSerialize}; use near_crypto::PublicKey; +use near_primitives_core::namespace::Namespace; use crate::hash::CryptoHash; use crate::types::AccountId; @@ -57,38 +58,65 @@ pub(crate) mod col { #[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)] pub enum TrieKey { /// Used to store `primitives::account::Account` struct for a given `AccountId`. - Account { account_id: AccountId }, + Account { + account_id: AccountId, + }, /// Used to store `Vec` contract code for a given `AccountId`. - ContractCode { account_id: AccountId }, + ContractCode { + account_id: AccountId, + namespace: Namespace, + }, /// Used to store `primitives::account::AccessKey` struct for a given `AccountId` and /// a given `public_key` of the `AccessKey`. - AccessKey { account_id: AccountId, public_key: PublicKey }, + AccessKey { + account_id: AccountId, + public_key: PublicKey, + }, /// Used to store `primitives::receipt::ReceivedData` struct for a given receiver's `AccountId` /// of `DataReceipt` and a given `data_id` (the unique identifier for the data). /// NOTE: This is one of the input data for some action receipt. /// The action receipt might be still not be received or requires more pending input data. - ReceivedData { receiver_id: AccountId, data_id: CryptoHash }, + ReceivedData { + receiver_id: AccountId, + data_id: CryptoHash, + }, /// Used to store receipt ID `primitives::hash::CryptoHash` for a given receiver's `AccountId` /// of the receipt and a given `data_id` (the unique identifier for the required input data). /// NOTE: This receipt ID indicates the postponed receipt. We store `receipt_id` for performance /// purposes to avoid deserializing the entire receipt. - PostponedReceiptId { receiver_id: AccountId, data_id: CryptoHash }, + PostponedReceiptId { + receiver_id: AccountId, + data_id: CryptoHash, + }, /// Used to store the number of still missing input data `u32` for a given receiver's /// `AccountId` and a given `receipt_id` of the receipt. - PendingDataCount { receiver_id: AccountId, receipt_id: CryptoHash }, + PendingDataCount { + receiver_id: AccountId, + receipt_id: CryptoHash, + }, /// Used to store the postponed receipt `primitives::receipt::Receipt` for a given receiver's /// `AccountId` and a given `receipt_id` of the receipt. - PostponedReceipt { receiver_id: AccountId, receipt_id: CryptoHash }, + PostponedReceipt { + receiver_id: AccountId, + receipt_id: CryptoHash, + }, /// Used to store indices of the delayed receipts queue (`node-runtime::DelayedReceiptIndices`). /// NOTE: It is a singleton per shard. DelayedReceiptIndices, /// Used to store a delayed receipt `primitives::receipt::Receipt` for a given index `u64` /// in a delayed receipt queue. The queue is unique per shard. - DelayedReceipt { index: u64 }, + DelayedReceipt { + index: u64, + }, /// Used to store a key-value record `Vec` within a contract deployed on a given `AccountId` /// and a given key. - ContractData { account_id: AccountId, key: Vec }, - RoutingTable { account_id: AccountId }, + ContractData { + account_id: AccountId, + key: Vec, + }, + RoutingTable { + account_id: AccountId, + }, } /// Provides `len` function. @@ -110,7 +138,12 @@ impl TrieKey { pub fn len(&self) -> usize { match self { TrieKey::Account { account_id } => col::ACCOUNT.len() + account_id.len(), - TrieKey::ContractCode { account_id } => col::CONTRACT_CODE.len() + account_id.len(), + TrieKey::ContractCode { account_id, namespace } => { + col::CONTRACT_CODE.len() + + account_id.len() + + ACCOUNT_DATA_SEPARATOR.len() + + namespace.len() + } TrieKey::AccessKey { account_id, public_key } => { col::ACCESS_KEY.len() * 2 + account_id.len() + public_key.len() } @@ -145,7 +178,7 @@ impl TrieKey { + account_id.len() + ACCOUNT_DATA_SEPARATOR.len() + key.len() - }, + } TrieKey::RoutingTable { account_id } => col::ROUTING_TABLE.len() + account_id.len(), } } @@ -159,9 +192,11 @@ impl TrieKey { buf.push(col::ACCOUNT); buf.extend(account_id.as_ref().as_bytes()); } - TrieKey::ContractCode { account_id } => { + TrieKey::ContractCode { account_id, namespace } => { buf.push(col::CONTRACT_CODE); buf.extend(account_id.as_ref().as_bytes()); + buf.push(ACCOUNT_DATA_SEPARATOR); + buf.extend(namespace.as_ref().as_bytes()); } TrieKey::AccessKey { account_id, public_key } => { buf.push(col::ACCESS_KEY); @@ -256,6 +291,29 @@ pub mod trie_key_parsers { PublicKey::try_from_slice(&raw_key[prefix_len..]) } + pub fn parse_namespace_from_contract_code_key<'a>( + raw_key: &'a [u8], + account_id: &AccountId, + ) -> Result { + let prefix_len = col::CONTRACT_CODE.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len(); + if raw_key.len() < prefix_len { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "raw key is too short for TrieKey::ContractCode", + )); + } + let namespace: Namespace = + if let Ok(namespace) = std::str::from_utf8(&raw_key[prefix_len..]).map(Into::into) { + namespace + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "namespace part of contract code trie key unparsable", + )); + }; + Ok(namespace) + } + pub fn parse_data_key_from_contract_data_key<'a>( raw_key: &'a [u8], account_id: &AccountId, @@ -353,8 +411,15 @@ pub mod trie_key_parsers { pub fn parse_account_id_from_contract_code_key( raw_key: &[u8], ) -> Result { - let account_id = parse_account_id_prefix(col::CONTRACT_CODE, raw_key)?; - parse_account_id_from_slice(account_id, "ContractCode") + let account_id_prefix = parse_account_id_prefix(col::CONTRACT_CODE, raw_key)?; + if let Some(account_id) = next_token(account_id_prefix, ACCOUNT_DATA_SEPARATOR) { + parse_account_id_from_slice(account_id, "ContractCode") + } else { + Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "raw key does not have ACCOUNT_DATA_SEPARATOR to be TrieKey::ContractCode", + )) + } } pub fn parse_trie_key_access_key_from_raw_key( @@ -446,6 +511,20 @@ pub mod trie_key_parsers { res.extend(prefix); res } + + pub fn get_raw_prefix_for_contract_code(account_id: &AccountId, prefix: &[u8]) -> Vec { + let mut res = Vec::with_capacity( + col::CONTRACT_CODE.len() + + account_id.len() + + ACCOUNT_DATA_SEPARATOR.len() + + prefix.len(), + ); + res.push(col::CONTRACT_CODE); + res.extend(account_id.as_bytes()); + res.push(ACCOUNT_DATA_SEPARATOR); + res.extend(prefix); + res + } } #[cfg(test)] @@ -556,7 +635,10 @@ mod tests { #[test] fn test_key_for_code_consistency() { for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::().unwrap()) { - let key = TrieKey::ContractCode { account_id: account_id.clone() }; + let key = TrieKey::ContractCode { + account_id: account_id.clone(), + namespace: Namespace::default(), + }; let raw_key = key.to_vec(); assert_eq!(raw_key.len(), key.len()); assert_eq!( @@ -662,7 +744,11 @@ mod tests { Some(account_id.clone()) ); assert_eq!( - TrieKey::ContractCode { account_id: account_id.clone() }.get_account_id(), + TrieKey::ContractCode { + account_id: account_id.clone(), + namespace: Namespace::default(), + } + .get_account_id(), Some(account_id.clone()) ); assert_eq!( diff --git a/core/primitives/src/types.rs b/core/primitives/src/types.rs index 5cded7416c7..c67263e5b9a 100644 --- a/core/primitives/src/types.rs +++ b/core/primitives/src/types.rs @@ -107,7 +107,7 @@ impl StateChangesKinds { TrieKey::Account { account_id } => { Some(Ok(StateChangeKind::AccountTouched { account_id })) } - TrieKey::ContractCode { account_id } => { + TrieKey::ContractCode { account_id, namespace } => { Some(Ok(StateChangeKind::ContractCodeTouched { account_id })) } TrieKey::AccessKey { account_id, .. } => { @@ -299,7 +299,7 @@ impl StateChanges { }, )) } - TrieKey::ContractCode { account_id } => { + TrieKey::ContractCode { account_id, namespace: _ } => { // TODO: Should this state change kind include namespace? state_changes.extend(changes.into_iter().map( |RawStateChange { cause, data }| StateChangeWithCause { cause, diff --git a/core/store/src/flat/delta.rs b/core/store/src/flat/delta.rs index 537e2bc4816..d759a7c2d9a 100644 --- a/core/store/src/flat/delta.rs +++ b/core/store/src/flat/delta.rs @@ -143,9 +143,9 @@ mod tests { /// Check correctness of creating `FlatStateChanges` from state changes. #[test] fn flat_state_changes_creation() { - let alice_trie_key = TrieKey::ContractCode { account_id: "alice".parse().unwrap() }; - let bob_trie_key = TrieKey::ContractCode { account_id: "bob".parse().unwrap() }; - let carol_trie_key = TrieKey::ContractCode { account_id: "carol".parse().unwrap() }; + let alice_trie_key = TrieKey::ContractCode { account_id: "alice".parse().unwrap(), namespace: Default::default() }; + let bob_trie_key = TrieKey::ContractCode { account_id: "bob".parse().unwrap(), namespace: Default::default() }; + let carol_trie_key = TrieKey::ContractCode { account_id: "carol".parse().unwrap(), namespace: Default::default() }; let delayed_trie_key = TrieKey::DelayedReceiptIndices; let delayed_receipt_trie_key = TrieKey::DelayedReceipt { index: 1 }; diff --git a/core/store/src/lib.rs b/core/store/src/lib.rs index afd14196ee3..01e07587f57 100644 --- a/core/store/src/lib.rs +++ b/core/store/src/lib.rs @@ -843,7 +843,10 @@ pub fn get_access_key_raw( } pub fn set_code(state_update: &mut TrieUpdate, account_id: AccountId, code: &ContractCode) { - state_update.set(TrieKey::ContractCode { account_id }, code.code().to_vec()); + state_update.set( + TrieKey::ContractCode { account_id, namespace: Default::default() }, + code.code().to_vec(), + ); } pub fn get_code( @@ -851,11 +854,15 @@ pub fn get_code( account_id: &AccountId, code_hash: Option, ) -> Result, StorageError> { - let key = TrieKey::ContractCode { account_id: account_id.clone() }; + let key = + TrieKey::ContractCode { account_id: account_id.clone(), namespace: Default::default() }; trie.get(&key).map(|opt| opt.map(|code| ContractCode::new(code, code_hash))) } -pub fn get_routing_table(trie: &dyn TrieAccess, account_id: &AccountId) -> Result, StorageError> { +pub fn get_routing_table( + trie: &dyn TrieAccess, + account_id: &AccountId, +) -> Result, StorageError> { get(trie, &TrieKey::RoutingTable { account_id: account_id.clone() }) } @@ -865,7 +872,24 @@ pub fn remove_account( account_id: &AccountId, ) -> Result<(), StorageError> { state_update.remove(TrieKey::Account { account_id: account_id.clone() }); - state_update.remove(TrieKey::ContractCode { account_id: account_id.clone() }); + state_update.remove(TrieKey::RoutingTable { account_id: account_id.clone() }); + + // Remove all deployed (namespaced) contract codes + let namespaces = state_update + .iter(&trie_key_parsers::get_raw_prefix_for_contract_code(account_id, &[]))? + .map(|raw_key| { + trie_key_parsers::parse_namespace_from_contract_code_key(&raw_key?, account_id).map_err( + |_e| { + StorageError::StorageInconsistentState( + "Can't parse namespace from raw key for ContractCode".to_string(), + ) + }, + ) + }) + .collect::, _>>()?; + for namespace in namespaces { + state_update.remove(TrieKey::ContractCode { account_id: account_id.clone(), namespace }); + } // Removing access keys let public_keys = state_update diff --git a/core/store/src/trie/split_state.rs b/core/store/src/trie/split_state.rs index 7cde5e9a448..018101f9cb9 100644 --- a/core/store/src/trie/split_state.rs +++ b/core/store/src/trie/split_state.rs @@ -67,7 +67,7 @@ impl ShardTries { None => {} }, TrieKey::Account { account_id } - | TrieKey::ContractCode { account_id } + | TrieKey::ContractCode { account_id, .. } | TrieKey::AccessKey { account_id, .. } | TrieKey::ReceivedData { receiver_id: account_id, .. } | TrieKey::PostponedReceiptId { receiver_id: account_id, .. } diff --git a/integration-tests/src/tests/runtime/state_viewer.rs b/integration-tests/src/tests/runtime/state_viewer.rs index e17120662a8..0b5e3006ff4 100644 --- a/integration-tests/src/tests/runtime/state_viewer.rs +++ b/integration-tests/src/tests/runtime/state_viewer.rs @@ -368,7 +368,7 @@ fn test_view_state_with_large_contract() { alice_account(), &Account::new(0, 0, sha256(&contract_code), 50_001), ); - state_update.set(TrieKey::ContractCode { account_id: alice_account() }, contract_code); + state_update.set(TrieKey::ContractCode { account_id: alice_account(), namespace: Default::default() }, contract_code); let trie_viewer = TrieViewer::new(Some(50_000), None); let result = trie_viewer.view_state(&state_update, &alice_account(), b"", false); assert!(result.is_ok()); diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index fa0e2191337..2eb8e09edd5 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -1120,7 +1120,7 @@ mod tests { let mut state_update = tries.new_trie_update(ShardUId::single_shard(), CryptoHash::default()); let account_id = "alice".parse::().unwrap(); - let trie_key = TrieKey::ContractCode { account_id: account_id.clone() }; + let trie_key = TrieKey::ContractCode { account_id: account_id.clone(), namespace: Default::default() }; let empty_contract = [0; 10_000].to_vec(); let contract_hash = hash(&empty_contract); state_update.set(trie_key, empty_contract); diff --git a/tools/state-viewer/src/contract_accounts.rs b/tools/state-viewer/src/contract_accounts.rs index 910d64aeda4..1f28c4df9a8 100644 --- a/tools/state-viewer/src/contract_accounts.rs +++ b/tools/state-viewer/src/contract_accounts.rs @@ -193,7 +193,7 @@ impl ContractAccountIterator { let mut trie_iter = trie.iter()?; // TODO(#8376): Consider changing the interface to TrieKey to make this easier. // `TrieKey::ContractCode` requires a valid `AccountId`, we use "xx" - let key = TrieKey::ContractCode { account_id: "xx".parse()? }.to_vec(); + let key = TrieKey::ContractCode { account_id: "xx".parse()?, namespace: Default::default() }.to_vec(); let (prefix, suffix) = key.split_at(key.len() - 2); assert_eq!(suffix, "xx".as_bytes()); @@ -645,7 +645,7 @@ mod tests { /// Create a test contract key-value pair to insert in the test trie, with specified amount of bytes. fn contract_tuple(account: &str, num_bytes: u8) -> (Vec, Option>) { ( - TrieKey::ContractCode { account_id: account.parse().unwrap() }.to_vec(), + TrieKey::ContractCode { account_id: account.parse().unwrap(), namespace: Default::default() }.to_vec(), Some(vec![num_bytes; num_bytes as usize]), ) } From 3d7711ca059c5ac552441bee64c4025137e3ee2b Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Wed, 12 Apr 2023 13:41:15 +0900 Subject: [PATCH 3/9] wip checkpoint --- core/primitives-core/src/namespace.rs | 16 +++++- core/primitives-core/src/routing_table.rs | 51 ++++-------------- core/primitives/src/trie_key.rs | 64 ++++++++++++++++++++--- core/primitives/src/types.rs | 2 +- core/store/src/lib.rs | 14 +++-- runtime/runtime/src/actions.rs | 2 +- runtime/runtime/src/ext.rs | 6 ++- runtime/runtime/src/state_viewer/mod.rs | 2 +- 8 files changed, 99 insertions(+), 58 deletions(-) diff --git a/core/primitives-core/src/namespace.rs b/core/primitives-core/src/namespace.rs index 3646138ce08..8c97cbcbd1e 100644 --- a/core/primitives-core/src/namespace.rs +++ b/core/primitives-core/src/namespace.rs @@ -1,4 +1,4 @@ -use std::ops::Deref; +use std::{ops::Deref, string::FromUtf8Error}; use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; @@ -21,6 +21,14 @@ use serde::{Deserialize, Serialize}; )] pub struct Namespace(String); +impl TryFrom<&'_ [u8]> for Namespace { + type Error = FromUtf8Error; + + fn try_from(value: &'_ [u8]) -> Result { + Ok(Self(String::from_utf8(value.to_vec())?)) + } +} + impl From for Namespace { fn from(value: String) -> Self { Self(value) @@ -45,6 +53,12 @@ impl AsRef for Namespace { } } +impl AsRef<[u8]> for Namespace { + fn as_ref(&self) -> &[u8] { + self.0.as_bytes() + } +} + impl Deref for Namespace { type Target = String; diff --git a/core/primitives-core/src/routing_table.rs b/core/primitives-core/src/routing_table.rs index 41efaa0faba..2cee2daab31 100644 --- a/core/primitives-core/src/routing_table.rs +++ b/core/primitives-core/src/routing_table.rs @@ -6,51 +6,25 @@ use crate::{hash::CryptoHash, namespace::Namespace}; #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Default)] pub struct RoutingTable { - namespace_table: HashMap, method_resolution_table: HashMap, } -pub struct RegisteredNamespace<'a> { - registered_to: &'a mut RoutingTable, - namespace: Namespace, -} - -impl<'a> RegisteredNamespace<'a> { - pub fn add(&mut self, incoming_method_name: String, target_method_name: String) { - self.registered_to - .method_resolution_table - .insert(incoming_method_name, (self.namespace.clone(), target_method_name)); - } -} - impl RoutingTable { pub fn new() -> Self { Default::default() } - pub fn namespace<'s>(&'s mut self, namespace: Namespace) -> Option> { - if self.namespace_table.contains_key(&namespace) { - Some(RegisteredNamespace { registered_to: self, namespace }) - } else { - None - } - } - - pub fn register_namespace( + pub fn add( &mut self, - namespace: Namespace, - code_hash: CryptoHash, - ) -> RegisteredNamespace { - self.namespace_table.insert(namespace.clone(), code_hash); - RegisteredNamespace { registered_to: self, namespace } - } - - pub fn unregister_namespace(&mut self, namespace: &Namespace) { - self.namespace_table.remove(namespace); + incoming_method_name: String, + target_namespace: Namespace, + target_method_name: String, + ) { + self.method_resolution_table + .insert(incoming_method_name, (target_namespace, target_method_name)); } pub fn merge(&mut self, other: RoutingTable) { - self.namespace_table.extend(other.namespace_table); self.method_resolution_table.extend(other.method_resolution_table); } @@ -90,14 +64,11 @@ mod tests { let method_b = "method_b".to_string(); let method_c = "method_c".to_string(); - let mut ta_a = table_a.register_namespace(namespace_a.clone(), Default::default()); - let mut tb_b = table_b.register_namespace(namespace_b.clone(), Default::default()); - - ta_a.add(method_a.clone(), method_a.clone()); - ta_a.add(method_b.clone(), method_b.clone()); + table_a.add(method_a.clone(), namespace_a.clone(), method_a.clone()); + table_a.add(method_b.clone(), namespace_a.clone(), method_b.clone()); - tb_b.add(method_b.clone(), method_b.clone()); - tb_b.add(method_c.clone(), method_c.clone()); + table_b.add(method_b.clone(), namespace_b.clone(), method_b.clone()); + table_b.add(method_c.clone(), namespace_b.clone(), method_c.clone()); table_a.merge(table_b); diff --git a/core/primitives/src/trie_key.rs b/core/primitives/src/trie_key.rs index f9e54b79d8d..c37d661c9ae 100644 --- a/core/primitives/src/trie_key.rs +++ b/core/primitives/src/trie_key.rs @@ -112,6 +112,7 @@ pub enum TrieKey { /// and a given key. ContractData { account_id: AccountId, + namespace: Namespace, key: Vec, }, RoutingTable { @@ -173,10 +174,12 @@ impl TrieKey { } TrieKey::DelayedReceiptIndices => col::DELAYED_RECEIPT_INDICES.len(), TrieKey::DelayedReceipt { .. } => col::DELAYED_RECEIPT.len() + size_of::(), - TrieKey::ContractData { account_id, key } => { + TrieKey::ContractData { account_id, namespace, key } => { col::CONTRACT_DATA.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len() + + namespace.len() + + ACCOUNT_DATA_SEPARATOR.len() + key.len() } TrieKey::RoutingTable { account_id } => col::ROUTING_TABLE.len() + account_id.len(), @@ -196,7 +199,7 @@ impl TrieKey { buf.push(col::CONTRACT_CODE); buf.extend(account_id.as_ref().as_bytes()); buf.push(ACCOUNT_DATA_SEPARATOR); - buf.extend(namespace.as_ref().as_bytes()); + buf.extend(namespace.as_bytes()); } TrieKey::AccessKey { account_id, public_key } => { buf.push(col::ACCESS_KEY); @@ -235,10 +238,12 @@ impl TrieKey { buf.push(col::DELAYED_RECEIPT_INDICES); buf.extend(&index.to_le_bytes()); } - TrieKey::ContractData { account_id, key } => { + TrieKey::ContractData { account_id, namespace, key } => { buf.push(col::CONTRACT_DATA); buf.extend(account_id.as_ref().as_bytes()); buf.push(ACCOUNT_DATA_SEPARATOR); + buf.extend(namespace.as_bytes()); + buf.push(ACCOUNT_DATA_SEPARATOR); buf.extend(key); } TrieKey::RoutingTable { account_id } => { @@ -328,6 +333,38 @@ pub mod trie_key_parsers { Ok(&raw_key[prefix_len..]) } + pub fn parse_parts_from_contract_data_key<'a>( + raw_key: &'a [u8], + account_id: &AccountId, + ) -> Result<(Namespace, &'a [u8]), std::io::Error> { + let prefix_len = col::CONTRACT_DATA.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len(); + if raw_key.len() < prefix_len { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "raw key is too short for TrieKey::ContractData", + )); + } + let (namespace, namespace_slice_len) = next_token(&raw_key[prefix_len..], ACCOUNT_DATA_SEPARATOR) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "namespace part of contract data trie key unparsable", + ) + }) + .and_then(|s| { + Namespace::try_from(s).map(|n| (n, s.len())).map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "could not decode namespace part of contract data trie key as utf-8", + ) + }) + })?; + + let data_key = &raw_key[prefix_len + namespace_slice_len + ACCOUNT_DATA_SEPARATOR.len()..]; + + Ok((namespace, data_key)) + } + pub fn parse_account_id_prefix<'a>( column: u8, raw_key: &'a [u8], @@ -498,16 +535,20 @@ pub mod trie_key_parsers { res } - pub fn get_raw_prefix_for_contract_data(account_id: &AccountId, prefix: &[u8]) -> Vec { + pub fn get_raw_prefix_for_contract_data(account_id: &AccountId, namespace: &Namespace, prefix: &[u8]) -> Vec { let mut res = Vec::with_capacity( col::CONTRACT_DATA.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len() + + namespace.len() + + ACCOUNT_DATA_SEPARATOR.len() + prefix.len(), ); res.push(col::CONTRACT_DATA); res.extend(account_id.as_bytes()); res.push(ACCOUNT_DATA_SEPARATOR); + res.extend(namespace.as_bytes()); + res.push(ACCOUNT_DATA_SEPARATOR); res.extend(prefix); res } @@ -612,8 +653,11 @@ mod tests { fn test_key_for_data_consistency() { let data_key = b"0123456789" as &[u8]; for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::().unwrap()) { - let key = - TrieKey::ContractData { account_id: account_id.clone(), key: data_key.to_vec() }; + let key = TrieKey::ContractData { + account_id: account_id.clone(), + namespace: Default::default(), + key: data_key.to_vec(), + }; let raw_key = key.to_vec(); assert_eq!(raw_key.len(), key.len()); assert_eq!( @@ -791,8 +835,12 @@ mod tests { assert_eq!(TrieKey::DelayedReceipt { index: Default::default() }.get_account_id(), None); assert_eq!(TrieKey::DelayedReceiptIndices.get_account_id(), None); assert_eq!( - TrieKey::ContractData { account_id: account_id.clone(), key: Default::default() } - .get_account_id(), + TrieKey::ContractData { + account_id: account_id.clone(), + namespace: Default::default(), + key: Default::default() + } + .get_account_id(), Some(account_id.clone()) ); } diff --git a/core/primitives/src/types.rs b/core/primitives/src/types.rs index c67263e5b9a..4891cb0d35b 100644 --- a/core/primitives/src/types.rs +++ b/core/primitives/src/types.rs @@ -315,7 +315,7 @@ impl StateChanges { }, )); } - TrieKey::ContractData { account_id, key } => { + TrieKey::ContractData { account_id, namespace, key } => { // TODO: Namespace here? state_changes.extend(changes.into_iter().map( |RawStateChange { cause, data }| StateChangeWithCause { cause, diff --git a/core/store/src/lib.rs b/core/store/src/lib.rs index 01e07587f57..edfb3b107c0 100644 --- a/core/store/src/lib.rs +++ b/core/store/src/lib.rs @@ -909,20 +909,24 @@ pub fn remove_account( } // Removing contract data - let data_keys = state_update + let data_paths = state_update .iter(&trie_key_parsers::get_raw_prefix_for_contract_data(account_id, &[]))? .map(|raw_key| { - trie_key_parsers::parse_data_key_from_contract_data_key(&raw_key?, account_id) + trie_key_parsers::parse_parts_from_contract_data_key(&raw_key?, account_id) .map_err(|_e| { StorageError::StorageInconsistentState( "Can't parse data key from raw key for ContractData".to_string(), ) }) - .map(Vec::from) + .map(|(namespace, key)| (namespace, key.to_vec())) }) .collect::, _>>()?; - for key in data_keys { - state_update.remove(TrieKey::ContractData { account_id: account_id.clone(), key }); + for (namespace, key) in data_paths { + state_update.remove(TrieKey::ContractData { + account_id: account_id.clone(), + namespace, + key, + }); } Ok(()) } diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 2eb8e09edd5..e2b461f27f3 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -55,7 +55,7 @@ pub(crate) fn execute_function_call( ) -> Result { let account_id = runtime_ext.account_id(); tracing::debug!(target: "runtime", %account_id, "Calling the contract"); - let code = match runtime_ext.get_code(account.code_hash()) { + let code = match runtime_ext.get_code(account.code_hashes()) { Ok(Some(code)) => code, Ok(None) => { let error = FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index 230ef0da4c5..9a0742cc49b 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -85,7 +85,11 @@ impl<'a> RuntimeExt<'a> { } pub fn create_storage_key(&self, key: &[u8]) -> TrieKey { - TrieKey::ContractData { account_id: self.account_id.clone(), key: key.to_vec() } + TrieKey::ContractData { + account_id: self.account_id.clone(), + namespace: Default::default(), + key: key.to_vec(), + } } pub fn set_trie_cache_mode(&mut self, state: TrieCacheMode) { diff --git a/runtime/runtime/src/state_viewer/mod.rs b/runtime/runtime/src/state_viewer/mod.rs index bd16a3d9844..00cd6a871f7 100644 --- a/runtime/runtime/src/state_viewer/mod.rs +++ b/runtime/runtime/src/state_viewer/mod.rs @@ -141,7 +141,7 @@ impl TrieViewer { }; let mut values = vec![]; - let query = trie_key_parsers::get_raw_prefix_for_contract_data(account_id, prefix); + let query = trie_key_parsers::get_raw_prefix_for_contract_data(account_id, Default::default(), prefix); let acc_sep_len = query.len() - prefix.len(); let mut iter = state_update.trie().iter()?; iter.remember_visited_nodes(include_proof); From 3d75608e2bd3dc46aa164e6406fd194f5a72c2b9 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Wed, 12 Apr 2023 16:14:21 +0900 Subject: [PATCH 4/9] namespace and routing table into account data, deploy contract and function call should dispatch --- chain/rosetta-rpc/src/adapters/mod.rs | 8 ++ .../validated_operations/deploy_contract.rs | 8 +- chain/rosetta-rpc/src/models.rs | 7 ++ chain/rosetta-rpc/src/types.rs | 62 +++++++++++- core/chain-configs/src/genesis_validate.rs | 8 +- core/primitives-core/src/account.rs | 30 +++++- core/primitives-core/src/namespace.rs | 6 ++ core/primitives-core/src/routing_table.rs | 30 +++--- core/primitives/src/lib.rs | 1 + core/primitives/src/state_record.rs | 34 ++++--- core/primitives/src/test_utils.rs | 14 ++- core/primitives/src/transaction.rs | 13 ++- core/primitives/src/trie_key.rs | 94 +++++-------------- core/primitives/src/types.rs | 3 - core/primitives/src/views.rs | 16 +++- core/store/src/lib.rs | 26 ++--- core/store/src/trie/split_state.rs | 3 +- core/store/src/trie/update.rs | 2 +- .../genesis-csv-to-json/src/csv_parser.rs | 3 +- genesis-tools/genesis-populate/src/lib.rs | 6 +- integration-tests/src/node/mod.rs | 3 +- .../src/tests/client/benchmarks.rs | 4 +- .../src/tests/client/cold_storage.rs | 4 + .../tests/client/features/delegate_action.rs | 10 +- .../features/increase_deployment_cost.rs | 8 +- .../src/tests/client/process_blocks.rs | 12 ++- .../src/tests/client/sharding_upgrade.rs | 4 + .../src/tests/runtime/deployment.rs | 8 +- .../src/tests/runtime/state_viewer.rs | 30 +++++- .../src/tests/standard_cases/mod.rs | 9 +- .../src/tests/standard_cases/runtime.rs | 1 + integration-tests/src/user/mod.rs | 8 +- runtime/near-vm-logic/src/receipt_manager.rs | 12 ++- .../src/action_costs.rs | 4 + runtime/runtime-params-estimator/src/lib.rs | 8 +- runtime/runtime-params-estimator/src/utils.rs | 8 +- runtime/runtime/src/actions.rs | 54 ++++++++--- runtime/runtime/src/config.rs | 6 +- runtime/runtime/src/ext.rs | 15 +-- runtime/runtime/src/genesis.rs | 15 +-- runtime/runtime/src/lib.rs | 19 ++-- runtime/runtime/src/prefetch.rs | 2 + runtime/runtime/src/state_viewer/mod.rs | 16 ++-- runtime/runtime/src/verifier.rs | 15 ++- .../runtime/tests/runtime_group_tools/mod.rs | 9 +- runtime/runtime/tests/test_async_calls.rs | 6 +- test-utils/runtime-tester/src/fuzzing.rs | 4 + test-utils/testlib/src/runtime_utils.rs | 7 +- tools/amend-genesis/src/lib.rs | 2 + tools/state-viewer/src/cli.rs | 1 + tools/state-viewer/src/commands.rs | 6 +- tools/state-viewer/src/contract_accounts.rs | 18 +++- tools/state-viewer/src/state_dump.rs | 12 ++- 53 files changed, 514 insertions(+), 200 deletions(-) diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 4f3ea2500ac..9c5aa630bd9 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -370,6 +370,8 @@ impl From for Vec { validated_operations::DeployContractOperation { account: receiver_account_identifier.clone(), code: action.code, + namespace: action.namespace, + routing_table: action.routing_table, } .into_related_operation( crate::models::OperationIdentifier::new(&operations), @@ -666,6 +668,8 @@ impl TryFrom> for NearActions { actions.push( near_primitives::transaction::DeployContractAction { code: deploy_contract_operation.code, + namespace: deploy_contract_operation.namespace, + routing_table: deploy_contract_operation.routing_table, } .into(), ) @@ -827,6 +831,8 @@ mod tests { use near_client::test_utils::setup_no_network; use near_crypto::{KeyType, SecretKey}; use near_primitives::delegate_action::{DelegateAction, SignedDelegateAction}; + use near_primitives::namespace::Namespace; + use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config::RuntimeConfig; use near_primitives::transaction::{Action, TransferAction}; use near_primitives::views::RuntimeConfigView; @@ -994,6 +1000,8 @@ mod tests { .into()]; let deploy_contract_actions = vec![near_primitives::transaction::DeployContractAction { code: b"binary-data".to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), } .into()]; let function_call_without_balance_actions = diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs b/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs index 4d0e5f32823..95ec40876fb 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs @@ -1,8 +1,12 @@ +use near_primitives::{namespace::Namespace, routing_table::RoutingTable}; + use super::ValidatedOperation; pub(crate) struct DeployContractOperation { pub(crate) account: crate::models::AccountIdentifier, pub(crate) code: Vec, + pub(crate) namespace: Namespace, + pub(crate) routing_table: RoutingTable, } impl ValidatedOperation for DeployContractOperation { @@ -43,7 +47,9 @@ impl TryFrom for DeployContractOperation { Self::validate_operation_type(operation.type_)?; let metadata = operation.metadata.ok_or_else(required_fields_error)?; let code = metadata.code.ok_or_else(required_fields_error)?.into_inner(); + let namespace = metadata.namespace.ok_or_else(required_fields_error)?.into(); + let routing_table = metadata.routing_table.ok_or_else(required_fields_error)?.into(); - Ok(Self { account: operation.account, code }) + Ok(Self { account: operation.account, code, namespace, routing_table }) } } diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index db95fb12d91..ee287071d64 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -1,8 +1,11 @@ +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use paperclip::actix::{api_v2_errors, Apiv2Schema}; use near_primitives::hash::CryptoHash; use near_primitives::types::{BlockHeight, Nonce}; +use crate::types::{TypedNamespace, TypedRoutingTable}; use crate::utils::{BlobInHexString, BorshInHexString}; /// An AccountBalanceRequest is utilized to make a balance request on the @@ -778,6 +781,10 @@ pub(crate) struct OperationMetadata { /// Has to be specified for DEPLOY_CONTRACT operation #[serde(skip_serializing_if = "Option::is_none")] pub code: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub namespace: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub routing_table: Option, /// Has to be specified for FUNCTION_CALL operation #[serde(skip_serializing_if = "Option::is_none")] pub method_name: Option, diff --git a/chain/rosetta-rpc/src/types.rs b/chain/rosetta-rpc/src/types.rs index c6030503e66..beeff7fbd93 100644 --- a/chain/rosetta-rpc/src/types.rs +++ b/chain/rosetta-rpc/src/types.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{fmt, ops::Deref}; #[derive( Eq, @@ -24,9 +24,69 @@ impl fmt::Debug for AccountId { } } +use near_primitives::{namespace::Namespace, routing_table::RoutingTable}; use paperclip::v2::{models::DataType, schema::TypedData}; +use serde::{Deserialize, Serialize}; impl TypedData for AccountId { fn data_type() -> DataType { DataType::String } } + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)] +pub(crate) struct TypedNamespace(Namespace); + +impl From for TypedNamespace { + fn from(value: Namespace) -> Self { + Self(value) + } +} + +impl From for Namespace { + fn from(value: TypedNamespace) -> Self { + value.0 + } +} + +impl Deref for TypedNamespace { + type Target = Namespace; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl TypedData for TypedNamespace { + fn data_type() -> DataType { + DataType::String + } +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)] +pub(crate) struct TypedRoutingTable(RoutingTable); + +impl From for TypedRoutingTable { + fn from(value: RoutingTable) -> Self { + Self(value) + } +} + +impl From for RoutingTable { + fn from(value: TypedRoutingTable) -> Self { + value.0 + } +} + +impl Deref for TypedRoutingTable { + type Target = RoutingTable; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl TypedData for TypedRoutingTable { + fn data_type() -> DataType { + DataType::Object + } +} diff --git a/core/chain-configs/src/genesis_validate.rs b/core/chain-configs/src/genesis_validate.rs index 45ae47c9aeb..d5d8244fc3f 100644 --- a/core/chain-configs/src/genesis_validate.rs +++ b/core/chain-configs/src/genesis_validate.rs @@ -193,6 +193,7 @@ mod test { use crate::GenesisRecords; use near_crypto::{KeyType, PublicKey}; use near_primitives::account::{AccessKey, Account}; + use near_primitives::namespace::Namespace; use near_primitives::types::AccountInfo; const VALID_ED25519_RISTRETTO_KEY: &str = "ed25519:KuTCtARNzxZQ3YvXDeLjx83FDqxv2SdQTSbiq876zR7"; @@ -299,10 +300,15 @@ mod test { config.total_supply = 110; let records = GenesisRecords(vec![ StateRecord::Account { account_id: "test".parse().unwrap(), account: create_account() }, - StateRecord::Contract { account_id: "test".parse().unwrap(), code: [1, 2, 3].to_vec() }, + StateRecord::Contract { + account_id: "test".parse().unwrap(), + code: [1, 2, 3].to_vec(), + namespace: Namespace::default(), + }, StateRecord::Contract { account_id: "test".parse().unwrap(), code: [1, 2, 3, 4].to_vec(), + namespace: Namespace::default(), }, ]); let genesis = &Genesis::new(config, records).unwrap(); diff --git a/core/primitives-core/src/account.rs b/core/primitives-core/src/account.rs index eedeeba5bb5..65aa862fc5f 100644 --- a/core/primitives-core/src/account.rs +++ b/core/primitives-core/src/account.rs @@ -1,5 +1,6 @@ use crate::hash::CryptoHash; use crate::namespace::Namespace; +use crate::routing_table::RoutingTable; use crate::serialize::dec_format; use crate::types::{Balance, Nonce, StorageUsage}; use borsh::{BorshDeserialize, BorshSerialize}; @@ -39,6 +40,7 @@ pub struct Account { locked: Balance, /// Hash of the code stored in the storage for this account. code_hashes: HashMap, + routing_table: RoutingTable, /// Storage used by the given account, includes account id, this struct, access keys and other data. storage_usage: StorageUsage, /// Version of Account in re migrations and similar @@ -57,7 +59,14 @@ impl Account { code_hash: CryptoHash, storage_usage: StorageUsage, ) -> Self { - Account { amount, locked, code_hashes: [(Namespace::default(), code_hash)].into_iter().collect(), storage_usage, version: AccountVersion::V1 } + Account { + amount, + locked, + code_hashes: [(Namespace::default(), code_hash)].into_iter().collect(), + routing_table: RoutingTable::new(), + storage_usage, + version: AccountVersion::V1, + } } #[inline] @@ -80,6 +89,16 @@ impl Account { &self.code_hashes } + #[inline] + pub fn routing_table(&self) -> &RoutingTable { + &self.routing_table + } + + #[inline] + pub fn routing_table_mut(&mut self) -> &mut RoutingTable { + &mut self.routing_table + } + #[inline] pub fn storage_usage(&self) -> StorageUsage { self.storage_usage @@ -105,6 +124,11 @@ impl Account { self.code_hashes.insert(Namespace::default(), code_hash); } + #[inline] + pub fn set_code_hash_for(&mut self, namespace: Namespace, code_hash: CryptoHash) { + self.code_hashes.insert(namespace, code_hash); + } + #[inline] pub fn set_storage_usage(&mut self, storage_usage: StorageUsage) { self.storage_usage = storage_usage; @@ -120,6 +144,7 @@ struct LegacyAccount { amount: Balance, locked: Balance, code_hashes: HashMap, + routing_table: RoutingTable, storage_usage: StorageUsage, } @@ -132,6 +157,7 @@ impl BorshDeserialize for Account { amount: deserialized_account.amount, locked: deserialized_account.locked, code_hashes: deserialized_account.code_hashes, + routing_table: deserialized_account.routing_table, storage_usage: deserialized_account.storage_usage, version: AccountVersion::V1, }) @@ -145,6 +171,7 @@ impl BorshSerialize for Account { amount: self.amount, locked: self.locked, code_hashes: self.code_hashes.clone(), + routing_table: self.routing_table.clone(), storage_usage: self.storage_usage, } .serialize(writer), @@ -264,6 +291,7 @@ mod tests { amount: 100, locked: 200, code_hashes: HashMap::default(), + routing_table: RoutingTable::default(), storage_usage: 300, }; let mut old_bytes = &old_account.try_to_vec().unwrap()[..]; diff --git a/core/primitives-core/src/namespace.rs b/core/primitives-core/src/namespace.rs index 8c97cbcbd1e..e905be4eb89 100644 --- a/core/primitives-core/src/namespace.rs +++ b/core/primitives-core/src/namespace.rs @@ -21,6 +21,12 @@ use serde::{Deserialize, Serialize}; )] pub struct Namespace(String); +impl std::fmt::Display for Namespace { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + impl TryFrom<&'_ [u8]> for Namespace { type Error = FromUtf8Error; diff --git a/core/primitives-core/src/routing_table.rs b/core/primitives-core/src/routing_table.rs index 2cee2daab31..d6e2bb6efed 100644 --- a/core/primitives-core/src/routing_table.rs +++ b/core/primitives-core/src/routing_table.rs @@ -2,12 +2,21 @@ use std::collections::HashMap; use borsh::{BorshDeserialize, BorshSerialize}; -use crate::{hash::CryptoHash, namespace::Namespace}; - -#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Default)] -pub struct RoutingTable { - method_resolution_table: HashMap, -} +use crate::namespace::Namespace; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Default, + PartialEq, + Eq, + serde::Serialize, + serde::Deserialize, +)] +#[serde(transparent)] +pub struct RoutingTable(HashMap); impl RoutingTable { pub fn new() -> Self { @@ -20,16 +29,15 @@ impl RoutingTable { target_namespace: Namespace, target_method_name: String, ) { - self.method_resolution_table - .insert(incoming_method_name, (target_namespace, target_method_name)); + self.0.insert(incoming_method_name, (target_namespace, target_method_name)); } pub fn merge(&mut self, other: RoutingTable) { - self.method_resolution_table.extend(other.method_resolution_table); + self.0.extend(other.0); } pub fn resolve_method(&self, incoming_method_name: &str) -> Option<&(Namespace, String)> { - self.method_resolution_table.get(incoming_method_name) + self.0.get(incoming_method_name) } pub fn inverse_resolve_method( @@ -37,7 +45,7 @@ impl RoutingTable { target_namespace: &Namespace, target_method_name: &str, ) -> Option<&String> { - self.method_resolution_table + self.0 .iter() .find(|(_, (namespace, method_name))| { namespace == target_namespace && method_name == target_method_name diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 94888f13569..d1f0246c9ca 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -3,6 +3,7 @@ pub use near_primitives_core::borsh; pub use near_primitives_core::config; pub use near_primitives_core::contract; pub use near_primitives_core::hash; +pub use near_primitives_core::namespace; pub use near_primitives_core::num_rational; pub use near_primitives_core::profile; pub use near_primitives_core::routing_table; diff --git a/core/primitives/src/state_record.rs b/core/primitives/src/state_record.rs index 62da28a869c..75508991093 100644 --- a/core/primitives/src/state_record.rs +++ b/core/primitives/src/state_record.rs @@ -7,11 +7,13 @@ use crate::trie_key::trie_key_parsers::{ parse_account_id_from_access_key_key, parse_account_id_from_account_key, parse_account_id_from_contract_code_key, parse_account_id_from_contract_data_key, parse_account_id_from_received_data_key, parse_data_id_from_received_data_key, - parse_data_key_from_contract_data_key, parse_public_key_from_access_key_key, + parse_data_key_from_contract_data_key, parse_namespace_from_contract_code_key, + parse_parts_from_contract_data_key, parse_public_key_from_access_key_key, }; use crate::types::AccountId; use borsh::BorshDeserialize; use near_crypto::PublicKey; +use near_primitives_core::namespace::Namespace; use std::fmt::{Display, Formatter}; /// Record in the state storage. @@ -22,6 +24,7 @@ pub enum StateRecord { /// Data records inside the contract, encoded in base64. Data { account_id: AccountId, + namespace: Namespace, #[serde(with = "base64_format")] data_key: Vec, #[serde(with = "base64_format")] @@ -30,6 +33,7 @@ pub enum StateRecord { /// Contract code encoded in base64. Contract { account_id: AccountId, + namespace: Namespace, #[serde(with = "base64_format")] code: Vec, }, @@ -62,13 +66,20 @@ impl StateRecord { }), col::CONTRACT_DATA => { let account_id = parse_account_id_from_contract_data_key(&key).unwrap(); - let data_key = parse_data_key_from_contract_data_key(&key, &account_id).unwrap(); - Some(StateRecord::Data { account_id, data_key: data_key.to_vec(), value }) + let (namespace, data_key) = + parse_parts_from_contract_data_key(&key, &account_id).unwrap(); + Some(StateRecord::Data { + account_id, + namespace, + data_key: data_key.to_vec(), + value, + }) + } + col::CONTRACT_CODE => { + let account_id = parse_account_id_from_contract_code_key(&key).unwrap(); + let namespace = parse_namespace_from_contract_code_key(&key, &account_id).unwrap(); + Some(StateRecord::Contract { account_id, namespace, code: value }) } - col::CONTRACT_CODE => Some(StateRecord::Contract { - account_id: parse_account_id_from_contract_code_key(&key).unwrap(), - code: value, - }), col::ACCESS_KEY => { let access_key = AccessKey::try_from_slice(&value).unwrap(); let account_id = parse_account_id_from_access_key_key(&key).unwrap(); @@ -103,15 +114,16 @@ impl Display for StateRecord { StateRecord::Account { account_id, account } => { write!(f, "Account {:?}: {:?}", account_id, account) } - StateRecord::Data { account_id, data_key, value } => write!( + StateRecord::Data { account_id, namespace, data_key, value } => write!( f, - "Storage {:?},{:?}: {:?}", + "Storage {:?}:{:?},{:?}: {:?}", account_id, + namespace, to_printable(data_key), to_printable(value) ), - StateRecord::Contract { account_id, code: _ } => { - write!(f, "Code for {:?}: ...", account_id) + StateRecord::Contract { account_id, namespace, code: _ } => { + write!(f, "Code for {:?}:{namespace}: ...", account_id) } StateRecord::AccessKey { account_id, public_key, access_key } => { write!(f, "Access key {:?},{:?}: {:?}", account_id, public_key, access_key) diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index ef9ff49fc4b..2156357b173 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -2,6 +2,8 @@ use std::collections::HashMap; use std::sync::Arc; use near_crypto::{EmptySigner, InMemorySigner, KeyType, PublicKey, SecretKey, Signature, Signer}; +use near_primitives_core::namespace::Namespace; +use near_primitives_core::routing_table::RoutingTable; use near_primitives_core::types::ProtocolVersion; use crate::account::{AccessKey, AccessKeyPermission, Account}; @@ -48,7 +50,11 @@ impl Transaction { } pub fn deploy_contract(mut self, code: Vec) -> Self { - self.actions.push(Action::DeployContract(DeployContractAction { code })); + self.actions.push(Action::DeployContract(DeployContractAction { + code, + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })); self } @@ -197,7 +203,11 @@ impl SignedTransaction { access_key: AccessKey { nonce: 0, permission: AccessKeyPermission::FullAccess }, }), Action::Transfer(TransferAction { deposit: amount }), - Action::DeployContract(DeployContractAction { code }), + Action::DeployContract(DeployContractAction { + code, + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + }), ], block_hash, ) diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index a0b760cb719..6ba79d58c36 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -8,7 +8,9 @@ use crate::types::{AccountId, Balance, Gas, Nonce}; use borsh::{BorshDeserialize, BorshSerialize}; use near_crypto::{PublicKey, Signature}; use near_o11y::pretty; +use near_primitives_core::namespace::Namespace; use near_primitives_core::profile::{ProfileDataV2, ProfileDataV3}; +use near_primitives_core::routing_table::RoutingTable; use near_primitives_core::types::Compute; use std::borrow::Borrow; use std::fmt; @@ -121,6 +123,10 @@ pub struct DeployContractAction { /// WebAssembly binary #[serde(with = "base64_format")] pub code: Vec, + #[serde(default)] + pub namespace: Namespace, + #[serde(default)] + pub routing_table: RoutingTable, } impl From for Action { @@ -133,6 +139,7 @@ impl fmt::Debug for DeployContractAction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DeployContractAction") .field("code", &format_args!("{}", pretty::AbbrBytes(&self.code))) + .field("namespace", &format_args!("{}", &self.namespace)) .finish() } } @@ -564,7 +571,11 @@ mod tests { block_hash: Default::default(), actions: vec![ Action::CreateAccount(CreateAccountAction {}), - Action::DeployContract(DeployContractAction { code: vec![1, 2, 3] }), + Action::DeployContract(DeployContractAction { + code: vec![1, 2, 3], + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + }), Action::FunctionCall(FunctionCallAction { method_name: "qqq".to_string(), args: vec![1, 2, 3], diff --git a/core/primitives/src/trie_key.rs b/core/primitives/src/trie_key.rs index c37d661c9ae..f3afa6d2bc2 100644 --- a/core/primitives/src/trie_key.rs +++ b/core/primitives/src/trie_key.rs @@ -41,7 +41,7 @@ pub(crate) mod col { pub const CONTRACT_DATA: u8 = 9; pub const ROUTING_TABLE: u8 = 10; /// All columns - pub const NON_DELAYED_RECEIPT_COLUMNS: [(u8, &str); 9] = [ + pub const NON_DELAYED_RECEIPT_COLUMNS: [(u8, &str); 8] = [ (ACCOUNT, "Account"), (CONTRACT_CODE, "ContractCode"), (ACCESS_KEY, "AccessKey"), @@ -50,7 +50,6 @@ pub(crate) mod col { (PENDING_DATA_COUNT, "PendingDataCount"), (POSTPONED_RECEIPT, "PostponedReceipt"), (CONTRACT_DATA, "ContractData"), - (ROUTING_TABLE, "RoutingTable"), ]; } @@ -58,66 +57,37 @@ pub(crate) mod col { #[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)] pub enum TrieKey { /// Used to store `primitives::account::Account` struct for a given `AccountId`. - Account { - account_id: AccountId, - }, + Account { account_id: AccountId }, /// Used to store `Vec` contract code for a given `AccountId`. - ContractCode { - account_id: AccountId, - namespace: Namespace, - }, + ContractCode { account_id: AccountId, namespace: Namespace }, /// Used to store `primitives::account::AccessKey` struct for a given `AccountId` and /// a given `public_key` of the `AccessKey`. - AccessKey { - account_id: AccountId, - public_key: PublicKey, - }, + AccessKey { account_id: AccountId, public_key: PublicKey }, /// Used to store `primitives::receipt::ReceivedData` struct for a given receiver's `AccountId` /// of `DataReceipt` and a given `data_id` (the unique identifier for the data). /// NOTE: This is one of the input data for some action receipt. /// The action receipt might be still not be received or requires more pending input data. - ReceivedData { - receiver_id: AccountId, - data_id: CryptoHash, - }, + ReceivedData { receiver_id: AccountId, data_id: CryptoHash }, /// Used to store receipt ID `primitives::hash::CryptoHash` for a given receiver's `AccountId` /// of the receipt and a given `data_id` (the unique identifier for the required input data). /// NOTE: This receipt ID indicates the postponed receipt. We store `receipt_id` for performance /// purposes to avoid deserializing the entire receipt. - PostponedReceiptId { - receiver_id: AccountId, - data_id: CryptoHash, - }, + PostponedReceiptId { receiver_id: AccountId, data_id: CryptoHash }, /// Used to store the number of still missing input data `u32` for a given receiver's /// `AccountId` and a given `receipt_id` of the receipt. - PendingDataCount { - receiver_id: AccountId, - receipt_id: CryptoHash, - }, + PendingDataCount { receiver_id: AccountId, receipt_id: CryptoHash }, /// Used to store the postponed receipt `primitives::receipt::Receipt` for a given receiver's /// `AccountId` and a given `receipt_id` of the receipt. - PostponedReceipt { - receiver_id: AccountId, - receipt_id: CryptoHash, - }, + PostponedReceipt { receiver_id: AccountId, receipt_id: CryptoHash }, /// Used to store indices of the delayed receipts queue (`node-runtime::DelayedReceiptIndices`). /// NOTE: It is a singleton per shard. DelayedReceiptIndices, /// Used to store a delayed receipt `primitives::receipt::Receipt` for a given index `u64` /// in a delayed receipt queue. The queue is unique per shard. - DelayedReceipt { - index: u64, - }, + DelayedReceipt { index: u64 }, /// Used to store a key-value record `Vec` within a contract deployed on a given `AccountId` /// and a given key. - ContractData { - account_id: AccountId, - namespace: Namespace, - key: Vec, - }, - RoutingTable { - account_id: AccountId, - }, + ContractData { account_id: AccountId, namespace: Namespace, key: Vec }, } /// Provides `len` function. @@ -182,7 +152,6 @@ impl TrieKey { + ACCOUNT_DATA_SEPARATOR.len() + key.len() } - TrieKey::RoutingTable { account_id } => col::ROUTING_TABLE.len() + account_id.len(), } } @@ -246,10 +215,6 @@ impl TrieKey { buf.push(ACCOUNT_DATA_SEPARATOR); buf.extend(key); } - TrieKey::RoutingTable { account_id } => { - buf.push(col::ROUTING_TABLE); - buf.extend(account_id.as_ref().as_bytes()); - } }; debug_assert_eq!(expected_len, buf.len() - start_len); } @@ -273,7 +238,6 @@ impl TrieKey { TrieKey::DelayedReceiptIndices => None, TrieKey::DelayedReceipt { .. } => None, TrieKey::ContractData { account_id, .. } => Some(account_id.clone()), - TrieKey::RoutingTable { account_id } => Some(account_id.clone()), } } } @@ -323,14 +287,7 @@ pub mod trie_key_parsers { raw_key: &'a [u8], account_id: &AccountId, ) -> Result<&'a [u8], std::io::Error> { - let prefix_len = col::CONTRACT_DATA.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len(); - if raw_key.len() < prefix_len { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - "raw key is too short for TrieKey::ContractData", - )); - } - Ok(&raw_key[prefix_len..]) + parse_parts_from_contract_data_key(raw_key, account_id).map(|o| o.1) } pub fn parse_parts_from_contract_data_key<'a>( @@ -344,21 +301,22 @@ pub mod trie_key_parsers { "raw key is too short for TrieKey::ContractData", )); } - let (namespace, namespace_slice_len) = next_token(&raw_key[prefix_len..], ACCOUNT_DATA_SEPARATOR) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "namespace part of contract data trie key unparsable", - ) - }) - .and_then(|s| { - Namespace::try_from(s).map(|n| (n, s.len())).map_err(|e| { + let (namespace, namespace_slice_len) = + next_token(&raw_key[prefix_len..], ACCOUNT_DATA_SEPARATOR) + .ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::InvalidData, - "could not decode namespace part of contract data trie key as utf-8", + "namespace part of contract data trie key unparsable", ) }) - })?; + .and_then(|s| { + Namespace::try_from(s).map(|n| (n, s.len())).map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "could not decode namespace part of contract data trie key as utf-8", + ) + }) + })?; let data_key = &raw_key[prefix_len + namespace_slice_len + ACCOUNT_DATA_SEPARATOR.len()..]; @@ -535,20 +493,16 @@ pub mod trie_key_parsers { res } - pub fn get_raw_prefix_for_contract_data(account_id: &AccountId, namespace: &Namespace, prefix: &[u8]) -> Vec { + pub fn get_raw_prefix_for_contract_data(account_id: &AccountId, prefix: &[u8]) -> Vec { let mut res = Vec::with_capacity( col::CONTRACT_DATA.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len() - + namespace.len() - + ACCOUNT_DATA_SEPARATOR.len() + prefix.len(), ); res.push(col::CONTRACT_DATA); res.extend(account_id.as_bytes()); res.push(ACCOUNT_DATA_SEPARATOR); - res.extend(namespace.as_bytes()); - res.push(ACCOUNT_DATA_SEPARATOR); res.extend(prefix); res } diff --git a/core/primitives/src/types.rs b/core/primitives/src/types.rs index 4891cb0d35b..add6541a311 100644 --- a/core/primitives/src/types.rs +++ b/core/primitives/src/types.rs @@ -334,9 +334,6 @@ impl StateChanges { }, )); } - TrieKey::RoutingTable { .. } => { - // TODO: implement - } // The next variants considered as unnecessary as too low level TrieKey::ReceivedData { .. } => {} TrieKey::PostponedReceiptId { .. } => {} diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index c4fa3abdb70..3f8efe64923 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -41,6 +41,8 @@ use chrono::DateTime; use near_crypto::{PublicKey, Signature}; use near_o11y::pretty; use near_primitives_core::config::{ActionCosts, ExtCosts, ParameterCost, VMConfig}; +use near_primitives_core::namespace::Namespace; +use near_primitives_core::routing_table::RoutingTable; use near_primitives_core::runtime::fees::Fee; use num_rational::Rational32; use std::collections::HashMap; @@ -1108,6 +1110,10 @@ pub enum ActionView { DeployContract { #[serde(with = "base64_format")] code: Vec, + #[serde(default)] + namespace: Namespace, + #[serde(default)] + routing_table: RoutingTable, }, FunctionCall { method_name: String, @@ -1148,7 +1154,11 @@ impl From for ActionView { Action::CreateAccount(_) => ActionView::CreateAccount, Action::DeployContract(action) => { let code = hash(&action.code).as_ref().to_vec(); - ActionView::DeployContract { code } + ActionView::DeployContract { + code, + namespace: action.namespace, + routing_table: action.routing_table, + } } Action::FunctionCall(action) => ActionView::FunctionCall { method_name: action.method_name, @@ -1182,8 +1192,8 @@ impl TryFrom for Action { fn try_from(action_view: ActionView) -> Result { Ok(match action_view { ActionView::CreateAccount => Action::CreateAccount(CreateAccountAction {}), - ActionView::DeployContract { code } => { - Action::DeployContract(DeployContractAction { code }) + ActionView::DeployContract { code, namespace, routing_table } => { + Action::DeployContract(DeployContractAction { code, namespace, routing_table }) } ActionView::FunctionCall { method_name, args, gas, deposit } => { Action::FunctionCall(FunctionCallAction { method_name, args, gas, deposit }) diff --git a/core/store/src/lib.rs b/core/store/src/lib.rs index edfb3b107c0..bf89535c6a0 100644 --- a/core/store/src/lib.rs +++ b/core/store/src/lib.rs @@ -7,7 +7,7 @@ use std::{fmt, io}; use borsh::{BorshDeserialize, BorshSerialize}; use metadata::{DbKind, DbVersion, KIND_KEY, VERSION_KEY}; -use near_primitives::routing_table::RoutingTable; +use near_primitives::namespace::Namespace; use once_cell::sync::Lazy; use strum; @@ -842,37 +842,31 @@ pub fn get_access_key_raw( ) } -pub fn set_code(state_update: &mut TrieUpdate, account_id: AccountId, code: &ContractCode) { - state_update.set( - TrieKey::ContractCode { account_id, namespace: Default::default() }, - code.code().to_vec(), - ); +pub fn set_code( + state_update: &mut TrieUpdate, + account_id: AccountId, + namespace: Namespace, + code: &ContractCode, +) { + state_update.set(TrieKey::ContractCode { account_id, namespace }, code.code().to_vec()); } pub fn get_code( trie: &dyn TrieAccess, account_id: &AccountId, + namespace: Namespace, code_hash: Option, ) -> Result, StorageError> { - let key = - TrieKey::ContractCode { account_id: account_id.clone(), namespace: Default::default() }; + let key = TrieKey::ContractCode { account_id: account_id.clone(), namespace }; trie.get(&key).map(|opt| opt.map(|code| ContractCode::new(code, code_hash))) } -pub fn get_routing_table( - trie: &dyn TrieAccess, - account_id: &AccountId, -) -> Result, StorageError> { - get(trie, &TrieKey::RoutingTable { account_id: account_id.clone() }) -} - /// Removes account, code and all access keys associated to it. pub fn remove_account( state_update: &mut TrieUpdate, account_id: &AccountId, ) -> Result<(), StorageError> { state_update.remove(TrieKey::Account { account_id: account_id.clone() }); - state_update.remove(TrieKey::RoutingTable { account_id: account_id.clone() }); // Remove all deployed (namespaced) contract codes let namespaces = state_update diff --git a/core/store/src/trie/split_state.rs b/core/store/src/trie/split_state.rs index 018101f9cb9..4a3167c60a4 100644 --- a/core/store/src/trie/split_state.rs +++ b/core/store/src/trie/split_state.rs @@ -73,8 +73,7 @@ impl ShardTries { | TrieKey::PostponedReceiptId { receiver_id: account_id, .. } | TrieKey::PendingDataCount { receiver_id: account_id, .. } | TrieKey::PostponedReceipt { receiver_id: account_id, .. } - | TrieKey::ContractData { account_id, .. } - | TrieKey::RoutingTable { account_id } => { + | TrieKey::ContractData { account_id, .. } => { let new_shard_uid = account_id_to_shard_id(account_id); // we can safely unwrap here because the caller of this function guarantees trie_updates contains all shard_uids for the new shards let trie_update = trie_updates.get_mut(&new_shard_uid).unwrap(); diff --git a/core/store/src/trie/update.rs b/core/store/src/trie/update.rs index ada4b76b28c..00d567a4892 100644 --- a/core/store/src/trie/update.rs +++ b/core/store/src/trie/update.rs @@ -179,7 +179,7 @@ mod tests { const COMPLEX_SHARD_UID: ShardUId = ShardUId { version: SHARD_VERSION, shard_id: 0 }; fn test_key(key: Vec) -> TrieKey { - TrieKey::ContractData { account_id: "alice".parse().unwrap(), key } + TrieKey::ContractData { account_id: "alice".parse().unwrap(), namespace: Default::default(), key } } #[test] diff --git a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs index 068de030491..5d80f500183 100644 --- a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs +++ b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs @@ -6,6 +6,7 @@ use near_crypto::{KeyType, PublicKey}; use near_network::types::PeerInfo; use near_primitives::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission}; use near_primitives::hash::{hash, CryptoHash}; +use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; use near_primitives::state_record::StateRecord; use near_primitives::transaction::{Action, FunctionCallAction}; @@ -223,7 +224,7 @@ fn account_records(row: &Row, gas_price: Balance) -> Vec { // Add smart contract code if was specified. if let Some(code) = smart_contract_code { - res.push(StateRecord::Contract { account_id: row.account_id.clone(), code }); + res.push(StateRecord::Contract { account_id: row.account_id.clone(), code, namespace: Namespace::default() }); } // Add init function call if smart contract was provided. diff --git a/genesis-tools/genesis-populate/src/lib.rs b/genesis-tools/genesis-populate/src/lib.rs index 1ecc49d55e3..998e63ae67b 100644 --- a/genesis-tools/genesis-populate/src/lib.rs +++ b/genesis-tools/genesis-populate/src/lib.rs @@ -12,6 +12,7 @@ use near_primitives::account::{AccessKey, Account}; use near_primitives::block::{genesis_chunks, Tip}; use near_primitives::contract::ContractCode; use near_primitives::hash::{hash, CryptoHash}; +use near_primitives::namespace::Namespace; use near_primitives::shard_layout::{account_id_to_shard_id, ShardUId}; use near_primitives::state_record::StateRecord; use near_primitives::types::chunk_extra::ChunkExtra; @@ -288,8 +289,9 @@ impl GenesisBuilder { records.push(access_key_record); if let Some(wasm_binary) = self.additional_accounts_code.as_ref() { let code = ContractCode::new(wasm_binary.clone(), None); - set_code(&mut state_update, account_id.clone(), &code); - let contract_record = StateRecord::Contract { account_id, code: wasm_binary.clone() }; + let namespace = Namespace::default(); + set_code(&mut state_update, account_id.clone(), namespace.clone(), &code); + let contract_record = StateRecord::Contract { account_id, code: wasm_binary.clone(), namespace }; records.push(contract_record); } diff --git a/integration-tests/src/node/mod.rs b/integration-tests/src/node/mod.rs index 13431f79feb..ee94f6e7530 100644 --- a/integration-tests/src/node/mod.rs +++ b/integration-tests/src/node/mod.rs @@ -9,6 +9,7 @@ use near_chain_configs::Genesis; use near_crypto::{InMemorySigner, Signer}; use near_jsonrpc_primitives::errors::ServerError; use near_primitives::contract::ContractCode; +use near_primitives::namespace::Namespace; use near_primitives::num_rational::Ratio; use near_primitives::state_record::StateRecord; use near_primitives::transaction::SignedTransaction; @@ -168,7 +169,7 @@ pub fn create_nodes_from_seeds(seeds: Vec) -> Vec { } assert!(is_account_record_found); records - .push(StateRecord::Contract { account_id: seed.parse().unwrap(), code: code.to_vec() }); + .push(StateRecord::Contract { account_id: seed.parse().unwrap(), code: code.to_vec(), namespace: Namespace::default() }); } near_configs_to_node_configs(configs, validator_signers, network_signers, genesis) } diff --git a/integration-tests/src/tests/client/benchmarks.rs b/integration-tests/src/tests/client/benchmarks.rs index a60d6840197..5d54a06518d 100644 --- a/integration-tests/src/tests/client/benchmarks.rs +++ b/integration-tests/src/tests/client/benchmarks.rs @@ -10,7 +10,7 @@ use near_chain::ChainGenesis; use near_chain_configs::Genesis; use near_client::test_utils::{create_chunk_on_height, TestEnv}; use near_crypto::{InMemorySigner, KeyType}; -use near_primitives::transaction::{Action, DeployContractAction, SignedTransaction}; +use near_primitives::{transaction::{Action, DeployContractAction, SignedTransaction}, namespace::Namespace, routing_table::RoutingTable}; use nearcore::config::GenesisExt; /// How long does it take to produce a large chunk? @@ -44,7 +44,7 @@ fn benchmark_large_chunk_production_time() { account_id.clone(), account_id.clone(), &signer, - vec![Action::DeployContract(DeployContractAction { code: vec![92; tx_size] })], + vec![Action::DeployContract(DeployContractAction { code: vec![92; tx_size], namespace: Namespace::default(), routing_table: RoutingTable::default() })], last_block_hash, ); env.clients[0].process_tx(tx, false, false); diff --git a/integration-tests/src/tests/client/cold_storage.rs b/integration-tests/src/tests/client/cold_storage.rs index 023fb2ede76..1058662ba95 100644 --- a/integration-tests/src/tests/client/cold_storage.rs +++ b/integration-tests/src/tests/client/cold_storage.rs @@ -8,6 +8,8 @@ use near_crypto::{InMemorySigner, KeyType}; use near_o11y::pretty; use near_o11y::testonly::init_test_logger; use near_primitives::block::Tip; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::sharding::ShardChunk; use near_primitives::transaction::{ Action, DeployContractAction, FunctionCallAction, SignedTransaction, @@ -98,6 +100,8 @@ fn test_storage_after_commit_of_cold_update() { &signer, vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::rs_contract().to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), })], last_hash, ); diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index d9ea1c6ddd5..582d41f4e1d 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -16,6 +16,8 @@ use near_primitives::errors::{ ActionError, ActionErrorKind, ActionsValidationError, InvalidAccessKeyError, InvalidTxError, TxExecutionError, }; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::test_utils::{create_user_test_signer, implicit_test_account}; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, @@ -433,7 +435,11 @@ fn meta_tx_deploy() { let code = smallest_rs_contract().to_vec(); let tx_cost = fee_helper.deploy_contract_cost(code.len() as u64); - let actions = vec![Action::DeployContract(DeployContractAction { code })]; + let actions = vec![Action::DeployContract(DeployContractAction { + code, + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })]; check_meta_tx_no_fn_call(&node, actions, tx_cost, 0, sender, relayer, receiver); } @@ -826,7 +832,7 @@ fn meta_tx_create_and_use_implicit_account() { let initial_amount = nearcore::NEAR_BASE; let actions = vec![ Action::Transfer(TransferAction { deposit: initial_amount }), - Action::DeployContract(DeployContractAction { code: ft_contract().to_vec() }), + Action::DeployContract(DeployContractAction { code: ft_contract().to_vec(), namespace: Namespace::default(), routing_table: RoutingTable::default() }), ]; // Execute and expect `AccountDoesNotExist`, as we try to call a meta diff --git a/integration-tests/src/tests/client/features/increase_deployment_cost.rs b/integration-tests/src/tests/client/features/increase_deployment_cost.rs index a4b4b90c88b..8d1b7dd6594 100644 --- a/integration-tests/src/tests/client/features/increase_deployment_cost.rs +++ b/integration-tests/src/tests/client/features/increase_deployment_cost.rs @@ -5,6 +5,8 @@ use near_client::test_utils::TestEnv; use near_crypto::{InMemorySigner, KeyType}; use near_epoch_manager::shard_tracker::TrackedConfig; use near_primitives::config::VMConfig; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::transaction::{Action, DeployContractAction}; use near_primitives::version::ProtocolFeature; @@ -50,7 +52,11 @@ fn test_deploy_cost_increased() { }; let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0"); - let actions = vec![Action::DeployContract(DeployContractAction { code: test_contract })]; + let actions = vec![Action::DeployContract(DeployContractAction { + code: test_contract, + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })]; let tx = env.tx_from_actions(actions.clone(), &signer, signer.account_id.clone()); let old_outcome = env.execute_tx(tx).unwrap(); diff --git a/integration-tests/src/tests/client/process_blocks.rs b/integration-tests/src/tests/client/process_blocks.rs index dfaf298bcb5..90dd2fc9a96 100644 --- a/integration-tests/src/tests/client/process_blocks.rs +++ b/integration-tests/src/tests/client/process_blocks.rs @@ -12,6 +12,7 @@ use near_chain::test_utils::ValidatorSchedule; use near_chunks::test_utils::MockClientAdapterForShardsManager; use near_primitives::config::{ActionCosts, ExtCosts}; +use near_primitives::namespace::Namespace; use near_primitives::num_rational::{Ratio, Rational32}; use near_actix_test_utils::run_actix; @@ -50,6 +51,7 @@ use near_primitives::errors::TxExecutionError; use near_primitives::hash::{hash, CryptoHash}; use near_primitives::merkle::{verify_hash, PartialMerkleTree}; use near_primitives::receipt::DelayedReceiptIndices; +use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config::RuntimeConfig; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::shard_layout::{get_block_shard_uid, ShardUId}; @@ -156,7 +158,11 @@ pub(crate) fn deploy_test_contract_with_protocol_version( account_id.clone(), account_id, &signer, - vec![Action::DeployContract(DeployContractAction { code: wasm_code.to_vec() })], + vec![Action::DeployContract(DeployContractAction { + code: wasm_code.to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })], *block.hash(), ); env.clients[0].process_tx(tx, false, false); @@ -210,6 +216,8 @@ pub(crate) fn prepare_env_with_congestion( &signer, vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::base_rs_contract().to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), })], *genesis_block.hash(), ); @@ -2363,6 +2371,8 @@ fn test_validate_chunk_extra() { &signer, vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::rs_contract().to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), })], *genesis_block.hash(), ); diff --git a/integration-tests/src/tests/client/sharding_upgrade.rs b/integration-tests/src/tests/client/sharding_upgrade.rs index a8146b4ad71..c6c93cba58b 100644 --- a/integration-tests/src/tests/client/sharding_upgrade.rs +++ b/integration-tests/src/tests/client/sharding_upgrade.rs @@ -1,4 +1,6 @@ use borsh::BorshSerialize; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use crate::tests::client::process_blocks::{ create_nightshade_runtimes, set_block_protocol_version, @@ -629,6 +631,8 @@ fn setup_test_env_with_cross_contract_txs( &signer, vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::base_rs_contract().to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), })], genesis_hash, ) diff --git a/integration-tests/src/tests/runtime/deployment.rs b/integration-tests/src/tests/runtime/deployment.rs index 07348a9db94..d0f53c0e39f 100644 --- a/integration-tests/src/tests/runtime/deployment.rs +++ b/integration-tests/src/tests/runtime/deployment.rs @@ -1,5 +1,7 @@ use crate::node::{Node, RuntimeNode}; use near_chain_configs::Genesis; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::transaction::{Action, DeployContractAction, SignedTransaction}; use near_primitives::types::AccountId; @@ -30,7 +32,11 @@ fn test_deploy_max_size_contract() { test_contract_id.clone(), test_contract_id.clone(), &*node_user.signer(), - vec![Action::DeployContract(DeployContractAction { code: vec![0u8] })], + vec![Action::DeployContract(DeployContractAction { + code: vec![0u8], + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })], block_hash, ); let tx_overhead = signed_transaction.get_size(); diff --git a/integration-tests/src/tests/runtime/state_viewer.rs b/integration-tests/src/tests/runtime/state_viewer.rs index 0b5e3006ff4..8ee8e83738a 100644 --- a/integration-tests/src/tests/runtime/state_viewer.rs +++ b/integration-tests/src/tests/runtime/state_viewer.rs @@ -5,6 +5,7 @@ use near_primitives::{ account::Account, hash::hash as sha256, hash::CryptoHash, + namespace::Namespace, serialize::to_base64, trie_key::trie_key_parsers, types::{AccountId, StateRoot}, @@ -257,19 +258,35 @@ fn test_view_state() { let shard_uid = TEST_SHARD_UID; let mut state_update = tries.new_trie_update(shard_uid, root); state_update.set( - TrieKey::ContractData { account_id: alice_account(), key: b"test123".to_vec() }, + TrieKey::ContractData { + account_id: alice_account(), + key: b"test123".to_vec(), + namespace: Namespace::default(), + }, b"123".to_vec(), ); state_update.set( - TrieKey::ContractData { account_id: alice_account(), key: b"test321".to_vec() }, + TrieKey::ContractData { + account_id: alice_account(), + key: b"test321".to_vec(), + namespace: Namespace::default(), + }, b"321".to_vec(), ); state_update.set( - TrieKey::ContractData { account_id: "alina".parse().unwrap(), key: b"qqq".to_vec() }, + TrieKey::ContractData { + account_id: "alina".parse().unwrap(), + key: b"qqq".to_vec(), + namespace: Namespace::default(), + }, b"321".to_vec(), ); state_update.set( - TrieKey::ContractData { account_id: "alex".parse().unwrap(), key: b"qqq".to_vec() }, + TrieKey::ContractData { + account_id: "alex".parse().unwrap(), + key: b"qqq".to_vec(), + namespace: Namespace::default(), + }, b"321".to_vec(), ); state_update.commit(StateChangeCause::InitialState); @@ -368,7 +385,10 @@ fn test_view_state_with_large_contract() { alice_account(), &Account::new(0, 0, sha256(&contract_code), 50_001), ); - state_update.set(TrieKey::ContractCode { account_id: alice_account(), namespace: Default::default() }, contract_code); + state_update.set( + TrieKey::ContractCode { account_id: alice_account(), namespace: Default::default() }, + contract_code, + ); let trie_viewer = TrieViewer::new(Some(50_000), None); let result = trie_viewer.view_state(&state_update, &alice_account(), b"", false); assert!(result.is_ok()); diff --git a/integration-tests/src/tests/standard_cases/mod.rs b/integration-tests/src/tests/standard_cases/mod.rs index 77d08b3e21b..d7eb67d07a6 100644 --- a/integration-tests/src/tests/standard_cases/mod.rs +++ b/integration-tests/src/tests/standard_cases/mod.rs @@ -12,6 +12,8 @@ use near_primitives::errors::{ ActionError, ActionErrorKind, InvalidAccessKeyError, InvalidTxError, TxExecutionError, }; use near_primitives::hash::{hash, CryptoHash}; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::types::{AccountId, Balance, TrieNodesCount}; use near_primitives::views::{ AccessKeyView, AccountView, ExecutionMetadataView, FinalExecutionOutcomeView, @@ -1523,7 +1525,12 @@ pub fn test_chunk_nodes_cache_mode(node: impl Node, runtime_config: RuntimeConfi make_receipt(&node, vec![make_write_key_value_action(vec![1], vec![1])], bob_account()), make_receipt( &node, - vec![DeployContractAction { code: test_utils::encode(&[2]) }.into()], + vec![DeployContractAction { + code: test_utils::encode(&[2]), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + } + .into()], alice_account(), ), make_receipt(&node, vec![make_write_key_value_action(vec![2], vec![2])], bob_account()), diff --git a/integration-tests/src/tests/standard_cases/runtime.rs b/integration-tests/src/tests/standard_cases/runtime.rs index ae75364de01..405172fedc7 100644 --- a/integration-tests/src/tests/standard_cases/runtime.rs +++ b/integration-tests/src/tests/standard_cases/runtime.rs @@ -29,6 +29,7 @@ fn create_runtime_with_expensive_storage() -> RuntimeNode { } records.push(StateRecord::Data { account_id: bob_account(), + namespace: Namespace::default(), data_key: b"test".to_vec(), value: b"123".to_vec(), }); diff --git a/integration-tests/src/user/mod.rs b/integration-tests/src/user/mod.rs index d9095de9553..1efd11215ed 100644 --- a/integration-tests/src/user/mod.rs +++ b/integration-tests/src/user/mod.rs @@ -7,7 +7,9 @@ use near_jsonrpc_primitives::errors::ServerError; use near_primitives::account::AccessKey; use near_primitives::delegate_action::{DelegateAction, NonDelegateAction, SignedDelegateAction}; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::Namespace; use near_primitives::receipt::Receipt; +use near_primitives::routing_table::RoutingTable; use near_primitives::test_utils::create_user_test_signer; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, @@ -128,7 +130,11 @@ pub trait User { self.sign_and_commit_actions( signer_id.clone(), signer_id, - vec![Action::DeployContract(DeployContractAction { code })], + vec![Action::DeployContract(DeployContractAction { + code, + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })], ) } diff --git a/runtime/near-vm-logic/src/receipt_manager.rs b/runtime/near-vm-logic/src/receipt_manager.rs index 6dc1723139a..37e8dfc9542 100644 --- a/runtime/near-vm-logic/src/receipt_manager.rs +++ b/runtime/near-vm-logic/src/receipt_manager.rs @@ -2,7 +2,9 @@ use crate::logic; use crate::types::ReceiptIndex; use crate::External; use near_crypto::PublicKey; +use near_primitives::namespace::Namespace; use near_primitives::receipt::DataReceiver; +use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, StakeAction, TransferAction, @@ -154,7 +156,15 @@ impl ReceiptManager { receipt_index: ReceiptIndex, code: Vec, ) -> logic::Result<()> { - self.append_action(receipt_index, Action::DeployContract(DeployContractAction { code })); + // TODO: Namespaces here + self.append_action( + receipt_index, + Action::DeployContract(DeployContractAction { + code, + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + }), + ); Ok(()) } diff --git a/runtime/runtime-params-estimator/src/action_costs.rs b/runtime/runtime-params-estimator/src/action_costs.rs index 4d81a3964bc..a3f68f7c8ab 100644 --- a/runtime/runtime-params-estimator/src/action_costs.rs +++ b/runtime/runtime-params-estimator/src/action_costs.rs @@ -13,7 +13,9 @@ use crate::utils::average_cost; use near_crypto::{KeyType, PublicKey}; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt}; +use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::Action; use near_primitives::types::{AccountId, Gas}; use std::iter; @@ -615,6 +617,8 @@ fn delete_account_action() -> Action { fn deploy_action(size: ActionSize) -> Action { Action::DeployContract(near_primitives::transaction::DeployContractAction { code: near_test_contracts::sized_contract(size.deploy_contract() as usize), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), }) } diff --git a/runtime/runtime-params-estimator/src/lib.rs b/runtime/runtime-params-estimator/src/lib.rs index 92131c51230..5265dad9170 100644 --- a/runtime/runtime-params-estimator/src/lib.rs +++ b/runtime/runtime-params-estimator/src/lib.rs @@ -93,6 +93,8 @@ use gas_metering::gas_metering_cost; use near_crypto::{KeyType, SecretKey}; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::contract::ContractCode; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::fees::RuntimeFeesConfig; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, @@ -646,7 +648,11 @@ fn deploy_contract_cost( let sender = tb.random_unused_account(); let receiver = sender.clone(); - let actions = vec![Action::DeployContract(DeployContractAction { code: code_factory() })]; + let actions = vec![Action::DeployContract(DeployContractAction { + code: code_factory(), + namespace: Namespace::default(), // TODO: non-default options? + routing_table: RoutingTable::default(), + })]; tb.transaction_from_actions(sender, receiver, actions) }; // Use a small block size since deployments are gas heavy. diff --git a/runtime/runtime-params-estimator/src/utils.rs b/runtime/runtime-params-estimator/src/utils.rs index 48dc210a826..db4908803a6 100644 --- a/runtime/runtime-params-estimator/src/utils.rs +++ b/runtime/runtime-params-estimator/src/utils.rs @@ -2,6 +2,8 @@ use crate::apply_block_cost; use crate::estimator_context::EstimatorContext; use crate::gas_cost::{GasCost, NonNegativeTolerance}; use crate::transaction_builder::TransactionBuilder; +use near_primitives::namespace::Namespace; +use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::{ Action, DeployContractAction, FunctionCallAction, SignedTransaction, }; @@ -260,7 +262,11 @@ pub(crate) fn fn_cost_in_contract( for account in &chosen_accounts { let tb = testbed.transaction_builder(); - let setup = vec![Action::DeployContract(DeployContractAction { code: code.to_vec() })]; + let setup = vec![Action::DeployContract(DeployContractAction { + code: code.to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })]; let setup_tx = tb.transaction_from_actions(account.clone(), account.clone(), setup); testbed.process_block(vec![setup_tx], 0); diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index e2b461f27f3..246a294f002 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -13,6 +13,7 @@ use near_primitives::contract::ContractCode; use near_primitives::delegate_action::{DelegateAction, SignedDelegateAction}; use near_primitives::errors::{ActionError, ActionErrorKind, InvalidAccessKeyError, RuntimeError}; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; use near_primitives::runtime::config::AccountCreationConfig; use near_primitives::runtime::fees::RuntimeFeesConfig; @@ -55,7 +56,21 @@ pub(crate) fn execute_function_call( ) -> Result { let account_id = runtime_ext.account_id(); tracing::debug!(target: "runtime", %account_id, "Calling the contract"); - let code = match runtime_ext.get_code(account.code_hashes()) { + let (resolved_namespace, resolved_method_name) = account + .routing_table() + .resolve_method(&function_call.method_name) + .map(|(namespace, method_name)| (namespace.clone(), method_name.as_str())) + .unwrap_or((Namespace::default(), &function_call.method_name)); // fallback: default namespace, same method name + let code_hash = match account.code_hashes().get(&resolved_namespace) { + Some(code_hash) => *code_hash, + None => { + return Ok(VMOutcome::nop_outcome(FunctionCallError::CompilationError( + CompilationError::CodeDoesNotExist { account_id: account_id.clone() }, + ))); + } + }; + + let code = match runtime_ext.get_code(resolved_namespace.clone(), code_hash) { Ok(Some(code)) => code, Ok(None) => { let error = FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { @@ -110,7 +125,8 @@ pub(crate) fn execute_function_call( } let result = near_vm_runner::run( &code, - &function_call.method_name, + // &function_call.method_name, + resolved_method_name, runtime_ext, context, &config.wasm_config, @@ -470,7 +486,12 @@ pub(crate) fn action_deploy_contract( ) -> Result<(), StorageError> { let _span = tracing::debug_span!(target: "runtime", "action_deploy_contract").entered(); let code = ContractCode::new(deploy_contract.code.clone(), None); - let prev_code = get_code(state_update, account_id, Some(account.code_hash()))?; + let prev_code = get_code( + state_update, + account_id, + deploy_contract.namespace.clone(), + Some(account.code_hash()), + )?; let prev_code_length = prev_code.map(|code| code.code().len() as u64).unwrap_or_default(); account.set_storage_usage(account.storage_usage().saturating_sub(prev_code_length)); account.set_storage_usage( @@ -481,8 +502,10 @@ pub(crate) fn action_deploy_contract( )) })?, ); - account.set_code_hash(*code.hash()); - set_code(state_update, account_id.clone(), &code); + account.set_code_hash_for(deploy_contract.namespace.clone(), *code.hash()); + set_code(state_update, account_id.clone(), deploy_contract.namespace.clone(), &code); + // TODO: Accounting for routing table storage costs + account.routing_table_mut().merge(deploy_contract.routing_table.clone()); // Precompile the contract and store result (compiled code or error) in the database. // Note, that contract compilation costs are already accounted in deploy cost using // special logic in estimator (see get_runtime_config() function). @@ -509,13 +532,19 @@ pub(crate) fn action_delete_account( if current_protocol_version >= ProtocolFeature::DeleteActionRestriction.protocol_version() { let account = account.as_ref().unwrap(); let mut account_storage_usage = account.storage_usage(); - let contract_code = get_code(state_update, account_id, Some(account.code_hash()))?; - if let Some(code) = contract_code { - // account storage usage should be larger than code size - let code_len = code.code().len() as u64; - debug_assert!(account_storage_usage > code_len); - account_storage_usage = account_storage_usage.saturating_sub(code_len); + + // delete code from all namespaces + for (namespace, code_hash) in account.code_hashes().iter() { + let contract_code = + get_code(state_update, account_id, namespace.clone(), Some(*code_hash))?; + if let Some(code) = contract_code { + // account storage usage should be larger than code size + let code_len = code.code().len() as u64; + debug_assert!(account_storage_usage > code_len); + account_storage_usage = account_storage_usage.saturating_sub(code_len); + } } + if account_storage_usage > Account::MAX_ACCOUNT_DELETION_STORAGE_USAGE { result.result = Err(ActionErrorKind::DeleteAccountWithLargeState { account_id: account_id.clone(), @@ -1120,7 +1149,8 @@ mod tests { let mut state_update = tries.new_trie_update(ShardUId::single_shard(), CryptoHash::default()); let account_id = "alice".parse::().unwrap(); - let trie_key = TrieKey::ContractCode { account_id: account_id.clone(), namespace: Default::default() }; + let trie_key = + TrieKey::ContractCode { account_id: account_id.clone(), namespace: Default::default() }; let empty_contract = [0; 10_000].to_vec(); let contract_hash = hash(&empty_contract); state_update.set(trie_key, empty_contract); diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs index a95d7a10508..122572954e5 100644 --- a/runtime/runtime/src/config.rs +++ b/runtime/runtime/src/config.rs @@ -87,7 +87,8 @@ pub fn total_send_fees( CreateAccount(_) => { config.fee(ActionCosts::create_account).send_fee(sender_is_receiver) } - DeployContract(DeployContractAction { code }) => { + DeployContract(DeployContractAction { code, .. }) => { + // TODO: Accounting let num_bytes = code.len() as u64; config.fee(ActionCosts::deploy_contract_base).send_fee(sender_is_receiver) + config.fee(ActionCosts::deploy_contract_byte).send_fee(sender_is_receiver) @@ -192,7 +193,8 @@ pub fn exec_fee( match action { CreateAccount(_) => config.fee(ActionCosts::create_account).exec_fee(), - DeployContract(DeployContractAction { code }) => { + DeployContract(DeployContractAction { code, .. }) => { + // TODO: Accounting let num_bytes = code.len() as u64; config.fee(ActionCosts::deploy_contract_base).exec_fee() + config.fee(ActionCosts::deploy_contract_byte).exec_fee() * num_bytes diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index 9a0742cc49b..3689b55898b 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -1,6 +1,7 @@ use near_primitives::contract::ContractCode; use near_primitives::errors::{EpochError, StorageError}; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::Namespace; use near_primitives::trie_key::{trie_key_parsers, TrieKey}; use near_primitives::types::{ AccountId, Balance, EpochId, EpochInfoProvider, TrieCacheMode, TrieNodesCount, @@ -80,8 +81,8 @@ impl<'a> RuntimeExt<'a> { self.account_id } - pub fn get_code(&self, code_hash: CryptoHash) -> Result, StorageError> { - get_code(self.trie_update, self.account_id, Some(code_hash)) + pub fn get_code(&self, namespace: Namespace, code_hash: CryptoHash) -> Result, StorageError> { + get_code(self.trie_update, self.account_id, namespace, Some(code_hash)) } pub fn create_storage_key(&self, key: &[u8]) -> TrieKey { @@ -146,24 +147,24 @@ impl<'a> External for RuntimeExt<'a> { } fn storage_remove_subtree(&mut self, prefix: &[u8]) -> ExtResult<()> { - let data_keys = self + let namespace_data_keys = self .trie_update .iter(&trie_key_parsers::get_raw_prefix_for_contract_data(self.account_id, prefix)) .map_err(wrap_storage_error)? .map(|raw_key| { - trie_key_parsers::parse_data_key_from_contract_data_key(&raw_key?, self.account_id) + trie_key_parsers::parse_parts_from_contract_data_key(&raw_key?, self.account_id) .map_err(|_e| { StorageError::StorageInconsistentState( "Can't parse data key from raw key for ContractData".to_string(), ) }) - .map(Vec::from) + .map(|(namespace, key)| (namespace, key.to_vec())) }) .collect::, _>>() .map_err(wrap_storage_error)?; - for key in data_keys { + for (namespace, key) in namespace_data_keys { self.trie_update - .remove(TrieKey::ContractData { account_id: self.account_id.clone(), key }); + .remove(TrieKey::ContractData { account_id: self.account_id.clone(), namespace, key }); } Ok(()) } diff --git a/runtime/runtime/src/genesis.rs b/runtime/runtime/src/genesis.rs index 6d5ff23df54..d311c366c8a 100644 --- a/runtime/runtime/src/genesis.rs +++ b/runtime/runtime/src/genesis.rs @@ -42,12 +42,14 @@ impl<'a> StorageComputer<'a> { StateRecord::Account { account_id, .. } => { Some((account_id.clone(), self.config.num_bytes_account)) } - StateRecord::Data { account_id, data_key, value } => { + StateRecord::Data { account_id, namespace, data_key, value } => { + // TODO: Accounting let storage_usage = self.config.num_extra_bytes_record + data_key.len() as u64 + value.len() as u64; Some((account_id.clone(), storage_usage)) } - StateRecord::Contract { account_id, code } => { + StateRecord::Contract { account_id, namespace, code } => { + // TODO: Accounting Some((account_id.clone(), code.len() as u64)) } StateRecord::AccessKey { account_id, public_key, access_key } => { @@ -189,26 +191,27 @@ impl GenesisStateApplier { StateRecord::Account { account_id, account } => storage.modify(|state_update| { set_account(state_update, account_id.clone(), account); }), - StateRecord::Data { account_id, data_key, value } => { + StateRecord::Data { account_id, namespace, data_key, value } => { storage.modify(|state_update| { state_update.set( TrieKey::ContractData { key: data_key.clone(), account_id: account_id.clone(), + namespace: namespace.clone(), }, value.clone(), ); }) } - StateRecord::Contract { account_id, code } => { + StateRecord::Contract { account_id, namespace, code } => { storage.modify(|state_update| { // Recompute contract code hash. let code = ContractCode::new(code.clone(), None); if let Some(acc) = get_account(state_update, account_id).expect("Failed to read state") { - set_code(state_update, account_id.clone(), &code); - assert_eq!(*code.hash(), acc.code_hash()); + set_code(state_update, account_id.clone(), namespace.clone(), &code); + assert_eq!(Some(code.hash()), acc.code_hashes().get(namespace)); } else { tracing::error!( target: "runtime", diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index e4bc959a1e3..51c56e6523b 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -1526,15 +1526,15 @@ impl Runtime { StateRecord::Account { account_id, account } => { set_account(state_update, account_id, &account); } - StateRecord::Data { account_id, data_key, value } => { - state_update.set(TrieKey::ContractData { key: data_key, account_id }, value); + StateRecord::Data { account_id, namespace, data_key, value } => { + state_update.set(TrieKey::ContractData { key: data_key, account_id, namespace }, value); } - StateRecord::Contract { account_id, code } => { + StateRecord::Contract { account_id, namespace, code } => { let acc = get_account(state_update, &account_id).expect("Failed to read state").expect("Code state record should be preceded by the corresponding account record"); // Recompute contract code hash. let code = ContractCode::new(code, None); - set_code(state_update, account_id, &code); - assert_eq!(*code.hash(), acc.code_hash()); + set_code(state_update, account_id, namespace.clone(), &code); + assert_eq!(Some(code.hash()), acc.code_hashes().get(&namespace)); } StateRecord::AccessKey { account_id, public_key, access_key } => { set_access_key(state_update, account_id, public_key, &access_key); @@ -1600,6 +1600,8 @@ mod tests { use near_primitives::account::AccessKey; use near_primitives::contract::ContractCode; use near_primitives::hash::hash; + use near_primitives::namespace::Namespace; + use near_primitives::routing_table::RoutingTable; use near_primitives::shard_layout::ShardUId; use near_primitives::test_utils::{account_new, MockEpochInfoProvider}; use near_primitives::transaction::DeployContractAction; @@ -2522,8 +2524,11 @@ mod tests { setup_runtime(initial_balance, initial_locked, gas_limit); let wasm_code = near_test_contracts::rs_contract().to_vec(); - let actions = - vec![Action::DeployContract(DeployContractAction { code: wasm_code.clone() })]; + let actions = vec![Action::DeployContract(DeployContractAction { + code: wasm_code.clone(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })]; let receipts = vec![create_receipt_with_actions(alice_account(), signer, actions)]; diff --git a/runtime/runtime/src/prefetch.rs b/runtime/runtime/src/prefetch.rs index 3e959759eca..1fc04133b04 100644 --- a/runtime/runtime/src/prefetch.rs +++ b/runtime/runtime/src/prefetch.rs @@ -43,6 +43,7 @@ use near_o11y::metrics::prometheus; use near_o11y::metrics::prometheus::core::GenericCounter; +use near_primitives::namespace::Namespace; use near_primitives::receipt::{Receipt, ReceiptEnum}; use near_primitives::transaction::{Action, SignedTransaction}; use near_primitives::trie_key::TrieKey; @@ -201,6 +202,7 @@ impl TriePrefetcher { key.extend(hashed_account); let trie_key = TrieKey::ContractData { account_id: account_id.clone(), + namespace: Namespace::default(), // TODO: necessary? key: key.to_vec(), }; near_o11y::io_trace!(count: "prefetch"); diff --git a/runtime/runtime/src/state_viewer/mod.rs b/runtime/runtime/src/state_viewer/mod.rs index 00cd6a871f7..0e75fad2ea0 100644 --- a/runtime/runtime/src/state_viewer/mod.rs +++ b/runtime/runtime/src/state_viewer/mod.rs @@ -1,6 +1,7 @@ use crate::near_primitives::version::PROTOCOL_VERSION; use crate::{actions::execute_function_call, ext::RuntimeExt}; use near_crypto::{KeyType, PublicKey}; +use near_primitives::namespace::Namespace; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::{ account::{AccessKey, Account}, @@ -65,11 +66,10 @@ impl TrieViewer { account_id: &AccountId, ) -> Result { let account = self.view_account(state_update, account_id)?; - get_code(state_update, account_id, Some(account.code_hash()))?.ok_or_else(|| { - errors::ViewContractCodeError::NoContractCode { + get_code(state_update, account_id, Namespace::default(), Some(account.code_hash()))? + .ok_or_else(|| errors::ViewContractCodeError::NoContractCode { contract_account_id: account_id.clone(), - } - }) + }) } pub fn view_access_key( @@ -122,7 +122,7 @@ impl TrieViewer { ) -> Result { match get_account(state_update, account_id)? { Some(account) => { - let code_len = get_code(state_update, account_id, Some(account.code_hash()))? + let code_len = get_code(state_update, account_id, Namespace::default(), Some(account.code_hash()))? .map(|c| c.code().len() as u64) .unwrap_or_default(); if let Some(limit) = self.state_size_limit { @@ -141,7 +141,11 @@ impl TrieViewer { }; let mut values = vec![]; - let query = trie_key_parsers::get_raw_prefix_for_contract_data(account_id, Default::default(), prefix); + // TODO: Namespace state viewing + let query = trie_key_parsers::get_raw_prefix_for_contract_data( + account_id, + prefix, + ); let acc_sep_len = query.len() - prefix.len(); let mut iter = state_update.trie().iter()?; iter.remember_visited_nodes(include_proof); diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 107a25a0b09..08c5439d438 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -550,6 +550,8 @@ mod tests { use near_primitives::account::{AccessKey, FunctionCallPermission}; use near_primitives::delegate_action::{DelegateAction, NonDelegateAction}; use near_primitives::hash::{hash, CryptoHash}; + use near_primitives::namespace::Namespace; + use near_primitives::routing_table::RoutingTable; use near_primitives::test_utils::account_new; use near_primitives::transaction::{ CreateAccountAction, DeleteAccountAction, DeleteKeyAction, StakeAction, TransferAction, @@ -640,6 +642,7 @@ mod tests { set_code( &mut initial_state, account_id.clone(), + Namespace::default(), &ContractCode::new(code.clone(), Some(code_hash)), ); initial_account.set_code_hash(code_hash); @@ -652,7 +655,11 @@ mod tests { let value = vec![0u8; 100]; set( &mut initial_state, - TrieKey::ContractData { account_id: account_id.clone(), key: key.clone() }, + TrieKey::ContractData { + account_id: account_id.clone(), + namespace: Namespace::default(), + key: key.clone(), + }, &value, ); initial_account.set_storage_usage( @@ -1435,7 +1442,11 @@ mod tests { alice_account(), bob_account(), &*signer, - vec![Action::DeployContract(DeployContractAction { code: vec![1; 5] })], + vec![Action::DeployContract(DeployContractAction { + code: vec![1; 5], + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })], CryptoHash::default(), ); let transaction_size = transaction.get_size(); diff --git a/runtime/runtime/tests/runtime_group_tools/mod.rs b/runtime/runtime/tests/runtime_group_tools/mod.rs index c05874b7a76..7a531fd659a 100644 --- a/runtime/runtime/tests/runtime_group_tools/mod.rs +++ b/runtime/runtime/tests/runtime_group_tools/mod.rs @@ -2,6 +2,7 @@ use near_chain_configs::{get_initial_supply, Genesis, GenesisConfig, GenesisReco use near_crypto::{InMemorySigner, KeyType}; use near_primitives::account::{AccessKey, Account}; use near_primitives::hash::{hash, CryptoHash}; +use near_primitives::namespace::Namespace; use near_primitives::receipt::Receipt; use near_primitives::runtime::migration_data::{MigrationData, MigrationFlags}; use near_primitives::shard_layout::ShardUId; @@ -225,8 +226,12 @@ impl RuntimeGroup { public_key: signer.public_key.clone(), access_key: AccessKey::full_access(), }); - state_records - .push(StateRecord::Contract { account_id, code: contract_code.to_vec() }); + // TODO: I don't know what this is doing, and therefore, I don't know how to correctly implement it + state_records.push(StateRecord::Contract { + account_id, + code: contract_code.to_vec(), + namespace: Namespace::default(), + }); validators.push(AccountInfo { account_id: signer.account_id.clone(), public_key: signer.public_key.clone(), diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs index d86ec0e6f3e..9d6a25b9a02 100644 --- a/runtime/runtime/tests/test_async_calls.rs +++ b/runtime/runtime/tests/test_async_calls.rs @@ -3,7 +3,9 @@ use borsh::ser::BorshSerialize; use near_crypto::{InMemorySigner, KeyType}; use near_primitives::account::{AccessKeyPermission, FunctionCallPermission}; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, ReceiptEnum}; +use near_primitives::routing_table::RoutingTable; use near_primitives::serialize::to_base64; use near_primitives::types::AccountId; @@ -782,7 +784,7 @@ fn test_account_factory() { method_names: vec!["call_promise".to_string(), "hello".to_string()], })); }, - a3, Action::DeployContract(DeployContractAction{code}), { + a3, Action::DeployContract(DeployContractAction{code,namespace,routing_table}), { assert_eq!(code, near_test_contracts::rs_contract()); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { @@ -918,7 +920,7 @@ fn test_create_account_add_key_call_delete_key_delete_account() { assert_eq!(access_key.nonce, 1); assert_eq!(access_key.permission, AccessKeyPermission::FullAccess); }, - a3, Action::DeployContract(DeployContractAction{code}), { + a3, Action::DeployContract(DeployContractAction{code, namespace, routing_table}), { assert_eq!(code, near_test_contracts::rs_contract()); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { diff --git a/test-utils/runtime-tester/src/fuzzing.rs b/test-utils/runtime-tester/src/fuzzing.rs index 02b4a723fcb..a30dbc31a6a 100644 --- a/test-utils/runtime-tester/src/fuzzing.rs +++ b/test-utils/runtime-tester/src/fuzzing.rs @@ -2,6 +2,8 @@ use crate::run_test::{BlockConfig, NetworkConfig, RuntimeConfig, Scenario, Trans use near_crypto::{InMemorySigner, KeyType, PublicKey}; use near_primitives::{ account::{AccessKey, AccessKeyPermission, FunctionCallPermission}, + namespace::Namespace, + routing_table::RoutingTable, transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, TransferAction, @@ -216,6 +218,8 @@ impl TransactionConfig { signer, actions: vec![Action::DeployContract(DeployContractAction { code: scope.available_contracts[contract_id].code.clone(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), })], }) }); diff --git a/test-utils/testlib/src/runtime_utils.rs b/test-utils/testlib/src/runtime_utils.rs index eafbf8396be..c8c12c8a58f 100644 --- a/test-utils/testlib/src/runtime_utils.rs +++ b/test-utils/testlib/src/runtime_utils.rs @@ -2,6 +2,7 @@ use near_chain_configs::Genesis; use near_crypto::PublicKey; use near_primitives::account::{AccessKey, Account}; use near_primitives::hash::hash; +use near_primitives::namespace::Namespace; use near_primitives::state_record::StateRecord; use near_primitives::types::{AccountId, Balance}; @@ -49,7 +50,11 @@ pub fn add_contract(genesis: &mut Genesis, account_id: &AccountId, code: Vec account: Account::new(0, 0, hash, 0), }); } - records.push(StateRecord::Contract { account_id: account_id.clone(), code }); + records.push(StateRecord::Contract { + account_id: account_id.clone(), + namespace: Namespace::default(), // TODO: predeploy to namespaces? + code, + }); } /// Add an account with a specified access key & balance to the genesis state records. diff --git a/tools/amend-genesis/src/lib.rs b/tools/amend-genesis/src/lib.rs index 39d9e74108b..5fa7c5da23e 100644 --- a/tools/amend-genesis/src/lib.rs +++ b/tools/amend-genesis/src/lib.rs @@ -385,6 +385,7 @@ mod test { use anyhow::Context; use near_chain_configs::{get_initial_supply, Genesis, GenesisConfig}; use near_primitives::hash::CryptoHash; + use near_primitives::namespace::Namespace; use near_primitives::shard_layout::ShardLayout; use near_primitives::state_record::StateRecord; use near_primitives::static_clock::StaticClock; @@ -449,6 +450,7 @@ mod test { Self::Contract { account_id } => StateRecord::Contract { account_id: account_id.parse().unwrap(), code: vec![123], + namespace: Namespace::default(), }, } } diff --git a/tools/state-viewer/src/cli.rs b/tools/state-viewer/src/cli.rs index a3218119f07..469b380f6ec 100644 --- a/tools/state-viewer/src/cli.rs +++ b/tools/state-viewer/src/cli.rs @@ -294,6 +294,7 @@ impl DumpAccountStorageCmd { pub fn run(self, home_dir: &Path, near_config: NearConfig, store: Store) { dump_account_storage( self.account_id, + Default::default(), // TODO: correct for CLI self.storage_key, &self.output, self.block_height, diff --git a/tools/state-viewer/src/commands.rs b/tools/state-viewer/src/commands.rs index 2fa3cd8090f..35db4c9dd6e 100644 --- a/tools/state-viewer/src/commands.rs +++ b/tools/state-viewer/src/commands.rs @@ -217,6 +217,7 @@ pub(crate) fn apply_tx( pub(crate) fn dump_account_storage( account_id: String, + namespace: String, storage_key: String, output: &Path, block_height: String, @@ -239,6 +240,7 @@ pub(crate) fn dump_account_storage( .unwrap(); let key = TrieKey::ContractData { account_id: account_id.parse().unwrap(), + namespace: namespace.clone().into(), key: storage_key.as_bytes().to_vec(), }; let item = trie.get(&key.to_vec()); @@ -246,10 +248,10 @@ pub(crate) fn dump_account_storage( if let Some(value) = value { let record = StateRecord::from_raw_key_value(key.to_vec(), value).unwrap(); match record { - StateRecord::Data { account_id: _, data_key: _, value } => { + StateRecord::Data { account_id: _, namespace: _, data_key: _, value } => { fs::write(output, &value).unwrap(); println!( - "Dump contract storage under key {} of account {} into file {}", + "Dump contract storage under key {} of account {} namespace {namespace} into file {}", storage_key, account_id, output.display() diff --git a/tools/state-viewer/src/contract_accounts.rs b/tools/state-viewer/src/contract_accounts.rs index 1f28c4df9a8..2c4d385d0e2 100644 --- a/tools/state-viewer/src/contract_accounts.rs +++ b/tools/state-viewer/src/contract_accounts.rs @@ -193,7 +193,9 @@ impl ContractAccountIterator { let mut trie_iter = trie.iter()?; // TODO(#8376): Consider changing the interface to TrieKey to make this easier. // `TrieKey::ContractCode` requires a valid `AccountId`, we use "xx" - let key = TrieKey::ContractCode { account_id: "xx".parse()?, namespace: Default::default() }.to_vec(); + let key = + TrieKey::ContractCode { account_id: "xx".parse()?, namespace: Default::default() } + .to_vec(); let (prefix, suffix) = key.split_at(key.len() - 2); assert_eq!(suffix, "xx".as_bytes()); @@ -485,7 +487,9 @@ mod tests { use borsh::BorshSerialize; use near_crypto::{InMemorySigner, Signer}; use near_primitives::hash::CryptoHash; + use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; + use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::{ Action, CreateAccountAction, DeployContractAction, ExecutionMetadata, ExecutionOutcome, ExecutionOutcomeWithProof, ExecutionStatus, FunctionCallAction, TransferAction, @@ -582,7 +586,11 @@ mod tests { vec![ Action::Transfer(TransferAction { deposit: 20 }), Action::CreateAccount(CreateAccountAction {}), - Action::DeployContract(DeployContractAction { code: vec![] }), + Action::DeployContract(DeployContractAction { + code: vec![], + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + }), ], ); @@ -645,7 +653,11 @@ mod tests { /// Create a test contract key-value pair to insert in the test trie, with specified amount of bytes. fn contract_tuple(account: &str, num_bytes: u8) -> (Vec, Option>) { ( - TrieKey::ContractCode { account_id: account.parse().unwrap(), namespace: Default::default() }.to_vec(), + TrieKey::ContractCode { + account_id: account.parse().unwrap(), + namespace: Default::default(), + } + .to_vec(), Some(vec![num_bytes; num_bytes as usize]), ) } diff --git a/tools/state-viewer/src/state_dump.rs b/tools/state-viewer/src/state_dump.rs index 6aff5656d45..febb6b6e92a 100644 --- a/tools/state-viewer/src/state_dump.rs +++ b/tools/state-viewer/src/state_dump.rs @@ -164,8 +164,9 @@ pub fn state_dump_redis( println!("Account written: {}", account_id); } - if let StateRecord::Data { account_id, data_key, value } = &sr { - println!("Data: {}", account_id); + if let StateRecord::Data { account_id, namespace, data_key, value } = &sr { + // TODO: namespace dump + println!("Data: {}:{namespace}", account_id); let redis_key = [account_id.as_ref().as_bytes(), b":", data_key.as_ref()].concat(); redis_connection.zadd( @@ -181,7 +182,8 @@ pub fn state_dump_redis( println!("Data written: {}", account_id); } - if let StateRecord::Contract { account_id, code } = &sr { + if let StateRecord::Contract { account_id, namespace, code } = &sr { + // TODO: dump namespace println!("Contract: {}", account_id); let redis_key = [b"code:", account_id.as_ref().as_bytes()].concat(); redis_connection.zadd(redis_key.clone(), block_hash.as_ref(), block_height)?; @@ -300,6 +302,8 @@ mod test { use near_client::test_utils::TestEnv; use near_crypto::{InMemorySigner, KeyFile, KeyType, PublicKey, SecretKey}; use near_primitives::account::id::AccountId; + use near_primitives::namespace::Namespace; + use near_primitives::routing_table::RoutingTable; use near_primitives::state_record::StateRecord; use near_primitives::transaction::{Action, DeployContractAction, SignedTransaction}; use near_primitives::types::{ @@ -442,6 +446,8 @@ mod test { &signer0, vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::base_rs_contract().to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), })], genesis_hash, ); From 10e6144c6863a920dbff47d382a22595bdfcb77f Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Thu, 18 May 2023 02:19:43 +0900 Subject: [PATCH 5/9] everything knows about namespaces now and compiles --- chain/chain/src/store.rs | 3 +- chain/client/src/test_utils.rs | 2 + .../jsonrpc/jsonrpc-tests/tests/rpc_query.rs | 2 + chain/jsonrpc/src/api/query.rs | 2 + chain/rosetta-rpc/src/adapters/mod.rs | 4 + .../validated_operations/function_call.rs | 13 +- core/primitives/src/test_utils.rs | 11 +- core/primitives/src/transaction.rs | 3 + core/primitives/src/trie_key.rs | 1 - core/primitives/src/types.rs | 6 +- core/primitives/src/views.rs | 13 +- core/store/src/flat/delta.rs | 15 ++- core/store/src/trie/update.rs | 6 +- .../genesis-csv-to-json/src/csv_parser.rs | 7 +- genesis-tools/genesis-populate/src/lib.rs | 3 +- integration-tests/src/node/mod.rs | 7 +- .../src/tests/client/benchmarks.rs | 12 +- .../src/tests/client/cold_storage.rs | 1 + .../client/features/chunk_nodes_cache.rs | 7 +- .../tests/client/features/delegate_action.rs | 17 ++- .../features/lower_storage_key_limit.rs | 3 + .../src/tests/client/features/wasmer2.rs | 2 + .../src/tests/client/process_blocks.rs | 4 + .../src/tests/client/sharding_upgrade.rs | 1 + .../src/tests/runtime/deployment.rs | 5 +- .../src/tests/runtime/sanity_checks.rs | 27 +++- .../src/tests/runtime/state_viewer.rs | 4 + .../src/tests/runtime/test_evil_contracts.rs | 14 +- .../src/tests/standard_cases/mod.rs | 123 +++++++++++++++--- integration-tests/src/user/mod.rs | 6 +- integration-tests/src/user/rpc_user.rs | 3 + integration-tests/src/user/runtime_user.rs | 3 + nearcore/src/runtime/mod.rs | 6 +- runtime/near-vm-errors/src/lib.rs | 3 + runtime/near-vm-logic/src/logic.rs | 17 +++ runtime/near-vm-logic/src/receipt_manager.rs | 4 + .../near-vm-logic/src/tests/gas_counter.rs | 6 + runtime/near-vm-logic/src/tests/helpers.rs | 9 ++ .../near-vm-logic/src/tests/view_method.rs | 6 +- runtime/near-vm-runner/src/imports.rs | 8 ++ .../src/action_costs.rs | 1 + runtime/runtime-params-estimator/src/lib.rs | 2 +- .../src/transaction_builder.rs | 17 ++- runtime/runtime-params-estimator/src/utils.rs | 20 ++- runtime/runtime/src/actions.rs | 7 + runtime/runtime/src/adapter.rs | 2 + runtime/runtime/src/ext.rs | 13 +- runtime/runtime/src/lib.rs | 2 + runtime/runtime/src/state_viewer/mod.rs | 18 ++- runtime/runtime/src/verifier.rs | 13 ++ runtime/runtime/tests/test_async_calls.rs | 13 ++ test-utils/runtime-tester/src/fuzzing.rs | 3 +- tools/state-viewer/src/contract_accounts.rs | 1 + 53 files changed, 430 insertions(+), 71 deletions(-) diff --git a/chain/chain/src/store.rs b/chain/chain/src/store.rs index c55612277dc..abb5007ecc6 100644 --- a/chain/chain/src/store.rs +++ b/chain/chain/src/store.rs @@ -796,7 +796,8 @@ impl ChainStore { StateChangesRequest::ContractCodeChanges { account_ids } => { let mut changes = StateChanges::new(); for account_id in account_ids { - let data_key = trie_key_parsers::get_raw_prefix_for_contract_code(account_id, &[]); + let data_key = + trie_key_parsers::get_raw_prefix_for_contract_code(account_id, &[]); let storage_key = KeyForStateChanges::from_raw_key(block_hash, &data_key); let changes_per_key = storage_key.find_iter(&self.store); changes.extend(StateChanges::from_contract_code_changes(changes_per_key)?); diff --git a/chain/client/src/test_utils.rs b/chain/client/src/test_utils.rs index 365fb1b0bea..78463c90a6c 100644 --- a/chain/client/src/test_utils.rs +++ b/chain/client/src/test_utils.rs @@ -14,6 +14,7 @@ use near_chunks::shards_manager_actor::start_shards_manager; use near_chunks::ShardsManager; use near_network::shards_manager::ShardsManagerRequestFromNetwork; use near_primitives::errors::InvalidTxError; +use near_primitives::namespace::Namespace; use near_primitives::test_utils::create_test_signer; use near_primitives::time; use num_rational::Ratio; @@ -1895,6 +1896,7 @@ impl TestEnv { pub fn call_main(&mut self, account: &AccountId) -> FinalExecutionOutcomeView { let signer = InMemorySigner::from_seed(account.clone(), KeyType::ED25519, account.as_str()); let actions = vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "main".to_string(), args: vec![], gas: 3 * 10u64.pow(14), diff --git a/chain/jsonrpc/jsonrpc-tests/tests/rpc_query.rs b/chain/jsonrpc/jsonrpc-tests/tests/rpc_query.rs index 28568d03f29..6c745edc950 100644 --- a/chain/jsonrpc/jsonrpc-tests/tests/rpc_query.rs +++ b/chain/jsonrpc/jsonrpc-tests/tests/rpc_query.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use actix::System; use futures::{future, FutureExt}; +use near_primitives::namespace::Namespace; use serde_json::json; use near_actix_test_utils::run_actix; @@ -322,6 +323,7 @@ fn test_query_call_function() { block_reference: BlockReference::latest(), request: QueryRequest::CallFunction { account_id: "test".parse().unwrap(), + namespace: Namespace::default(), method_name: "method".to_string(), args: vec![].into(), }, diff --git a/chain/jsonrpc/src/api/query.rs b/chain/jsonrpc/src/api/query.rs index 5bf4884b119..4efbcefb34d 100644 --- a/chain/jsonrpc/src/api/query.rs +++ b/chain/jsonrpc/src/api/query.rs @@ -1,3 +1,4 @@ +use near_primitives::namespace::Namespace; use serde_json::Value; use near_client_primitives::types::QueryError; @@ -75,6 +76,7 @@ fn parse_path_data(path: String, data: String) -> Result match maybe_extra_arg { Some(method_name) => QueryRequest::CallFunction { account_id, + namespace: Namespace::default(), // TODO: update to support choosing namespace method_name: method_name.to_string(), args: parse_data()?.into(), }, diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 9c5aa630bd9..bbcc955beaa 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -410,6 +410,7 @@ impl From for Vec { related_operations.push(initiate_function_call_operation_id); let deploy_contract_operation = validated_operations::FunctionCallOperation { account: receiver_account_identifier.clone(), + namespace: action.namespace, method_name: action.method_name, args: action.args, attached_gas: action.gas, @@ -703,6 +704,7 @@ impl TryFrom> for NearActions { } actions.push( near_primitives::transaction::FunctionCallAction { + namespace: function_call_operation.namespace, method_name: function_call_operation.method_name, args: function_call_operation.args, gas: function_call_operation.attached_gas, @@ -1006,6 +1008,7 @@ mod tests { .into()]; let function_call_without_balance_actions = vec![near_primitives::transaction::FunctionCallAction { + namespace: Namespace::default(), method_name: "method-name".parse().unwrap(), args: b"args".to_vec(), gas: 100500, @@ -1014,6 +1017,7 @@ mod tests { .into()]; let function_call_with_balance_actions = vec![near_primitives::transaction::FunctionCallAction { + namespace: Namespace::default(), method_name: "method-name".parse().unwrap(), args: b"args".to_vec(), gas: 100500, diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/function_call.rs b/chain/rosetta-rpc/src/adapters/validated_operations/function_call.rs index e0b96580fc5..c9d5dc16d73 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/function_call.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/function_call.rs @@ -1,7 +1,10 @@ +use near_primitives::namespace::Namespace; + use super::ValidatedOperation; pub(crate) struct FunctionCallOperation { pub(crate) account: crate::models::AccountIdentifier, + pub(crate) namespace: Namespace, pub(crate) method_name: String, pub(crate) args: Vec, pub(crate) attached_gas: near_primitives::types::Gas, @@ -51,6 +54,7 @@ impl TryFrom for FunctionCallOperation { Self::validate_operation_type(operation.type_)?; let metadata = operation.metadata.ok_or_else(required_fields_error)?; let method_name = metadata.method_name.ok_or_else(required_fields_error)?; + let namespace = metadata.namespace.ok_or_else(required_fields_error)?.into(); let args = metadata.args.ok_or_else(required_fields_error)?.into_inner(); let attached_gas = metadata.attached_gas.ok_or_else(required_fields_error)?; let attached_gas = if attached_gas.is_positive() { @@ -71,6 +75,13 @@ impl TryFrom for FunctionCallOperation { 0 }; - Ok(Self { account: operation.account, method_name, args, attached_gas, attached_amount }) + Ok(Self { + namespace, + account: operation.account, + method_name, + args, + attached_gas, + attached_amount, + }) } } diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index 2156357b173..0f672720da6 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -60,12 +60,14 @@ impl Transaction { pub fn function_call( mut self, + namespace: Namespace, method_name: String, args: Vec, gas: Gas, deposit: Balance, ) -> Self { self.actions.push(Action::FunctionCall(FunctionCallAction { + namespace, method_name, args, gas, @@ -219,6 +221,7 @@ impl SignedTransaction { receiver_id: AccountId, signer: &dyn Signer, deposit: Balance, + namespace: Namespace, method_name: String, args: Vec, gas: Gas, @@ -229,7 +232,13 @@ impl SignedTransaction { signer_id, receiver_id, signer, - vec![Action::FunctionCall(FunctionCallAction { args, method_name, gas, deposit })], + vec![Action::FunctionCall(FunctionCallAction { + namespace, + args, + method_name, + gas, + deposit, + })], block_hash, ) } diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index 6ba79d58c36..54b6db2ab08 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -148,6 +148,7 @@ impl fmt::Debug for DeployContractAction { BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone, )] pub struct FunctionCallAction { + pub namespace: Namespace, pub method_name: String, #[serde(with = "base64_format")] pub args: Vec, @@ -165,6 +166,7 @@ impl From for Action { impl fmt::Debug for FunctionCallAction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FunctionCallAction") + .field("namespace", &format_args!("{}", &self.namespace)) .field("method_name", &format_args!("{}", &self.method_name)) .field("args", &format_args!("{}", pretty::AbbrBytes(&self.args))) .field("gas", &format_args!("{}", &self.gas)) @@ -577,6 +579,7 @@ mod tests { routing_table: RoutingTable::default(), }), Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "qqq".to_string(), args: vec![1, 2, 3], gas: 1_000, diff --git a/core/primitives/src/trie_key.rs b/core/primitives/src/trie_key.rs index f3afa6d2bc2..1b26d465428 100644 --- a/core/primitives/src/trie_key.rs +++ b/core/primitives/src/trie_key.rs @@ -39,7 +39,6 @@ pub(crate) mod col { pub const DELAYED_RECEIPT: u8 = 8; /// This column id is used when storing Key-Value data from a contract on an `account_id`. pub const CONTRACT_DATA: u8 = 9; - pub const ROUTING_TABLE: u8 = 10; /// All columns pub const NON_DELAYED_RECEIPT_COLUMNS: [(u8, &str); 8] = [ (ACCOUNT, "Account"), diff --git a/core/primitives/src/types.rs b/core/primitives/src/types.rs index add6541a311..f5d06072b91 100644 --- a/core/primitives/src/types.rs +++ b/core/primitives/src/types.rs @@ -299,7 +299,8 @@ impl StateChanges { }, )) } - TrieKey::ContractCode { account_id, namespace: _ } => { // TODO: Should this state change kind include namespace? + TrieKey::ContractCode { account_id, namespace: _ } => { + // TODO: Should this state change kind include namespace? state_changes.extend(changes.into_iter().map( |RawStateChange { cause, data }| StateChangeWithCause { cause, @@ -315,7 +316,8 @@ impl StateChanges { }, )); } - TrieKey::ContractData { account_id, namespace, key } => { // TODO: Namespace here? + TrieKey::ContractData { account_id, namespace, key } => { + // TODO: Namespace here? state_changes.extend(changes.into_iter().map( |RawStateChange { cause, data }| StateChangeWithCause { cause, diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index 3f8efe64923..06c6e00686a 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -322,6 +322,7 @@ pub enum QueryRequest { }, CallFunction { account_id: AccountId, + namespace: Namespace, method_name: String, #[serde(rename = "args_base64", with = "base64_format")] args: FunctionArgs, @@ -1116,6 +1117,7 @@ pub enum ActionView { routing_table: RoutingTable, }, FunctionCall { + namespace: Namespace, method_name: String, #[serde(with = "base64_format")] args: Vec, @@ -1161,6 +1163,7 @@ impl From for ActionView { } } Action::FunctionCall(action) => ActionView::FunctionCall { + namespace: action.namespace, method_name: action.method_name, args: action.args, gas: action.gas, @@ -1195,8 +1198,14 @@ impl TryFrom for Action { ActionView::DeployContract { code, namespace, routing_table } => { Action::DeployContract(DeployContractAction { code, namespace, routing_table }) } - ActionView::FunctionCall { method_name, args, gas, deposit } => { - Action::FunctionCall(FunctionCallAction { method_name, args, gas, deposit }) + ActionView::FunctionCall { namespace, method_name, args, gas, deposit } => { + Action::FunctionCall(FunctionCallAction { + namespace, + method_name, + args, + gas, + deposit, + }) } ActionView::Transfer { deposit } => Action::Transfer(TransferAction { deposit }), ActionView::Stake { stake, public_key } => { diff --git a/core/store/src/flat/delta.rs b/core/store/src/flat/delta.rs index d759a7c2d9a..4367fcc52be 100644 --- a/core/store/src/flat/delta.rs +++ b/core/store/src/flat/delta.rs @@ -143,9 +143,18 @@ mod tests { /// Check correctness of creating `FlatStateChanges` from state changes. #[test] fn flat_state_changes_creation() { - let alice_trie_key = TrieKey::ContractCode { account_id: "alice".parse().unwrap(), namespace: Default::default() }; - let bob_trie_key = TrieKey::ContractCode { account_id: "bob".parse().unwrap(), namespace: Default::default() }; - let carol_trie_key = TrieKey::ContractCode { account_id: "carol".parse().unwrap(), namespace: Default::default() }; + let alice_trie_key = TrieKey::ContractCode { + account_id: "alice".parse().unwrap(), + namespace: Default::default(), + }; + let bob_trie_key = TrieKey::ContractCode { + account_id: "bob".parse().unwrap(), + namespace: Default::default(), + }; + let carol_trie_key = TrieKey::ContractCode { + account_id: "carol".parse().unwrap(), + namespace: Default::default(), + }; let delayed_trie_key = TrieKey::DelayedReceiptIndices; let delayed_receipt_trie_key = TrieKey::DelayedReceipt { index: 1 }; diff --git a/core/store/src/trie/update.rs b/core/store/src/trie/update.rs index 00d567a4892..1eae1ba7e7b 100644 --- a/core/store/src/trie/update.rs +++ b/core/store/src/trie/update.rs @@ -179,7 +179,11 @@ mod tests { const COMPLEX_SHARD_UID: ShardUId = ShardUId { version: SHARD_VERSION, shard_id: 0 }; fn test_key(key: Vec) -> TrieKey { - TrieKey::ContractData { account_id: "alice".parse().unwrap(), namespace: Default::default(), key } + TrieKey::ContractData { + account_id: "alice".parse().unwrap(), + namespace: Default::default(), + key, + } } #[test] diff --git a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs index 5d80f500183..ffad55a6d17 100644 --- a/genesis-tools/genesis-csv-to-json/src/csv_parser.rs +++ b/genesis-tools/genesis-csv-to-json/src/csv_parser.rs @@ -224,7 +224,11 @@ fn account_records(row: &Row, gas_price: Balance) -> Vec { // Add smart contract code if was specified. if let Some(code) = smart_contract_code { - res.push(StateRecord::Contract { account_id: row.account_id.clone(), code, namespace: Namespace::default() }); + res.push(StateRecord::Contract { + account_id: row.account_id.clone(), + code, + namespace: Namespace::default(), + }); } // Add init function call if smart contract was provided. @@ -260,6 +264,7 @@ fn account_records(row: &Row, gas_price: Balance) -> Vec { output_data_receivers: vec![], input_data_ids: vec![], actions: vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), // TODO: Not really sure what to do here. method_name: "init".to_string(), args, gas: INIT_GAS, diff --git a/genesis-tools/genesis-populate/src/lib.rs b/genesis-tools/genesis-populate/src/lib.rs index 998e63ae67b..b7c3994fb09 100644 --- a/genesis-tools/genesis-populate/src/lib.rs +++ b/genesis-tools/genesis-populate/src/lib.rs @@ -291,7 +291,8 @@ impl GenesisBuilder { let code = ContractCode::new(wasm_binary.clone(), None); let namespace = Namespace::default(); set_code(&mut state_update, account_id.clone(), namespace.clone(), &code); - let contract_record = StateRecord::Contract { account_id, code: wasm_binary.clone(), namespace }; + let contract_record = + StateRecord::Contract { account_id, code: wasm_binary.clone(), namespace }; records.push(contract_record); } diff --git a/integration-tests/src/node/mod.rs b/integration-tests/src/node/mod.rs index ee94f6e7530..58d02ce37a2 100644 --- a/integration-tests/src/node/mod.rs +++ b/integration-tests/src/node/mod.rs @@ -168,8 +168,11 @@ pub fn create_nodes_from_seeds(seeds: Vec) -> Vec { } } assert!(is_account_record_found); - records - .push(StateRecord::Contract { account_id: seed.parse().unwrap(), code: code.to_vec(), namespace: Namespace::default() }); + records.push(StateRecord::Contract { + account_id: seed.parse().unwrap(), + code: code.to_vec(), + namespace: Namespace::default(), + }); } near_configs_to_node_configs(configs, validator_signers, network_signers, genesis) } diff --git a/integration-tests/src/tests/client/benchmarks.rs b/integration-tests/src/tests/client/benchmarks.rs index 5d54a06518d..5f6e33e68d7 100644 --- a/integration-tests/src/tests/client/benchmarks.rs +++ b/integration-tests/src/tests/client/benchmarks.rs @@ -10,7 +10,11 @@ use near_chain::ChainGenesis; use near_chain_configs::Genesis; use near_client::test_utils::{create_chunk_on_height, TestEnv}; use near_crypto::{InMemorySigner, KeyType}; -use near_primitives::{transaction::{Action, DeployContractAction, SignedTransaction}, namespace::Namespace, routing_table::RoutingTable}; +use near_primitives::{ + namespace::Namespace, + routing_table::RoutingTable, + transaction::{Action, DeployContractAction, SignedTransaction}, +}; use nearcore::config::GenesisExt; /// How long does it take to produce a large chunk? @@ -44,7 +48,11 @@ fn benchmark_large_chunk_production_time() { account_id.clone(), account_id.clone(), &signer, - vec![Action::DeployContract(DeployContractAction { code: vec![92; tx_size], namespace: Namespace::default(), routing_table: RoutingTable::default() })], + vec![Action::DeployContract(DeployContractAction { + code: vec![92; tx_size], + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + })], last_block_hash, ); env.clients[0].process_tx(tx, false, false); diff --git a/integration-tests/src/tests/client/cold_storage.rs b/integration-tests/src/tests/client/cold_storage.rs index 1058662ba95..30a4e206f1d 100644 --- a/integration-tests/src/tests/client/cold_storage.rs +++ b/integration-tests/src/tests/client/cold_storage.rs @@ -118,6 +118,7 @@ fn test_storage_after_commit_of_cold_update() { "test0".parse().unwrap(), &signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "write_random_value".to_string(), args: vec![], gas: 100_000_000_000_000, diff --git a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs index f3032974f7d..6ca128fb703 100644 --- a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs +++ b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs @@ -15,6 +15,7 @@ use near_primitives::transaction::{ use near_primitives::types::{BlockHeightDelta, Gas, TrieNodesCount}; use near_primitives::version::{ProtocolFeature, ProtocolVersion}; use near_primitives::views::FinalExecutionStatus; +use near_primitives_core::namespace::Namespace; use near_store::test_utils::create_test_store; use nearcore::config::GenesisExt; use std::path::Path; @@ -41,14 +42,16 @@ fn process_transaction( signer, vec![ Action::FunctionCall(FunctionCallAction { - args: encode(&[0u64, 10u64]), + namespace: Namespace::default(), method_name: "write_key_value".to_string(), + args: encode(&[0u64, 10u64]), gas, deposit: 0, }), Action::FunctionCall(FunctionCallAction { - args: encode(&[1u64, 20u64]), + namespace: Namespace::default(), method_name: "write_key_value".to_string(), + args: encode(&[1u64, 20u64]), gas, deposit: 0, }), diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index 582d41f4e1d..137a81d4f21 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -579,6 +579,7 @@ fn meta_tx_ft_transfer() { .function_call( relayer.clone(), ft_contract.clone(), + Namespace::default(), "new_default_meta", // make the relayer (alice) owner, makes initialization easier br#"{"owner_id": "alice.near", "total_supply": "1000000"}"#.to_vec(), @@ -642,6 +643,7 @@ fn meta_tx_ft_transfer() { /// Call the function "log_something" in the test contract. fn log_something_fn_call() -> Action { Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: TEST_METHOD.to_owned(), args: vec![], gas: 30_000_000_000_000, @@ -664,6 +666,7 @@ fn ft_transfer_action(receiver: &str, amount: u128) -> (Action, u64) { let method_name = "ft_transfer".to_owned(); let num_bytes = method_name.len() + args.len(); let action = Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name, args, gas: 20_000_000_000_000, @@ -684,6 +687,7 @@ fn ft_register_action(receiver: &str) -> Action { .bytes() .collect(); Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "storage_deposit".to_owned(), args, gas: 20_000_000_000_000, @@ -718,7 +722,12 @@ fn assert_ft_balance( ) { let response = node .user() - .view_call(ft_contract, "ft_balance_of", format!(r#"{{"account_id":"{user}"}}"#).as_bytes()) + .view_call( + ft_contract, + &Namespace::default(), + "ft_balance_of", + format!(r#"{{"account_id":"{user}"}}"#).as_bytes(), + ) .expect("view call failed"); let balance = std::str::from_utf8(&response.result).expect("invalid UTF8"); assert_eq!(format!("\"{expected_balance}\""), balance); @@ -832,7 +841,11 @@ fn meta_tx_create_and_use_implicit_account() { let initial_amount = nearcore::NEAR_BASE; let actions = vec![ Action::Transfer(TransferAction { deposit: initial_amount }), - Action::DeployContract(DeployContractAction { code: ft_contract().to_vec(), namespace: Namespace::default(), routing_table: RoutingTable::default() }), + Action::DeployContract(DeployContractAction { + code: ft_contract().to_vec(), + namespace: Namespace::default(), + routing_table: RoutingTable::default(), + }), ]; // Execute and expect `AccountDoesNotExist`, as we try to call a meta diff --git a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs index 18d809261f8..0bd3d7f2d31 100644 --- a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs +++ b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs @@ -11,6 +11,7 @@ use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::transaction::{Action, FunctionCallAction, Transaction}; use near_primitives::types::BlockHeight; use near_primitives::views::FinalExecutionStatus; +use near_primitives_core::namespace::Namespace; use near_store::test_utils::create_test_store; use nearcore::config::GenesisExt; use std::path::Path; @@ -73,6 +74,7 @@ fn protocol_upgrade() { receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), actions: vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "write_key_value".to_string(), args, gas: 10u64.pow(14), @@ -133,6 +135,7 @@ fn protocol_upgrade() { receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), actions: vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "write_key_value".to_string(), args, gas: 10u64.pow(14), diff --git a/integration-tests/src/tests/client/features/wasmer2.rs b/integration-tests/src/tests/client/features/wasmer2.rs index 935a4267994..1d456fbfa3b 100644 --- a/integration-tests/src/tests/client/features/wasmer2.rs +++ b/integration-tests/src/tests/client/features/wasmer2.rs @@ -5,6 +5,7 @@ use near_client::test_utils::TestEnv; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_primitives::hash::CryptoHash; use near_primitives::transaction::{Action, FunctionCallAction, Transaction}; +use near_primitives_core::namespace::Namespace; use nearcore::config::GenesisExt; // This test fails on aarch because wasmer0 and wasmer2 are not available. @@ -45,6 +46,7 @@ fn test_wasmer2_upgrade() { receiver_id: "test0".parse().unwrap(), public_key: signer.public_key(), actions: vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "log_something".to_string(), args: Vec::new(), gas: 100_000_000_000_000, diff --git a/integration-tests/src/tests/client/process_blocks.rs b/integration-tests/src/tests/client/process_blocks.rs index 90dd2fc9a96..7f4f42b46c6 100644 --- a/integration-tests/src/tests/client/process_blocks.rs +++ b/integration-tests/src/tests/client/process_blocks.rs @@ -248,6 +248,7 @@ pub(crate) fn prepare_env_with_congestion( "test0".parse().unwrap(), &signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: gas_1, @@ -2391,6 +2392,7 @@ fn test_validate_chunk_extra() { "test0".parse().unwrap(), &signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "write_block_height".to_string(), args: vec![], gas: 100000000000000, @@ -3454,6 +3456,7 @@ fn test_validator_stake_host_function() { "test0".parse().unwrap(), &signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "ext_validator_stake".to_string(), args: b"test0".to_vec(), gas: 100_000_000_000_000, @@ -3621,6 +3624,7 @@ mod contract_precompilation_tests { state_update, view_state, &"test0".parse().unwrap(), + &Namespace::default(), "log_something", &[], &mut logs, diff --git a/integration-tests/src/tests/client/sharding_upgrade.rs b/integration-tests/src/tests/client/sharding_upgrade.rs index c6c93cba58b..9669343cbd6 100644 --- a/integration-tests/src/tests/client/sharding_upgrade.rs +++ b/integration-tests/src/tests/client/sharding_upgrade.rs @@ -591,6 +591,7 @@ fn gen_cross_contract_transaction( account1.clone(), &signer0, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, diff --git a/integration-tests/src/tests/runtime/deployment.rs b/integration-tests/src/tests/runtime/deployment.rs index d0f53c0e39f..8e4f274ba86 100644 --- a/integration-tests/src/tests/runtime/deployment.rs +++ b/integration-tests/src/tests/runtime/deployment.rs @@ -65,8 +65,9 @@ fn test_deploy_max_size_contract() { // Rune code through preparation for validation. (Deploying will succeed either way). near_vm_runner::prepare::prepare_contract(&wasm_binary, &config.wasm_config, VMKind::NearVm) .unwrap(); - let transaction_result = - node_user.deploy_contract(test_contract_id, wasm_binary.to_vec()).unwrap(); + let transaction_result = node_user + .deploy_contract(test_contract_id, Namespace::default(), wasm_binary.to_vec()) + .unwrap(); assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 1); diff --git a/integration-tests/src/tests/runtime/sanity_checks.rs b/integration-tests/src/tests/runtime/sanity_checks.rs index dc8e2f47e3c..fbec6d81a81 100644 --- a/integration-tests/src/tests/runtime/sanity_checks.rs +++ b/integration-tests/src/tests/runtime/sanity_checks.rs @@ -9,6 +9,7 @@ use near_primitives::version::PROTOCOL_VERSION; use near_primitives::views::{ CostGasUsed, ExecutionOutcomeWithIdView, ExecutionStatusView, FinalExecutionStatus, }; +use near_primitives_core::namespace::Namespace; use nearcore::config::GenesisExt; use std::collections::HashSet; use std::mem::size_of; @@ -65,8 +66,9 @@ fn setup_runtime_node_with_contract(wasm_binary: &[u8]) -> RuntimeNode { assert_eq!(tx_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(tx_result.receipts_outcome.len(), 2); - let tx_result = - node_user.deploy_contract(test_contract_account(), wasm_binary.to_vec()).unwrap(); + let tx_result = node_user + .deploy_contract(test_contract_account(), Namespace::default(), wasm_binary.to_vec()) + .unwrap(); assert_eq!(tx_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(tx_result.receipts_outcome.len(), 1); @@ -120,6 +122,7 @@ fn test_cost_sanity() { .function_call( alice_account(), test_contract_account(), + Namespace::default(), "sanity_check", args.into_bytes(), MAX_GAS, @@ -175,7 +178,15 @@ fn test_cost_sanity_nondeterministic() { let node = setup_runtime_node_with_contract(&contract); let res = node .user() - .function_call(alice_account(), test_contract_account(), "main", vec![], MAX_GAS, 0) + .function_call( + alice_account(), + test_contract_account(), + Namespace::default(), + "main", + vec![], + MAX_GAS, + 0, + ) .unwrap(); assert_eq!(res.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(res.transaction_outcome.outcome.metadata.gas_profile, None); @@ -215,7 +226,15 @@ fn test_sanity_used_gas() { let node = setup_runtime_node_with_contract(&contract_sanity_check_used_gas()); let res = node .user() - .function_call(alice_account(), test_contract_account(), "main", vec![], MAX_GAS, 0) + .function_call( + alice_account(), + test_contract_account(), + Namespace::default(), + "main", + vec![], + MAX_GAS, + 0, + ) .unwrap(); let num_return_values = 4; diff --git a/integration-tests/src/tests/runtime/state_viewer.rs b/integration-tests/src/tests/runtime/state_viewer.rs index 8ee8e83738a..d14de6b744d 100644 --- a/integration-tests/src/tests/runtime/state_viewer.rs +++ b/integration-tests/src/tests/runtime/state_viewer.rs @@ -112,6 +112,7 @@ fn test_view_call() { root, view_state, &"test.contract".parse().unwrap(), + &Namespace::default(), "run_test", &[], &mut logs, @@ -140,6 +141,7 @@ fn test_view_call_try_changing_storage() { root, view_state, &"test.contract".parse().unwrap(), + &Namespace::default(), "run_test_with_storage_change", &[], &mut logs, @@ -172,6 +174,7 @@ fn test_view_call_with_args() { root, view_state, &"test.contract".parse().unwrap(), + &Namespace::default(), "sum_with_input", &args, &mut logs, @@ -413,6 +416,7 @@ fn test_log_when_panic() { root, view_state, &"test.contract".parse().unwrap(), + &Namespace::default(), "panic_after_logging", &[], &mut logs, diff --git a/integration-tests/src/tests/runtime/test_evil_contracts.rs b/integration-tests/src/tests/runtime/test_evil_contracts.rs index 2c9862a5153..1ca777d94e7 100644 --- a/integration-tests/src/tests/runtime/test_evil_contracts.rs +++ b/integration-tests/src/tests/runtime/test_evil_contracts.rs @@ -1,6 +1,7 @@ use crate::node::{Node, RuntimeNode}; use near_primitives::errors::{ActionError, ActionErrorKind}; use near_primitives::views::FinalExecutionStatus; +use near_primitives_core::namespace::Namespace; use near_vm_errors::FunctionCallErrorSer; use std::mem::size_of; @@ -30,8 +31,13 @@ fn setup_test_contract(wasm_binary: &[u8]) -> RuntimeNode { assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 2); - let transaction_result = - node_user.deploy_contract("test_contract".parse().unwrap(), wasm_binary.to_vec()).unwrap(); + let transaction_result = node_user + .deploy_contract( + "test_contract".parse().unwrap(), + Namespace::default(), + wasm_binary.to_vec(), + ) + .unwrap(); assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 1); @@ -53,6 +59,7 @@ fn test_evil_deep_trie() { .function_call( "alice.near".parse().unwrap(), "test_contract".parse().unwrap(), + Namespace::default(), "insert_strings", input_data.to_vec(), MAX_GAS, @@ -74,6 +81,7 @@ fn test_evil_deep_trie() { .function_call( "alice.near".parse().unwrap(), "test_contract".parse().unwrap(), + Namespace::default(), "delete_strings", input_data.to_vec(), MAX_GAS, @@ -96,6 +104,7 @@ fn test_evil_deep_recursion() { .function_call( "alice.near".parse().unwrap(), "test_contract".parse().unwrap(), + Namespace::default(), "recurse", n_bytes.clone(), MAX_GAS, @@ -118,6 +127,7 @@ fn test_evil_abort() { .function_call( "alice.near".parse().unwrap(), "test_contract".parse().unwrap(), + Namespace::default(), "abort_with_zero", vec![], MAX_GAS, diff --git a/integration-tests/src/tests/standard_cases/mod.rs b/integration-tests/src/tests/standard_cases/mod.rs index d7eb67d07a6..17afa0738c7 100644 --- a/integration-tests/src/tests/standard_cases/mod.rs +++ b/integration-tests/src/tests/standard_cases/mod.rs @@ -63,7 +63,15 @@ pub fn test_smart_contract_simple(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(alice_account(), bob_account(), "run_test", vec![], 10u64.pow(14), 0) + .function_call( + alice_account(), + bob_account(), + Namespace::default(), + "run_test", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -80,6 +88,7 @@ pub fn test_smart_contract_panic(node: impl Node) { .function_call( alice_account(), alice_account(), + Namespace::default(), "panic_with_message", vec![], 10u64.pow(14), @@ -106,7 +115,15 @@ pub fn test_smart_contract_self_call(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(account_id.clone(), account_id.clone(), "run_test", vec![], 10u64.pow(14), 0) + .function_call( + account_id.clone(), + account_id.clone(), + Namespace::default(), + "run_test", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -122,7 +139,15 @@ pub fn test_smart_contract_bad_method_name(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(account_id.clone(), bob_account(), "_run_test", vec![], 10u64.pow(14), 0) + .function_call( + account_id.clone(), + bob_account(), + Namespace::default(), + "_run_test", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -146,7 +171,15 @@ pub fn test_smart_contract_empty_method_name_with_no_tokens(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(account_id.clone(), bob_account(), "", vec![], 10u64.pow(14), 0) + .function_call( + account_id.clone(), + bob_account(), + Namespace::default(), + "", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -170,7 +203,15 @@ pub fn test_smart_contract_empty_method_name_with_tokens(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(account_id.clone(), bob_account(), "", vec![], 10u64.pow(14), 10) + .function_call( + account_id.clone(), + bob_account(), + Namespace::default(), + "", + vec![], + 10u64.pow(14), + 10, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -197,6 +238,7 @@ pub fn test_smart_contract_with_args(node: impl Node) { .function_call( account_id.clone(), bob_account(), + Namespace::default(), "sum_with_input", (2u64..4).flat_map(|x| x.to_le_bytes().to_vec()).collect(), 10u64.pow(14), @@ -217,7 +259,15 @@ pub fn test_async_call_with_logs(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(account_id.clone(), bob_account(), "log_something", vec![], 10u64.pow(14), 0) + .function_call( + account_id.clone(), + bob_account(), + Namespace::default(), + "log_something", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 2); @@ -231,8 +281,9 @@ pub fn test_nonce_update_when_deploying_contract(node: impl Node) { let wasm_binary = b"test_binary"; let node_user = node.user(); let root = node_user.get_state_root(); - let transaction_result = - node_user.deploy_contract(account_id.clone(), wasm_binary.to_vec()).unwrap(); + let transaction_result = node_user + .deploy_contract(account_id.clone(), Namespace::default(), wasm_binary.to_vec()) + .unwrap(); assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 1); assert_eq!(node_user.get_access_key_nonce_for_signer(account_id).unwrap(), 1); @@ -271,8 +322,9 @@ pub fn test_upload_contract(node: impl Node) { let new_root = node_user.get_state_root(); assert_ne!(root, new_root); let wasm_binary = b"test_binary"; - let transaction_result = - node_user.deploy_contract(eve_dot_alice_account(), wasm_binary.to_vec()).unwrap(); + let transaction_result = node_user + .deploy_contract(eve_dot_alice_account(), Namespace::default(), wasm_binary.to_vec()) + .unwrap(); assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 1); let new_root = node_user.get_state_root(); @@ -289,8 +341,9 @@ pub fn test_redeploy_contract(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let test_binary = b"test_binary"; - let transaction_result = - node_user.deploy_contract(account_id.clone(), test_binary.to_vec()).unwrap(); + let transaction_result = node_user + .deploy_contract(account_id.clone(), Namespace::default(), test_binary.to_vec()) + .unwrap(); assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new())); assert_eq!(transaction_result.receipts_outcome.len(), 1); let new_root = node_user.get_state_root(); @@ -446,7 +499,15 @@ pub fn test_smart_contract_reward(node: impl Node) { let bob = node_user.view_account(&bob_account()).unwrap(); assert_eq!(bob.amount, TESTING_INIT_BALANCE - TESTING_INIT_STAKE); let transaction_result = node_user - .function_call(alice_account(), bob_account(), "run_test", vec![], 10u64.pow(14), 0) + .function_call( + alice_account(), + bob_account(), + Namespace::default(), + "run_test", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -982,7 +1043,15 @@ pub fn test_access_key_smart_contract(node: impl Node) { let exec_gas = fee_helper.function_call_exec_gas(method_name.as_bytes().len() as u64); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(account_id.clone(), bob_account(), method_name, vec![], prepaid_gas, 0) + .function_call( + account_id.clone(), + bob_account(), + Namespace::default(), + method_name, + vec![], + prepaid_gas, + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -1027,7 +1096,15 @@ pub fn test_access_key_smart_contract_reject_method_name(node: impl Node) { node_user.set_signer(Arc::new(signer2)); let transaction_result = node_user - .function_call(account_id.clone(), bob_account(), "run_test", vec![], 10u64.pow(14), 0) + .function_call( + account_id.clone(), + bob_account(), + Namespace::default(), + "run_test", + vec![], + 10u64.pow(14), + 0, + ) .unwrap_err(); assert_eq!( transaction_result, @@ -1058,6 +1135,7 @@ pub fn test_access_key_smart_contract_reject_contract_id(node: impl Node) { .function_call( account_id.clone(), eve_dot_alice_account(), + Namespace::default(), "run_test", vec![], 10u64.pow(14), @@ -1316,7 +1394,15 @@ pub fn test_smart_contract_free(node: impl Node) { let node_user = node.user(); let root = node_user.get_state_root(); let transaction_result = node_user - .function_call(alice_account(), bob_account(), "run_test", vec![], 10u64.pow(14), 0) + .function_call( + alice_account(), + bob_account(), + Namespace::default(), + "run_test", + vec![], + 10u64.pow(14), + 0, + ) .unwrap(); assert_eq!( transaction_result.status, @@ -1371,6 +1457,7 @@ pub fn test_contract_write_key_value_cost(node: impl Node) { .function_call( alice_account(), bob_account(), + Namespace::default(), "write_key_value", test_utils::encode(&[10u64, 20u64]), 10u64.pow(14), @@ -1391,6 +1478,7 @@ pub fn test_contract_write_key_value_cost(node: impl Node) { fn make_write_key_value_action(key: Vec, value: Vec) -> Action { let args: Vec = key.into_iter().chain(value.into_iter()).collect(); FunctionCallAction { + namespace: Namespace::default(), method_name: "write_key_value".to_string(), args: test_utils::encode(&args), gas: 10u64.pow(14), @@ -1556,8 +1644,9 @@ pub fn test_storage_read_write_costs(node: impl Node, runtime_config: RuntimeCon make_receipt( &node, vec![FunctionCallAction { - args: test_utils::encode(&[1]), + namespace: Namespace::default(), method_name: "read_value".to_string(), + args: test_utils::encode(&[1]), gas: 10u64.pow(14), deposit: 0, } diff --git a/integration-tests/src/user/mod.rs b/integration-tests/src/user/mod.rs index 1efd11215ed..ff3316cb197 100644 --- a/integration-tests/src/user/mod.rs +++ b/integration-tests/src/user/mod.rs @@ -43,6 +43,7 @@ pub trait User { fn view_call( &self, account_id: &AccountId, + namespace: &Namespace, method_name: &str, args: &[u8], ) -> Result; @@ -125,6 +126,7 @@ pub trait User { fn deploy_contract( &self, signer_id: AccountId, + namespace: Namespace, code: Vec, ) -> Result { self.sign_and_commit_actions( @@ -132,7 +134,7 @@ pub trait User { signer_id, vec![Action::DeployContract(DeployContractAction { code, - namespace: Namespace::default(), + namespace, routing_table: RoutingTable::default(), })], ) @@ -142,6 +144,7 @@ pub trait User { &self, signer_id: AccountId, contract_id: AccountId, + namespace: Namespace, method_name: &str, args: Vec, gas: Gas, @@ -151,6 +154,7 @@ pub trait User { signer_id, contract_id, vec![Action::FunctionCall(FunctionCallAction { + namespace, method_name: method_name.to_string(), args, gas, diff --git a/integration-tests/src/user/rpc_user.rs b/integration-tests/src/user/rpc_user.rs index fb2f2ce6a4a..969e69b5f1c 100644 --- a/integration-tests/src/user/rpc_user.rs +++ b/integration-tests/src/user/rpc_user.rs @@ -23,6 +23,7 @@ use near_primitives::views::{ EpochValidatorInfo, ExecutionOutcomeView, FinalExecutionOutcomeView, QueryRequest, ViewStateResult, }; +use near_primitives_core::namespace::Namespace; use crate::user::User; @@ -99,11 +100,13 @@ impl User for RpcUser { fn view_call( &self, account_id: &AccountId, + namespace: &Namespace, method_name: &str, args: &[u8], ) -> Result { let query = QueryRequest::CallFunction { account_id: account_id.clone(), + namespace: namespace.clone(), method_name: method_name.to_string(), args: args.to_vec().into(), }; diff --git a/integration-tests/src/user/runtime_user.rs b/integration-tests/src/user/runtime_user.rs index 3e803d97f84..1000e7ae5c6 100644 --- a/integration-tests/src/user/runtime_user.rs +++ b/integration-tests/src/user/runtime_user.rs @@ -18,6 +18,7 @@ use near_primitives::views::{ ExecutionOutcomeView, ExecutionOutcomeWithIdView, ExecutionStatusView, FinalExecutionOutcomeView, FinalExecutionStatus, ViewApplyState, ViewStateResult, }; +use near_primitives_core::namespace::Namespace; use near_store::{ShardTries, TrieUpdate}; use nearcore::config::MIN_GAS_PRICE; use node_runtime::state_viewer::TrieViewer; @@ -254,6 +255,7 @@ impl User for RuntimeUser { fn view_call( &self, account_id: &AccountId, + namespace: &Namespace, method_name: &str, args: &[u8], ) -> Result { @@ -277,6 +279,7 @@ impl User for RuntimeUser { state_update, view_state, account_id, + namespace, method_name, args, &mut result.logs, diff --git a/nearcore/src/runtime/mod.rs b/nearcore/src/runtime/mod.rs index 7c55c565d48..464572f6007 100644 --- a/nearcore/src/runtime/mod.rs +++ b/nearcore/src/runtime/mod.rs @@ -26,6 +26,7 @@ use near_primitives::epoch_manager::block_info::BlockInfo; use near_primitives::epoch_manager::EpochConfig; use near_primitives::errors::{InvalidTxError, RuntimeError, StorageError}; use near_primitives::hash::{hash, CryptoHash}; +use near_primitives::namespace::Namespace; use near_primitives::receipt::Receipt; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::runtime::migration_data::{MigrationData, MigrationFlags}; @@ -1123,7 +1124,7 @@ impl RuntimeAdapter for NightshadeRuntime { block_hash: *block_hash, }) } - QueryRequest::CallFunction { account_id, method_name, args } => { + QueryRequest::CallFunction { account_id, namespace, method_name, args } => { let mut logs = vec![]; let (epoch_height, current_protocol_version) = { let epoch_manager = self.epoch_manager.read(); @@ -1148,6 +1149,7 @@ impl RuntimeAdapter for NightshadeRuntime { epoch_height, epoch_id, account_id, + namespace, method_name, args.as_ref(), &mut logs, @@ -1526,6 +1528,7 @@ impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { epoch_height: EpochHeight, epoch_id: &EpochId, contract_id: &AccountId, + namespace: &Namespace, method_name: &str, args: &[u8], logs: &mut Vec, @@ -1547,6 +1550,7 @@ impl node_runtime::adapter::ViewRuntimeAdapter for NightshadeRuntime { state_update, view_state, contract_id, + namespace, method_name, args, logs, diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index bd7c92142ac..d29bc2c4a92 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -270,6 +270,8 @@ pub enum HostError { InvalidIteratorIndex { iterator_index: u64 }, /// VM Logic returned an invalid account id InvalidAccountId, + /// VM Logic returned an invalid namespace + InvalidNamespace, /// VM Logic returned an invalid method name InvalidMethodName, /// VM Logic provided an invalid public key @@ -492,6 +494,7 @@ impl std::fmt::Display for HostError { MemoryAccessViolation => write!(f, "Accessed memory outside the bounds."), InvalidReceiptIndex { receipt_index } => write!(f, "VM Logic returned an invalid receipt index: {:?}", receipt_index), InvalidAccountId => write!(f, "VM Logic returned an invalid account id"), + InvalidNamespace => write!(f, "VM Logic returned an invalid namespace"), InvalidMethodName => write!(f, "VM Logic returned an invalid method name"), InvalidPublicKey => write!(f, "VM Logic provided an invalid public key"), ProhibitedInView { method_name } => write!(f, "{} is not allowed in view calls", method_name), diff --git a/runtime/near-vm-logic/src/logic.rs b/runtime/near-vm-logic/src/logic.rs index d26a16f4235..4b78c5c28c4 100644 --- a/runtime/near-vm-logic/src/logic.rs +++ b/runtime/near-vm-logic/src/logic.rs @@ -1295,6 +1295,8 @@ impl<'a> VMLogic<'a> { &mut self, account_id_len: u64, account_id_ptr: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -1305,6 +1307,8 @@ impl<'a> VMLogic<'a> { let new_promise_idx = self.promise_batch_create(account_id_len, account_id_ptr)?; self.promise_batch_action_function_call( new_promise_idx, + namespace_len, + namespace_ptr, method_name_len, method_name_ptr, arguments_len, @@ -1339,6 +1343,8 @@ impl<'a> VMLogic<'a> { promise_idx: u64, account_id_len: u64, account_id_ptr: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -1350,6 +1356,8 @@ impl<'a> VMLogic<'a> { self.promise_batch_then(promise_idx, account_id_len, account_id_ptr)?; self.promise_batch_action_function_call( new_promise_idx, + namespace_len, + namespace_ptr, method_name_len, method_name_ptr, arguments_len, @@ -1660,6 +1668,8 @@ impl<'a> VMLogic<'a> { pub fn promise_batch_action_function_call( &mut self, promise_idx: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -1669,6 +1679,8 @@ impl<'a> VMLogic<'a> { ) -> Result<()> { self.promise_batch_action_function_call_weight( promise_idx, + namespace_len, + namespace_ptr, method_name_len, method_name_ptr, arguments_len, @@ -1718,6 +1730,8 @@ impl<'a> VMLogic<'a> { pub fn promise_batch_action_function_call_weight( &mut self, promise_idx: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -1734,6 +1748,7 @@ impl<'a> VMLogic<'a> { .into()); } let amount = self.memory.get_u128(&mut self.gas_counter, amount_ptr)?; + let namespace = get_memory_or_register!(self, namespace_ptr, namespace_len)?; let method_name = get_memory_or_register!(self, method_name_ptr, method_name_len)?; if method_name.is_empty() { return Err(HostError::EmptyMethodName.into()); @@ -1742,6 +1757,7 @@ impl<'a> VMLogic<'a> { let (receipt_idx, sir) = self.promise_idx_to_receipt_idx_with_sir(promise_idx)?; + let namespace = namespace.into_owned(); let method_name = method_name.into_owned(); let arguments = arguments.into_owned(); // Input can't be large enough to overflow @@ -1755,6 +1771,7 @@ impl<'a> VMLogic<'a> { self.receipt_manager.append_action_function_call_weight( receipt_idx, + namespace, method_name, arguments, amount, diff --git a/runtime/near-vm-logic/src/receipt_manager.rs b/runtime/near-vm-logic/src/receipt_manager.rs index 37e8dfc9542..3765aa5072b 100644 --- a/runtime/near-vm-logic/src/receipt_manager.rs +++ b/runtime/near-vm-logic/src/receipt_manager.rs @@ -191,6 +191,7 @@ impl ReceiptManager { pub(crate) fn append_action_function_call_weight( &mut self, receipt_index: ReceiptIndex, + namespace: Vec, method_name: Vec, args: Vec, attached_deposit: Balance, @@ -200,6 +201,9 @@ impl ReceiptManager { let action_index = self.append_action( receipt_index, Action::FunctionCall(FunctionCallAction { + namespace: String::from_utf8(namespace) + .map_err(|_| HostError::InvalidNamespace)? + .into(), method_name: String::from_utf8(method_name) .map_err(|_| HostError::InvalidMethodName)?, args, diff --git a/runtime/near-vm-logic/src/tests/gas_counter.rs b/runtime/near-vm-logic/src/tests/gas_counter.rs index 3ff8b8e134c..c0bdeffed9e 100644 --- a/runtime/near-vm-logic/src/tests/gas_counter.rs +++ b/runtime/near-vm-logic/src/tests/gas_counter.rs @@ -248,6 +248,7 @@ fn test_overflowing_burn_gas_with_promises_gas() { let mut logic = logic_builder.build(); let account_id = logic.internal_mem_write(b"rick.test"); + let namespace = logic.internal_mem_write(b""); let args = logic.internal_mem_write(b""); let num_100u128 = logic.internal_mem_write(&100u128.to_le_bytes()); let num_10u128 = logic.internal_mem_write(&10u128.to_le_bytes()); @@ -261,6 +262,8 @@ fn test_overflowing_burn_gas_with_promises_gas() { needed_gas_charge / logic.config().ext_costs.gas_cost(ExtCosts::read_memory_byte); let result = logic.promise_batch_action_function_call( call_id, + namespace.len, + namespace.ptr, function_name_len, /* function_name_ptr: */ 0, args.len, @@ -284,6 +287,7 @@ fn test_overflowing_burn_gas_with_promises_gas_2() { let mut logic = logic_builder.build(); let account_id = logic.internal_mem_write(b"rick.test"); + let namespace = logic.internal_mem_write(b""); let args = logic.internal_mem_write(b""); let num_100u128 = logic.internal_mem_write(&100u128.to_le_bytes()); @@ -302,6 +306,8 @@ fn test_overflowing_burn_gas_with_promises_gas_2() { needed_gas_charge / logic.config().ext_costs.gas_cost(ExtCosts::read_memory_byte); let result = logic.promise_batch_action_function_call( call_id, + namespace.len, + namespace.ptr, function_name_len, /* function_name_ptr: */ 0, args.len, diff --git a/runtime/near-vm-logic/src/tests/helpers.rs b/runtime/near-vm-logic/src/tests/helpers.rs index 24fe98390e2..c4e66e6a204 100644 --- a/runtime/near-vm-logic/src/tests/helpers.rs +++ b/runtime/near-vm-logic/src/tests/helpers.rs @@ -13,6 +13,7 @@ pub(super) fn promise_create( gas: Gas, ) -> Result { let account_id = logic.internal_mem_write(account_id); + let namespace = logic.internal_mem_write(b""); let method = logic.internal_mem_write(b"promise_create"); let args = logic.internal_mem_write(b"args"); let amount = logic.internal_mem_write(&amount.to_le_bytes()); @@ -20,6 +21,8 @@ pub(super) fn promise_create( logic.promise_create( account_id.len, account_id.ptr, + namespace.len, + namespace.ptr, method.len, method.ptr, args.len, @@ -62,11 +65,14 @@ pub(super) fn promise_batch_action_function_call_ext( gas: Gas, ) -> Result<()> { let method_id = logic.internal_mem_write(method_id); + let namespace = logic.internal_mem_write(b""); let args = logic.internal_mem_write(args); let amount = logic.internal_mem_write(&amount.to_le_bytes()); logic.promise_batch_action_function_call( promise_index, + namespace.len, + namespace.ptr, method_id.len, method_id.ptr, args.len, @@ -106,11 +112,14 @@ pub(super) fn promise_batch_action_function_call_weight_ext( weight: u64, ) -> Result<()> { let method_id = logic.internal_mem_write(method_id); + let namespace = logic.internal_mem_write(b""); let args = logic.internal_mem_write(args); let amount = logic.internal_mem_write(&amount.to_le_bytes()); logic.promise_batch_action_function_call_weight( promise_index, + namespace.len, + namespace.ptr, method_id.len, method_id.ptr, args.len, diff --git a/runtime/near-vm-logic/src/tests/view_method.rs b/runtime/near-vm-logic/src/tests/view_method.rs index e0d40f2ce2e..f0c9d9b6fe2 100644 --- a/runtime/near-vm-logic/src/tests/view_method.rs +++ b/runtime/near-vm-logic/src/tests/view_method.rs @@ -18,14 +18,14 @@ fn test_prohibited_view_methods() { test_prohibited!(predecessor_account_id, 0); test_prohibited!(prepaid_gas); test_prohibited!(used_gas); - test_prohibited!(promise_create, 0, 0, 0, 0, 0, 0, 0, 0); - test_prohibited!(promise_then, 0, 0, 0, 0, 0, 0, 0, 0, 0); + test_prohibited!(promise_create, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + test_prohibited!(promise_then, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); test_prohibited!(promise_and, 0, 0); test_prohibited!(promise_batch_create, 0, 0); test_prohibited!(promise_batch_then, 0, 0, 0); test_prohibited!(promise_batch_action_create_account, 0); test_prohibited!(promise_batch_action_deploy_contract, 0, 0, 0); - test_prohibited!(promise_batch_action_function_call, 0, 0, 0, 0, 0, 0, 0); + test_prohibited!(promise_batch_action_function_call, 0, 0, 0, 0, 0, 0, 0, 0, 0); test_prohibited!(promise_batch_action_transfer, 0, 0); test_prohibited!(promise_batch_action_stake, 0, 0, 0, 0); test_prohibited!(promise_batch_action_add_key_with_full_access, 0, 0, 0, 0); diff --git a/runtime/near-vm-runner/src/imports.rs b/runtime/near-vm-runner/src/imports.rs index 8a663b8d802..36ee0467aff 100644 --- a/runtime/near-vm-runner/src/imports.rs +++ b/runtime/near-vm-runner/src/imports.rs @@ -146,6 +146,8 @@ imports! { promise_create<[ account_id_len: u64, account_id_ptr: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -157,6 +159,8 @@ imports! { promise_index: u64, account_id_len: u64, account_id_ptr: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -174,6 +178,8 @@ imports! { promise_batch_action_deploy_contract<[promise_index: u64, code_len: u64, code_ptr: u64] -> []>, promise_batch_action_function_call<[ promise_index: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -183,6 +189,8 @@ imports! { ] -> []>, #[FunctionCallWeight] promise_batch_action_function_call_weight<[ promise_index: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, diff --git a/runtime/runtime-params-estimator/src/action_costs.rs b/runtime/runtime-params-estimator/src/action_costs.rs index a3f68f7c8ab..be800dfbc88 100644 --- a/runtime/runtime-params-estimator/src/action_costs.rs +++ b/runtime/runtime-params-estimator/src/action_costs.rs @@ -663,6 +663,7 @@ fn function_call_action(size: ActionSize) -> Action { let method_name: String = "noop".chars().take(method_len).collect(); let arg_len = total_size as usize - method_len; Action::FunctionCall(near_primitives::transaction::FunctionCallAction { + namespace: Namespace::default(), // TODO: correct? method_name, args: vec![1u8; arg_len], gas: 3 * 10u64.pow(12), // 3 Tgas, to allow 100 copies in the same receipt diff --git a/runtime/runtime-params-estimator/src/lib.rs b/runtime/runtime-params-estimator/src/lib.rs index 5265dad9170..793fcce3386 100644 --- a/runtime/runtime-params-estimator/src/lib.rs +++ b/runtime/runtime-params-estimator/src/lib.rs @@ -758,7 +758,7 @@ fn inner_action_function_call_per_byte(ctx: &mut EstimatorContext, arg_len: usiz let mut make_transaction = |tb: &mut TransactionBuilder| -> SignedTransaction { let sender = tb.random_unused_account(); let args = utils::random_vec(arg_len); - tb.transaction_from_function_call(sender, "noop", args) + tb.transaction_from_function_call(sender, Namespace::default(), "noop", args) }; let block_size = 5; let block_latency = 0; diff --git a/runtime/runtime-params-estimator/src/transaction_builder.rs b/runtime/runtime-params-estimator/src/transaction_builder.rs index 925735a2b82..b6d564cdd8c 100644 --- a/runtime/runtime-params-estimator/src/transaction_builder.rs +++ b/runtime/runtime-params-estimator/src/transaction_builder.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use genesis_populate::get_account_id; use near_crypto::{InMemorySigner, KeyType}; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::{self, Namespace}; use near_primitives::transaction::{Action, FunctionCallAction, SignedTransaction}; use near_primitives::types::AccountId; use rand::prelude::ThreadRng; @@ -63,11 +64,13 @@ impl TransactionBuilder { pub(crate) fn transaction_from_function_call( &mut self, sender: AccountId, + namespace: Namespace, method: &str, args: Vec, ) -> SignedTransaction { let receiver = sender.clone(); let actions = vec![Action::FunctionCall(FunctionCallAction { + namespace, method_name: method.to_string(), args, gas: 10u64.pow(18), @@ -92,7 +95,12 @@ impl TransactionBuilder { .chain(value.iter().cloned()) .collect(); - self.transaction_from_function_call(account, "account_storage_insert_key", arg) + self.transaction_from_function_call( + account, + Namespace::default(), + "account_storage_insert_key", + arg, + ) } /// Transaction that checks existence of a given key under an account. @@ -100,7 +108,12 @@ impl TransactionBuilder { pub(crate) fn account_has_key(&mut self, account: AccountId, key: &str) -> SignedTransaction { let arg = (key.len() as u64).to_le_bytes().into_iter().chain(key.bytes()).collect(); - self.transaction_from_function_call(account, "account_storage_has_key", arg) + self.transaction_from_function_call( + account, + Namespace::default(), + "account_storage_has_key", + arg, + ) } pub(crate) fn rng(&mut self) -> ThreadRng { diff --git a/runtime/runtime-params-estimator/src/utils.rs b/runtime/runtime-params-estimator/src/utils.rs index db4908803a6..17a6077432a 100644 --- a/runtime/runtime-params-estimator/src/utils.rs +++ b/runtime/runtime-params-estimator/src/utils.rs @@ -126,7 +126,7 @@ pub(crate) fn fn_cost_count( let block_size = 20; let mut make_transaction = |tb: &mut TransactionBuilder| -> SignedTransaction { let sender = tb.random_unused_account(); - tb.transaction_from_function_call(sender, method, Vec::new()) + tb.transaction_from_function_call(sender, Namespace::default(), method, Vec::new()) }; let (gas_cost, ext_costs) = transaction_cost_ext(ctx, block_size, &mut make_transaction, block_latency); @@ -142,7 +142,7 @@ pub(crate) fn noop_function_call_cost(ctx: &mut EstimatorContext) -> GasCost { let cost = { let mut make_transaction = |tb: &mut TransactionBuilder| -> SignedTransaction { let sender = tb.random_unused_account(); - tb.transaction_from_function_call(sender, "noop", Vec::new()) + tb.transaction_from_function_call(sender, Namespace::default(), "noop", Vec::new()) }; transaction_cost(ctx, &mut make_transaction) }; @@ -181,9 +181,18 @@ pub(crate) fn fn_cost_with_setup( let mut block = Vec::new(); for _ in 0..block_size { let sender = tb.random_unused_account(); - let setup_tx = - tb.transaction_from_function_call(sender.clone(), setup, Vec::new()); - let tx = tb.transaction_from_function_call(sender, method, Vec::new()); + let setup_tx = tb.transaction_from_function_call( + sender.clone(), + Namespace::default(), + setup, + Vec::new(), + ); + let tx = tb.transaction_from_function_call( + sender, + Namespace::default(), + method, + Vec::new(), + ); setup_block.push(setup_tx); block.push(tx); @@ -308,6 +317,7 @@ pub(crate) fn fn_cost_in_contract( fn function_call_action(method_name: String) -> Action { Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name, args: Vec::new(), gas: 10u64.pow(15), diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 246a294f002..e378ad8e9c4 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -1188,6 +1188,7 @@ mod tests { non_delegate_action( Action::FunctionCall( FunctionCallAction { + namespace: Namespace::default(), method_name: "ft_transfer".parse().unwrap(), args: vec![123, 34, 114, 101, 99, 101, 105, 118, 101, 114, 95, 105, 100, 34, 58, 34, 106, 97, 110, 101, 46, 116, 101, 115, 116, 46, 110, 101, 97, 114, 34, 44, 34, 97, 109, 111, 117, 110, 116, 34, 58, 34, 52, 34, 125], gas: 30000000000000, @@ -1587,6 +1588,7 @@ mod tests { let mut delegate_action = signed_delegate_action.delegate_action.clone(); delegate_action.actions = vec![non_delegate_action(Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), args: Vec::new(), deposit: 0, gas: 300, @@ -1638,12 +1640,14 @@ mod tests { let mut delegate_action = signed_delegate_action.delegate_action.clone(); delegate_action.actions = vec![ non_delegate_action(Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), args: Vec::new(), deposit: 0, gas: 300, method_name: "test_method".parse().unwrap(), })), non_delegate_action(Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), args: Vec::new(), deposit: 0, gas: 300, @@ -1677,6 +1681,7 @@ mod tests { let mut delegate_action = signed_delegate_action.delegate_action.clone(); delegate_action.actions = vec![non_delegate_action(Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), args: Vec::new(), deposit: 1, gas: 300, @@ -1709,6 +1714,7 @@ mod tests { let mut delegate_action = signed_delegate_action.delegate_action.clone(); delegate_action.actions = vec![non_delegate_action(Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), args: Vec::new(), deposit: 0, gas: 300, @@ -1744,6 +1750,7 @@ mod tests { let mut delegate_action = signed_delegate_action.delegate_action.clone(); delegate_action.actions = vec![non_delegate_action(Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), args: Vec::new(), deposit: 0, gas: 300, diff --git a/runtime/runtime/src/adapter.rs b/runtime/runtime/src/adapter.rs index be3d8f04c2c..404ee1aad15 100644 --- a/runtime/runtime/src/adapter.rs +++ b/runtime/runtime/src/adapter.rs @@ -3,6 +3,7 @@ use near_crypto::PublicKey; use near_primitives::account::{AccessKey, Account}; use near_primitives::contract::ContractCode; use near_primitives::hash::CryptoHash; +use near_primitives::namespace::Namespace; use near_primitives::types::{ AccountId, BlockHeight, EpochHeight, EpochId, EpochInfoProvider, MerkleHash, }; @@ -36,6 +37,7 @@ pub trait ViewRuntimeAdapter { epoch_height: EpochHeight, epoch_id: &EpochId, contract_id: &AccountId, + namespace: &Namespace, method_name: &str, args: &[u8], logs: &mut Vec, diff --git a/runtime/runtime/src/ext.rs b/runtime/runtime/src/ext.rs index 3689b55898b..e7cda1cef6b 100644 --- a/runtime/runtime/src/ext.rs +++ b/runtime/runtime/src/ext.rs @@ -81,7 +81,11 @@ impl<'a> RuntimeExt<'a> { self.account_id } - pub fn get_code(&self, namespace: Namespace, code_hash: CryptoHash) -> Result, StorageError> { + pub fn get_code( + &self, + namespace: Namespace, + code_hash: CryptoHash, + ) -> Result, StorageError> { get_code(self.trie_update, self.account_id, namespace, Some(code_hash)) } @@ -163,8 +167,11 @@ impl<'a> External for RuntimeExt<'a> { .collect::, _>>() .map_err(wrap_storage_error)?; for (namespace, key) in namespace_data_keys { - self.trie_update - .remove(TrieKey::ContractData { account_id: self.account_id.clone(), namespace, key }); + self.trie_update.remove(TrieKey::ContractData { + account_id: self.account_id.clone(), + namespace, + key, + }); } Ok(()) } diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 51c56e6523b..7dc93d3f448 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -2305,6 +2305,7 @@ mod tests { let gas = 2 * 10u64.pow(14); let gas_price = GAS_PRICE / 10; let actions = vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"world".to_vec(), gas, @@ -2374,6 +2375,7 @@ mod tests { let gas = 1_000_000; let gas_price = GAS_PRICE / 10; let actions = vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"world".to_vec(), gas, diff --git a/runtime/runtime/src/state_viewer/mod.rs b/runtime/runtime/src/state_viewer/mod.rs index 0e75fad2ea0..0ad1a52109f 100644 --- a/runtime/runtime/src/state_viewer/mod.rs +++ b/runtime/runtime/src/state_viewer/mod.rs @@ -122,9 +122,14 @@ impl TrieViewer { ) -> Result { match get_account(state_update, account_id)? { Some(account) => { - let code_len = get_code(state_update, account_id, Namespace::default(), Some(account.code_hash()))? - .map(|c| c.code().len() as u64) - .unwrap_or_default(); + let code_len = get_code( + state_update, + account_id, + Namespace::default(), + Some(account.code_hash()), + )? + .map(|c| c.code().len() as u64) + .unwrap_or_default(); if let Some(limit) = self.state_size_limit { if account.storage_usage().saturating_sub(code_len) > limit { return Err(errors::ViewStateError::AccountStateTooLarge { @@ -142,10 +147,7 @@ impl TrieViewer { let mut values = vec![]; // TODO: Namespace state viewing - let query = trie_key_parsers::get_raw_prefix_for_contract_data( - account_id, - prefix, - ); + let query = trie_key_parsers::get_raw_prefix_for_contract_data(account_id, prefix); let acc_sep_len = query.len() - prefix.len(); let mut iter = state_update.trie().iter()?; iter.remember_visited_nodes(include_proof); @@ -167,6 +169,7 @@ impl TrieViewer { mut state_update: TrieUpdate, view_state: ViewApplyState, contract_id: &AccountId, + namespace: &Namespace, method_name: &str, args: &[u8], logs: &mut Vec, @@ -222,6 +225,7 @@ impl TrieViewer { actions: vec![], }; let function_call = FunctionCallAction { + namespace: namespace.clone(), method_name: method_name.to_string(), args: args.to_vec(), gas: self.max_gas_burnt_view, diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 08c5439d438..a08114d1bd2 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -933,6 +933,7 @@ mod tests { bob_account(), &*signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 200, @@ -1095,6 +1096,7 @@ mod tests { bob_account(), &*signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 300, @@ -1228,6 +1230,7 @@ mod tests { &*signer, vec![ Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, @@ -1321,6 +1324,7 @@ mod tests { eve_dot_alice_account(), &*signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, @@ -1369,6 +1373,7 @@ mod tests { bob_account(), &*signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, @@ -1414,6 +1419,7 @@ mod tests { bob_account(), &*signer, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, @@ -1573,6 +1579,7 @@ mod tests { validate_actions( &limit_config, &[Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, @@ -1592,12 +1599,14 @@ mod tests { &limit_config, &[ Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, deposit: 0, }), Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 150, @@ -1620,12 +1629,14 @@ mod tests { &limit_config, &[ Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: u64::max_value() / 2 + 1, deposit: 0, }), Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: u64::max_value() / 2 + 1, @@ -1716,6 +1727,7 @@ mod tests { validate_action( &VMLimitConfig::test(), &Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "hello".to_string(), args: b"abc".to_vec(), gas: 100, @@ -1732,6 +1744,7 @@ mod tests { validate_action( &VMLimitConfig::test(), &Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "new".to_string(), args: vec![], gas: 0, diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs index 9d6a25b9a02..6ae8bb7c98d 100644 --- a/runtime/runtime/tests/test_async_calls.rs +++ b/runtime/runtime/tests/test_async_calls.rs @@ -33,6 +33,7 @@ fn test_simple_func_call() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "sum_n".to_string(), args: 10u64.to_le_bytes().to_vec(), gas: GAS_1, @@ -79,6 +80,7 @@ fn test_single_promise_no_callback() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -145,6 +147,7 @@ fn test_single_promise_with_callback() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -229,6 +232,7 @@ fn test_two_promises_no_callbacks() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -323,6 +327,7 @@ fn test_two_promises_with_two_callbacks() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -414,6 +419,7 @@ fn test_single_promise_no_callback_batch() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -486,6 +492,7 @@ fn test_single_promise_with_callback_batch() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -560,6 +567,7 @@ fn test_simple_transfer() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -627,6 +635,7 @@ fn test_create_account_with_transfer_and_full_key() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -739,6 +748,7 @@ fn test_account_factory() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -885,6 +895,7 @@ fn test_create_account_add_key_call_delete_key_delete_account() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -979,6 +990,7 @@ fn test_transfer_64len_hex() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, @@ -1045,6 +1057,7 @@ fn test_create_transfer_64len_hex_fail() { signer_receiver.account_id, &signer_sender, vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, diff --git a/test-utils/runtime-tester/src/fuzzing.rs b/test-utils/runtime-tester/src/fuzzing.rs index a30dbc31a6a..4d10610ab3b 100644 --- a/test-utils/runtime-tester/src/fuzzing.rs +++ b/test-utils/runtime-tester/src/fuzzing.rs @@ -748,8 +748,9 @@ impl Function { } }; Ok(FunctionCallAction { + namespace: Namespace::default(), // TODO: fuzz namespaces? method_name: method_name.to_string(), - args: args, + args, gas: GAS_1, deposit: 0, }) diff --git a/tools/state-viewer/src/contract_accounts.rs b/tools/state-viewer/src/contract_accounts.rs index 2c4d385d0e2..5dac1ebbda5 100644 --- a/tools/state-viewer/src/contract_accounts.rs +++ b/tools/state-viewer/src/contract_accounts.rs @@ -569,6 +569,7 @@ mod tests { "alice.near", "bob.near", vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "foo".to_owned(), args: vec![], gas: 1000, From 4d6f4b3577d05c94abb24c1ce07a82758165c398 Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 24 May 2023 11:49:53 +0900 Subject: [PATCH 6/9] remove routing table --- Cargo.lock | 115 ++++----- chain/rosetta-rpc/src/adapters/mod.rs | 4 - .../validated_operations/deploy_contract.rs | 6 +- chain/rosetta-rpc/src/models.rs | 5 +- chain/rosetta-rpc/src/types.rs | 31 +-- core/primitives-core/src/account.rs | 17 -- core/primitives-core/src/lib.rs | 1 - core/primitives-core/src/routing_table.rs | 92 -------- core/primitives/src/lib.rs | 1 - core/primitives/src/test_utils.rs | 3 - core/primitives/src/transaction.rs | 4 - core/primitives/src/views.rs | 8 +- .../src/tests/client/benchmarks.rs | 2 - .../src/tests/client/cold_storage.rs | 2 - .../client/features/chunk_nodes_cache.rs | 1 + .../tests/client/features/delegate_action.rs | 3 - .../features/increase_deployment_cost.rs | 2 - .../limit_contract_functions_number.rs | 2 + .../features/lower_storage_key_limit.rs | 1 + .../src/tests/client/features/wasmer2.rs | 1 + .../src/tests/client/process_blocks.rs | 223 +++++++++++++++++- .../src/tests/client/sharding_upgrade.rs | 2 - .../src/tests/runtime/deployment.rs | 2 - .../src/tests/standard_cases/mod.rs | 2 - integration-tests/src/user/mod.rs | 2 - runtime/near-vm-errors/src/lib.rs | 8 + runtime/near-vm-logic/src/receipt_manager.rs | 2 - .../src/action_costs.rs | 2 - runtime/runtime-params-estimator/src/lib.rs | 2 - runtime/runtime-params-estimator/src/utils.rs | 2 - runtime/runtime/src/actions.rs | 20 +- runtime/runtime/src/lib.rs | 2 - runtime/runtime/src/metrics.rs | 9 + runtime/runtime/src/verifier.rs | 2 - runtime/runtime/tests/test_async_calls.rs | 5 +- test-utils/runtime-tester/src/fuzzing.rs | 2 - tools/state-viewer/src/contract_accounts.rs | 2 - tools/state-viewer/src/state_dump.rs | 2 - 38 files changed, 298 insertions(+), 294 deletions(-) delete mode 100644 core/primitives-core/src/routing_table.rs diff --git a/Cargo.lock b/Cargo.lock index e681d915564..35d3f2132d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,14 +82,14 @@ dependencies = [ "http", "httparse", "httpdate", - "itoa 1.0.2", + "itoa", "language-tags", "local-channel", "mime", "percent-encoding", "pin-project-lite", "rand 0.8.5", - "sha1 0.10.4", + "sha1 0.10.5", "smallvec", "tracing", "zstd", @@ -212,7 +212,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "itoa 1.0.2", + "itoa", "language-tags", "log", "mime", @@ -453,7 +453,7 @@ dependencies = [ "futures-util", "h2", "http", - "itoa 1.0.2", + "itoa", "log", "mime", "openssl", @@ -843,18 +843,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" version = "3.12.0" @@ -1522,13 +1510,12 @@ dependencies = [ [[package]] name = "csv" -version = "1.1.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" dependencies = [ - "bstr", "csv-core", - "itoa 0.4.8", + "itoa", "ryu", "serde", ] @@ -1668,9 +1655,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.2", "crypto-common", @@ -1709,12 +1696,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - [[package]] name = "dynasm" version = "1.2.3" @@ -2335,7 +2316,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -2346,7 +2327,7 @@ checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" dependencies = [ "bytes", "fnv", - "itoa 1.0.2", + "itoa", ] [[package]] @@ -2387,7 +2368,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.2", + "itoa", "pin-project-lite", "socket2", "tokio", @@ -2603,12 +2584,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.2" @@ -2885,7 +2860,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b48670c893079d3c2ed79114e3644b7004df1c361a4e0ad52e2e6940d07c3d" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -3149,7 +3124,7 @@ dependencies = [ "enum-map", "insta", "itertools", - "itoa 1.0.2", + "itoa", "lru", "near-cache", "near-chain-configs", @@ -3186,7 +3161,7 @@ dependencies = [ "once_cell", "serde", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "smart-default", "tracing", ] @@ -3335,7 +3310,7 @@ dependencies = [ "secp256k1", "serde", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "subtle", "tempfile", "thiserror", @@ -3582,7 +3557,7 @@ dependencies = [ "secp256k1", "serde", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "strum", "thiserror", "tokio", @@ -3653,7 +3628,7 @@ dependencies = [ "atty", "bencher", "clap 3.1.18", - "itoa 1.0.2", + "itoa", "near-crypto", "near-primitives-core", "once_cell", @@ -3781,7 +3756,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "sha2 0.10.2", + "sha2 0.10.6", "strum", "thiserror", ] @@ -3889,7 +3864,7 @@ dependencies = [ "fs2", "insta", "itertools", - "itoa 1.0.2", + "itoa", "lru", "near-crypto", "near-o11y", @@ -4083,7 +4058,7 @@ dependencies = [ "ripemd", "serde", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "sha3", "tracing", "zeropool-bn", @@ -4354,7 +4329,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "tempfile", "testlib", "thiserror", @@ -5234,15 +5209,15 @@ dependencies = [ [[package]] name = "redis" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80b5f38d7f5a020856a0e16e40a9cfabf88ae8f0e4c2dcd8a3114c1e470852" +checksum = "152f3863635cbb76b73bc247845781098302c6c9ad2060e1a9a7de56840346b6" dependencies = [ "async-trait", "combine", - "dtoa", - "itoa 0.4.8", + "itoa", "percent-encoding", + "ryu", "sha1 0.6.1", "url", ] @@ -5422,7 +5397,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -5592,7 +5567,7 @@ dependencies = [ "serde", "serde-xml-rs", "serde_derive", - "sha2 0.10.2", + "sha2 0.10.6", "thiserror", "time 0.3.9", "tokio", @@ -5714,9 +5689,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "rand 0.8.5", "secp256k1-sys", @@ -5724,9 +5699,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7058dc8eaf3f2810d7828680320acda0b25a288f6d288e19278e249bbf74226b" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" dependencies = [ "cc", ] @@ -5855,7 +5830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "indexmap", - "itoa 1.0.2", + "itoa", "ryu", "serde", ] @@ -5878,7 +5853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.2", + "itoa", "ryu", "serde", ] @@ -5890,7 +5865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" dependencies = [ "indexmap", - "itoa 1.0.2", + "itoa", "ryu", "serde", "unsafe-libyaml", @@ -5907,13 +5882,13 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -5937,22 +5912,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", ] [[package]] name = "sha3" -version = "0.10.1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", "keccak", ] @@ -6428,7 +6403,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" dependencies = [ - "itoa 1.0.2", + "itoa", "libc", "num_threads", "serde", diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index bbcc955beaa..9ac23a44b67 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -371,7 +371,6 @@ impl From for Vec { account: receiver_account_identifier.clone(), code: action.code, namespace: action.namespace, - routing_table: action.routing_table, } .into_related_operation( crate::models::OperationIdentifier::new(&operations), @@ -670,7 +669,6 @@ impl TryFrom> for NearActions { near_primitives::transaction::DeployContractAction { code: deploy_contract_operation.code, namespace: deploy_contract_operation.namespace, - routing_table: deploy_contract_operation.routing_table, } .into(), ) @@ -834,7 +832,6 @@ mod tests { use near_crypto::{KeyType, SecretKey}; use near_primitives::delegate_action::{DelegateAction, SignedDelegateAction}; use near_primitives::namespace::Namespace; - use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config::RuntimeConfig; use near_primitives::transaction::{Action, TransferAction}; use near_primitives::views::RuntimeConfigView; @@ -1003,7 +1000,6 @@ mod tests { let deploy_contract_actions = vec![near_primitives::transaction::DeployContractAction { code: b"binary-data".to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), } .into()]; let function_call_without_balance_actions = diff --git a/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs b/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs index 95ec40876fb..a925a1c31e1 100644 --- a/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs +++ b/chain/rosetta-rpc/src/adapters/validated_operations/deploy_contract.rs @@ -1,4 +1,4 @@ -use near_primitives::{namespace::Namespace, routing_table::RoutingTable}; +use near_primitives::{namespace::Namespace}; use super::ValidatedOperation; @@ -6,7 +6,6 @@ pub(crate) struct DeployContractOperation { pub(crate) account: crate::models::AccountIdentifier, pub(crate) code: Vec, pub(crate) namespace: Namespace, - pub(crate) routing_table: RoutingTable, } impl ValidatedOperation for DeployContractOperation { @@ -48,8 +47,7 @@ impl TryFrom for DeployContractOperation { let metadata = operation.metadata.ok_or_else(required_fields_error)?; let code = metadata.code.ok_or_else(required_fields_error)?.into_inner(); let namespace = metadata.namespace.ok_or_else(required_fields_error)?.into(); - let routing_table = metadata.routing_table.ok_or_else(required_fields_error)?.into(); - Ok(Self { account: operation.account, code, namespace, routing_table }) + Ok(Self { account: operation.account, code, namespace }) } } diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index ee287071d64..71974503ae7 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -1,11 +1,10 @@ use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use paperclip::actix::{api_v2_errors, Apiv2Schema}; use near_primitives::hash::CryptoHash; use near_primitives::types::{BlockHeight, Nonce}; -use crate::types::{TypedNamespace, TypedRoutingTable}; +use crate::types::TypedNamespace; use crate::utils::{BlobInHexString, BorshInHexString}; /// An AccountBalanceRequest is utilized to make a balance request on the @@ -783,8 +782,6 @@ pub(crate) struct OperationMetadata { pub code: Option>>, #[serde(skip_serializing_if = "Option::is_none")] pub namespace: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub routing_table: Option, /// Has to be specified for FUNCTION_CALL operation #[serde(skip_serializing_if = "Option::is_none")] pub method_name: Option, diff --git a/chain/rosetta-rpc/src/types.rs b/chain/rosetta-rpc/src/types.rs index beeff7fbd93..05c8e8e2b52 100644 --- a/chain/rosetta-rpc/src/types.rs +++ b/chain/rosetta-rpc/src/types.rs @@ -24,7 +24,7 @@ impl fmt::Debug for AccountId { } } -use near_primitives::{namespace::Namespace, routing_table::RoutingTable}; +use near_primitives::namespace::Namespace; use paperclip::v2::{models::DataType, schema::TypedData}; use serde::{Deserialize, Serialize}; impl TypedData for AccountId { @@ -61,32 +61,3 @@ impl TypedData for TypedNamespace { DataType::String } } - -#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)] -pub(crate) struct TypedRoutingTable(RoutingTable); - -impl From for TypedRoutingTable { - fn from(value: RoutingTable) -> Self { - Self(value) - } -} - -impl From for RoutingTable { - fn from(value: TypedRoutingTable) -> Self { - value.0 - } -} - -impl Deref for TypedRoutingTable { - type Target = RoutingTable; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl TypedData for TypedRoutingTable { - fn data_type() -> DataType { - DataType::Object - } -} diff --git a/core/primitives-core/src/account.rs b/core/primitives-core/src/account.rs index 65aa862fc5f..dd17fdd6120 100644 --- a/core/primitives-core/src/account.rs +++ b/core/primitives-core/src/account.rs @@ -1,6 +1,5 @@ use crate::hash::CryptoHash; use crate::namespace::Namespace; -use crate::routing_table::RoutingTable; use crate::serialize::dec_format; use crate::types::{Balance, Nonce, StorageUsage}; use borsh::{BorshDeserialize, BorshSerialize}; @@ -40,7 +39,6 @@ pub struct Account { locked: Balance, /// Hash of the code stored in the storage for this account. code_hashes: HashMap, - routing_table: RoutingTable, /// Storage used by the given account, includes account id, this struct, access keys and other data. storage_usage: StorageUsage, /// Version of Account in re migrations and similar @@ -63,7 +61,6 @@ impl Account { amount, locked, code_hashes: [(Namespace::default(), code_hash)].into_iter().collect(), - routing_table: RoutingTable::new(), storage_usage, version: AccountVersion::V1, } @@ -89,16 +86,6 @@ impl Account { &self.code_hashes } - #[inline] - pub fn routing_table(&self) -> &RoutingTable { - &self.routing_table - } - - #[inline] - pub fn routing_table_mut(&mut self) -> &mut RoutingTable { - &mut self.routing_table - } - #[inline] pub fn storage_usage(&self) -> StorageUsage { self.storage_usage @@ -144,7 +131,6 @@ struct LegacyAccount { amount: Balance, locked: Balance, code_hashes: HashMap, - routing_table: RoutingTable, storage_usage: StorageUsage, } @@ -157,7 +143,6 @@ impl BorshDeserialize for Account { amount: deserialized_account.amount, locked: deserialized_account.locked, code_hashes: deserialized_account.code_hashes, - routing_table: deserialized_account.routing_table, storage_usage: deserialized_account.storage_usage, version: AccountVersion::V1, }) @@ -171,7 +156,6 @@ impl BorshSerialize for Account { amount: self.amount, locked: self.locked, code_hashes: self.code_hashes.clone(), - routing_table: self.routing_table.clone(), storage_usage: self.storage_usage, } .serialize(writer), @@ -291,7 +275,6 @@ mod tests { amount: 100, locked: 200, code_hashes: HashMap::default(), - routing_table: RoutingTable::default(), storage_usage: 300, }; let mut old_bytes = &old_account.try_to_vec().unwrap()[..]; diff --git a/core/primitives-core/src/lib.rs b/core/primitives-core/src/lib.rs index e085a922cbc..24ed81715f5 100644 --- a/core/primitives-core/src/lib.rs +++ b/core/primitives-core/src/lib.rs @@ -8,7 +8,6 @@ pub mod hash; pub mod namespace; pub mod parameter; pub mod profile; -pub mod routing_table; pub mod runtime; pub mod serialize; pub mod types; diff --git a/core/primitives-core/src/routing_table.rs b/core/primitives-core/src/routing_table.rs deleted file mode 100644 index d6e2bb6efed..00000000000 --- a/core/primitives-core/src/routing_table.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::collections::HashMap; - -use borsh::{BorshDeserialize, BorshSerialize}; - -use crate::namespace::Namespace; - -#[derive( - BorshSerialize, - BorshDeserialize, - Clone, - Debug, - Default, - PartialEq, - Eq, - serde::Serialize, - serde::Deserialize, -)] -#[serde(transparent)] -pub struct RoutingTable(HashMap); - -impl RoutingTable { - pub fn new() -> Self { - Default::default() - } - - pub fn add( - &mut self, - incoming_method_name: String, - target_namespace: Namespace, - target_method_name: String, - ) { - self.0.insert(incoming_method_name, (target_namespace, target_method_name)); - } - - pub fn merge(&mut self, other: RoutingTable) { - self.0.extend(other.0); - } - - pub fn resolve_method(&self, incoming_method_name: &str) -> Option<&(Namespace, String)> { - self.0.get(incoming_method_name) - } - - pub fn inverse_resolve_method( - &self, - target_namespace: &Namespace, - target_method_name: &str, - ) -> Option<&String> { - self.0 - .iter() - .find(|(_, (namespace, method_name))| { - namespace == target_namespace && method_name == target_method_name - }) - .map(|(incoming_method_name, _)| incoming_method_name) - } -} - -#[cfg(test)] -mod tests { - use crate::namespace::Namespace; - - use super::RoutingTable; - - #[test] - fn routing_table_merge() { - let mut table_a = RoutingTable::new(); - let mut table_b = RoutingTable::new(); - - let namespace_a: Namespace = "namespace_a".into(); - let namespace_b: Namespace = "namespace_b".into(); - - let method_a = "method_a".to_string(); - let method_b = "method_b".to_string(); - let method_c = "method_c".to_string(); - - table_a.add(method_a.clone(), namespace_a.clone(), method_a.clone()); - table_a.add(method_b.clone(), namespace_a.clone(), method_b.clone()); - - table_b.add(method_b.clone(), namespace_b.clone(), method_b.clone()); - table_b.add(method_c.clone(), namespace_b.clone(), method_c.clone()); - - table_a.merge(table_b); - - assert_eq!( - table_a.resolve_method(&method_a), - Some(&(namespace_a.clone(), method_a.clone())), - ); - assert_eq!( - table_a.resolve_method("method_b"), - Some(&(namespace_b.clone(), method_b.clone())), - ); - } -} diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index d1f0246c9ca..be7696dafd7 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -6,7 +6,6 @@ pub use near_primitives_core::hash; pub use near_primitives_core::namespace; pub use near_primitives_core::num_rational; pub use near_primitives_core::profile; -pub use near_primitives_core::routing_table; pub use near_primitives_core::serialize; pub mod block; diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index 0f672720da6..3d8bb6682fe 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use near_crypto::{EmptySigner, InMemorySigner, KeyType, PublicKey, SecretKey, Signature, Signer}; use near_primitives_core::namespace::Namespace; -use near_primitives_core::routing_table::RoutingTable; use near_primitives_core::types::ProtocolVersion; use crate::account::{AccessKey, AccessKeyPermission, Account}; @@ -53,7 +52,6 @@ impl Transaction { self.actions.push(Action::DeployContract(DeployContractAction { code, namespace: Namespace::default(), - routing_table: RoutingTable::default(), })); self } @@ -208,7 +206,6 @@ impl SignedTransaction { Action::DeployContract(DeployContractAction { code, namespace: Namespace::default(), - routing_table: RoutingTable::default(), }), ], block_hash, diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index 54b6db2ab08..94cc48620a2 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -10,7 +10,6 @@ use near_crypto::{PublicKey, Signature}; use near_o11y::pretty; use near_primitives_core::namespace::Namespace; use near_primitives_core::profile::{ProfileDataV2, ProfileDataV3}; -use near_primitives_core::routing_table::RoutingTable; use near_primitives_core::types::Compute; use std::borrow::Borrow; use std::fmt; @@ -125,8 +124,6 @@ pub struct DeployContractAction { pub code: Vec, #[serde(default)] pub namespace: Namespace, - #[serde(default)] - pub routing_table: RoutingTable, } impl From for Action { @@ -576,7 +573,6 @@ mod tests { Action::DeployContract(DeployContractAction { code: vec![1, 2, 3], namespace: Namespace::default(), - routing_table: RoutingTable::default(), }), Action::FunctionCall(FunctionCallAction { namespace: Namespace::default(), diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index 06c6e00686a..674f7e24d77 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -42,7 +42,6 @@ use near_crypto::{PublicKey, Signature}; use near_o11y::pretty; use near_primitives_core::config::{ActionCosts, ExtCosts, ParameterCost, VMConfig}; use near_primitives_core::namespace::Namespace; -use near_primitives_core::routing_table::RoutingTable; use near_primitives_core::runtime::fees::Fee; use num_rational::Rational32; use std::collections::HashMap; @@ -1113,8 +1112,6 @@ pub enum ActionView { code: Vec, #[serde(default)] namespace: Namespace, - #[serde(default)] - routing_table: RoutingTable, }, FunctionCall { namespace: Namespace, @@ -1159,7 +1156,6 @@ impl From for ActionView { ActionView::DeployContract { code, namespace: action.namespace, - routing_table: action.routing_table, } } Action::FunctionCall(action) => ActionView::FunctionCall { @@ -1195,8 +1191,8 @@ impl TryFrom for Action { fn try_from(action_view: ActionView) -> Result { Ok(match action_view { ActionView::CreateAccount => Action::CreateAccount(CreateAccountAction {}), - ActionView::DeployContract { code, namespace, routing_table } => { - Action::DeployContract(DeployContractAction { code, namespace, routing_table }) + ActionView::DeployContract { code, namespace } => { + Action::DeployContract(DeployContractAction { code, namespace }) } ActionView::FunctionCall { namespace, method_name, args, gas, deposit } => { Action::FunctionCall(FunctionCallAction { diff --git a/integration-tests/src/tests/client/benchmarks.rs b/integration-tests/src/tests/client/benchmarks.rs index 5f6e33e68d7..7009731f6bf 100644 --- a/integration-tests/src/tests/client/benchmarks.rs +++ b/integration-tests/src/tests/client/benchmarks.rs @@ -12,7 +12,6 @@ use near_client::test_utils::{create_chunk_on_height, TestEnv}; use near_crypto::{InMemorySigner, KeyType}; use near_primitives::{ namespace::Namespace, - routing_table::RoutingTable, transaction::{Action, DeployContractAction, SignedTransaction}, }; use nearcore::config::GenesisExt; @@ -51,7 +50,6 @@ fn benchmark_large_chunk_production_time() { vec![Action::DeployContract(DeployContractAction { code: vec![92; tx_size], namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], last_block_hash, ); diff --git a/integration-tests/src/tests/client/cold_storage.rs b/integration-tests/src/tests/client/cold_storage.rs index 30a4e206f1d..a52f3e7a3a3 100644 --- a/integration-tests/src/tests/client/cold_storage.rs +++ b/integration-tests/src/tests/client/cold_storage.rs @@ -9,7 +9,6 @@ use near_o11y::pretty; use near_o11y::testonly::init_test_logger; use near_primitives::block::Tip; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::sharding::ShardChunk; use near_primitives::transaction::{ Action, DeployContractAction, FunctionCallAction, SignedTransaction, @@ -101,7 +100,6 @@ fn test_storage_after_commit_of_cold_update() { vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::rs_contract().to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], last_hash, ); diff --git a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs index 6ca128fb703..7c7e35f5e87 100644 --- a/integration-tests/src/tests/client/features/chunk_nodes_cache.rs +++ b/integration-tests/src/tests/client/features/chunk_nodes_cache.rs @@ -108,6 +108,7 @@ fn compare_node_counts() { deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), near_test_contracts::base_rs_contract(), num_blocks, 1, diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index 137a81d4f21..907af6eb644 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -17,7 +17,6 @@ use near_primitives::errors::{ TxExecutionError, }; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::test_utils::{create_user_test_signer, implicit_test_account}; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, @@ -438,7 +437,6 @@ fn meta_tx_deploy() { let actions = vec![Action::DeployContract(DeployContractAction { code, namespace: Namespace::default(), - routing_table: RoutingTable::default(), })]; check_meta_tx_no_fn_call(&node, actions, tx_cost, 0, sender, relayer, receiver); } @@ -844,7 +842,6 @@ fn meta_tx_create_and_use_implicit_account() { Action::DeployContract(DeployContractAction { code: ft_contract().to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), }), ]; diff --git a/integration-tests/src/tests/client/features/increase_deployment_cost.rs b/integration-tests/src/tests/client/features/increase_deployment_cost.rs index 8d1b7dd6594..69083119c1f 100644 --- a/integration-tests/src/tests/client/features/increase_deployment_cost.rs +++ b/integration-tests/src/tests/client/features/increase_deployment_cost.rs @@ -6,7 +6,6 @@ use near_crypto::{InMemorySigner, KeyType}; use near_epoch_manager::shard_tracker::TrackedConfig; use near_primitives::config::VMConfig; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::transaction::{Action, DeployContractAction}; use near_primitives::version::ProtocolFeature; @@ -55,7 +54,6 @@ fn test_deploy_cost_increased() { let actions = vec![Action::DeployContract(DeployContractAction { code: test_contract, namespace: Namespace::default(), - routing_table: RoutingTable::default(), })]; let tx = env.tx_from_actions(actions.clone(), &signer, signer.account_id.clone()); diff --git a/integration-tests/src/tests/client/features/limit_contract_functions_number.rs b/integration-tests/src/tests/client/features/limit_contract_functions_number.rs index 321d3b28391..684dec2bce9 100644 --- a/integration-tests/src/tests/client/features/limit_contract_functions_number.rs +++ b/integration-tests/src/tests/client/features/limit_contract_functions_number.rs @@ -8,6 +8,7 @@ use near_primitives::errors::{ActionErrorKind, TxExecutionError}; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::version::ProtocolFeature; use near_primitives::views::FinalExecutionStatus; +use near_primitives_core::namespace::Namespace; use near_store::test_utils::create_test_store; use near_vm_errors::{CompilationError, FunctionCallErrorSer, PrepareError}; use nearcore::config::GenesisExt; @@ -44,6 +45,7 @@ fn verify_contract_limits_upgrade( deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), &near_test_contracts::LargeContract { functions: function_limit + 1, locals_per_function: local_limit + 1, diff --git a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs index 0bd3d7f2d31..f48b6dc69a4 100644 --- a/integration-tests/src/tests/client/features/lower_storage_key_limit.rs +++ b/integration-tests/src/tests/client/features/lower_storage_key_limit.rs @@ -60,6 +60,7 @@ fn protocol_upgrade() { deploy_test_contract_with_protocol_version( &mut env, "test0".parse().unwrap(), + Namespace::default(), near_test_contracts::base_rs_contract(), epoch_length, 1, diff --git a/integration-tests/src/tests/client/features/wasmer2.rs b/integration-tests/src/tests/client/features/wasmer2.rs index 1d456fbfa3b..ccbe54d2f5f 100644 --- a/integration-tests/src/tests/client/features/wasmer2.rs +++ b/integration-tests/src/tests/client/features/wasmer2.rs @@ -33,6 +33,7 @@ fn test_wasmer2_upgrade() { deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), near_test_contracts::rs_contract(), epoch_length, 1, diff --git a/integration-tests/src/tests/client/process_blocks.rs b/integration-tests/src/tests/client/process_blocks.rs index 7f4f42b46c6..a342513baeb 100644 --- a/integration-tests/src/tests/client/process_blocks.rs +++ b/integration-tests/src/tests/client/process_blocks.rs @@ -51,7 +51,6 @@ use near_primitives::errors::TxExecutionError; use near_primitives::hash::{hash, CryptoHash}; use near_primitives::merkle::{verify_hash, PartialMerkleTree}; use near_primitives::receipt::DelayedReceiptIndices; -use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config::RuntimeConfig; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::shard_layout::{get_block_shard_uid, ShardUId}; @@ -144,6 +143,7 @@ pub(crate) fn produce_blocks_from_height( pub(crate) fn deploy_test_contract_with_protocol_version( env: &mut TestEnv, account_id: AccountId, + namespace: Namespace, wasm_code: &[u8], epoch_length: u64, height: BlockHeight, @@ -158,11 +158,7 @@ pub(crate) fn deploy_test_contract_with_protocol_version( account_id.clone(), account_id, &signer, - vec![Action::DeployContract(DeployContractAction { - code: wasm_code.to_vec(), - namespace: Namespace::default(), - routing_table: RoutingTable::default(), - })], + vec![Action::DeployContract(DeployContractAction { code: wasm_code.to_vec(), namespace })], *block.hash(), ); env.clients[0].process_tx(tx, false, false); @@ -172,6 +168,7 @@ pub(crate) fn deploy_test_contract_with_protocol_version( pub(crate) fn deploy_test_contract( env: &mut TestEnv, account_id: AccountId, + namespace: Namespace, wasm_code: &[u8], epoch_length: u64, height: BlockHeight, @@ -179,6 +176,7 @@ pub(crate) fn deploy_test_contract( deploy_test_contract_with_protocol_version( env, account_id, + namespace, wasm_code, epoch_length, height, @@ -217,7 +215,6 @@ pub(crate) fn prepare_env_with_congestion( vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::base_rs_contract().to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], *genesis_block.hash(), ); @@ -2373,7 +2370,6 @@ fn test_validate_chunk_extra() { vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::rs_contract().to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], *genesis_block.hash(), ); @@ -2836,7 +2832,14 @@ fn test_execution_metadata() { .runtime_adapters(create_nightshade_runtimes(&genesis, 1)) .build(); - deploy_test_contract(&mut env, "test0".parse().unwrap(), &wasm_code, epoch_length, 1); + deploy_test_contract( + &mut env, + "test0".parse().unwrap(), + Namespace::default(), + &wasm_code, + epoch_length, + 1, + ); env }; @@ -2895,6 +2898,102 @@ fn test_execution_metadata() { assert_eq!(expected_receipt_cost, actual_receipt_cost) } +#[test] +fn test_execution_metadata_namespaced() { + // Prepare TestEnv with a very simple WASM contract. + let wasm_code = wat::parse_str( + r#" +(module + (import "env" "block_index" (func $block_index (result i64))) + (func (export "main") + (call $block_index) + drop + ) +)"#, + ) + .unwrap(); + + let namespace: Namespace = "namespace".into(); + + let mut env = { + let epoch_length = 5; + let mut genesis = + Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1); + genesis.config.epoch_length = epoch_length; + let chain_genesis = ChainGenesis::new(&genesis); + let mut env = TestEnv::builder(chain_genesis) + .runtime_adapters(create_nightshade_runtimes(&genesis, 1)) + .build(); + + deploy_test_contract( + &mut env, + "test0".parse().unwrap(), + namespace.clone(), + &wasm_code, + epoch_length, + 1, + ); + env + }; + + // Call the contract and get the execution outcome. + // TODO: new version of call_main that accepts namespace + let execution_outcome = env.call_main(&"test0".parse().unwrap()); + + dbg!(&execution_outcome); + + // Now, let's assert that we get the cost breakdown we expect. + let config = RuntimeConfigStore::test().get_config(PROTOCOL_VERSION).clone(); + + // Total costs for creating a function call receipt. + let expected_receipt_cost = config.fees.fee(ActionCosts::new_action_receipt).execution + + config.fees.fee(ActionCosts::function_call_base).exec_fee() + + config.fees.fee(ActionCosts::function_call_byte).exec_fee() * "main".len() as u64; + + // Profile for what's happening *inside* wasm vm during function call. + let expected_profile = serde_json::json!([ + // Inside the contract, we called one host function. + { + "cost_category": "WASM_HOST_COST", + "cost": "BASE", + "gas_used": config.wasm_config.ext_costs.gas_cost(ExtCosts::base).to_string() + }, + // We include compilation costs into running the function. + { + "cost_category": "WASM_HOST_COST", + "cost": "CONTRACT_LOADING_BASE", + "gas_used": config.wasm_config.ext_costs.gas_cost(ExtCosts::contract_loading_base).to_string() + }, + { + "cost_category": "WASM_HOST_COST", + "cost": "CONTRACT_LOADING_BYTES", + "gas_used": "18423750" + }, + // We spend two wasm instructions (call & drop). + { + "cost_category": "WASM_HOST_COST", + "cost": "WASM_INSTRUCTION", + "gas_used": (config.wasm_config.regular_op_cost as u64 * 2).to_string() + } + ]); + let outcome = &execution_outcome.receipts_outcome[0].outcome; + let metadata = &outcome.metadata; + + let actual_profile = serde_json::to_value(&metadata.gas_profile).unwrap(); + assert_eq!(expected_profile, actual_profile); + + let actual_receipt_cost = outcome.gas_burnt + - metadata + .gas_profile + .clone() + .unwrap_or_default() + .into_iter() + .map(|it| it.gas_used) + .sum::(); + + assert_eq!(expected_receipt_cost, actual_receipt_cost) +} + #[test] fn test_epoch_protocol_version_change() { init_test_logger(); @@ -3445,6 +3544,7 @@ fn test_validator_stake_host_function() { let block_height = deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), near_test_contracts::rs_contract(), epoch_length, 1, @@ -3561,6 +3661,7 @@ mod contract_precompilation_tests { let height = deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), &wasm_code, EPOCH_LENGTH, start_height, @@ -3633,6 +3734,107 @@ mod contract_precompilation_tests { .unwrap(); } + #[test] + #[cfg_attr(all(target_arch = "aarch64", target_vendor = "apple"), ignore)] + fn test_sync_and_call_cached_contract_namespaced() { + let num_clients = 2; + let stores: Vec = (0..num_clients).map(|_| create_test_store()).collect(); + let mut genesis = + Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1); + genesis.config.epoch_length = EPOCH_LENGTH; + let runtime_adapters = stores + .iter() + .map(|store| { + nearcore::NightshadeRuntime::test(Path::new("../../../.."), store.clone(), &genesis) + as Arc + }) + .collect(); + + let mut env = TestEnv::builder(ChainGenesis::test()) + .clients_count(num_clients) + .runtime_adapters(runtime_adapters) + .build(); + let start_height = 1; + + let namespace: Namespace = "namespace".into(); + // Process test contract deployment on the first client. + let wasm_code = near_test_contracts::rs_contract().to_vec(); + let height = deploy_test_contract( + &mut env, + "test0".parse().unwrap(), + namespace.clone(), + &wasm_code, + EPOCH_LENGTH, + start_height, + ); + + // Perform state sync for the second client. + state_sync_on_height(&mut env, height - 1); + + // Check existence of contract in both caches. + let mut caches: Vec = + stores.iter().map(StoreCompiledContractCache::new).collect(); + let contract_code = ContractCode::new(wasm_code.clone(), None); + let vm_kind = VMKind::for_protocol_version(PROTOCOL_VERSION); + let epoch_id = env.clients[0] + .chain + .get_block_by_height(height - 1) + .unwrap() + .header() + .epoch_id() + .clone(); + let runtime_config = env.get_runtime_config(0, epoch_id); + let key = get_contract_cache_key(&contract_code, vm_kind, &runtime_config.wasm_config); + for i in 0..num_clients { + caches[i] + .get(&key) + .unwrap_or_else(|_| panic!("Failed to get cached result for client {}", i)) + .unwrap_or_else(|| { + panic!("Compilation result should be non-empty for client {}", i) + }); + } + + // Check that contract function may be successfully called on the second client. + // Note that we can't test that behaviour is the same on two clients, because + // compile_module_cached_wasmer0 is cached by contract key via macro. + let block = env.clients[0].chain.get_block_by_height(EPOCH_LENGTH).unwrap(); + let chunk_extra = + env.clients[0].chain.get_chunk_extra(block.hash(), &ShardUId::single_shard()).unwrap(); + let state_root = *chunk_extra.state_root(); + + let viewer = TrieViewer::default(); + // TODO (#7327): set use_flat_storage to true when we implement support for state sync for FlatStorage + let trie = env.clients[1] + .runtime_adapter + .get_trie_for_shard(0, block.header().prev_hash(), state_root, false) + .unwrap(); + let state_update = TrieUpdate::new(trie); + + let mut logs = vec![]; + let view_state = ViewApplyState { + block_height: EPOCH_LENGTH, + prev_block_hash: *block.header().prev_hash(), + block_hash: *block.hash(), + epoch_id: block.header().epoch_id().clone(), + epoch_height: 1, + block_timestamp: block.header().raw_timestamp(), + current_protocol_version: PROTOCOL_VERSION, + cache: Some(Box::new(caches.swap_remove(1))), + }; + viewer + .call_function( + state_update, + view_state, + &"test0".parse().unwrap(), + &namespace, + "log_something", + &[], + &mut logs, + &MockEpochInfoProvider::default(), + ) + .unwrap(); + } + #[test] #[cfg_attr(all(target_arch = "aarch64", target_vendor = "apple"), ignore)] fn test_two_deployments() { @@ -3660,6 +3862,7 @@ mod contract_precompilation_tests { height = deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), &tiny_wasm_code, EPOCH_LENGTH, height, @@ -3673,6 +3876,7 @@ mod contract_precompilation_tests { height = deploy_test_contract( &mut env, "test0".parse().unwrap(), + Namespace::default(), &wasm_code, EPOCH_LENGTH, height, @@ -3741,6 +3945,7 @@ mod contract_precompilation_tests { height = deploy_test_contract( &mut env, "test2".parse().unwrap(), + Namespace::default(), &wasm_code, EPOCH_LENGTH, height, diff --git a/integration-tests/src/tests/client/sharding_upgrade.rs b/integration-tests/src/tests/client/sharding_upgrade.rs index 9669343cbd6..e691e373028 100644 --- a/integration-tests/src/tests/client/sharding_upgrade.rs +++ b/integration-tests/src/tests/client/sharding_upgrade.rs @@ -1,6 +1,5 @@ use borsh::BorshSerialize; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use crate::tests::client::process_blocks::{ create_nightshade_runtimes, set_block_protocol_version, @@ -633,7 +632,6 @@ fn setup_test_env_with_cross_contract_txs( vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::base_rs_contract().to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], genesis_hash, ) diff --git a/integration-tests/src/tests/runtime/deployment.rs b/integration-tests/src/tests/runtime/deployment.rs index 8e4f274ba86..0db335dd3f6 100644 --- a/integration-tests/src/tests/runtime/deployment.rs +++ b/integration-tests/src/tests/runtime/deployment.rs @@ -1,7 +1,6 @@ use crate::node::{Node, RuntimeNode}; use near_chain_configs::Genesis; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::config_store::RuntimeConfigStore; use near_primitives::transaction::{Action, DeployContractAction, SignedTransaction}; use near_primitives::types::AccountId; @@ -35,7 +34,6 @@ fn test_deploy_max_size_contract() { vec![Action::DeployContract(DeployContractAction { code: vec![0u8], namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], block_hash, ); diff --git a/integration-tests/src/tests/standard_cases/mod.rs b/integration-tests/src/tests/standard_cases/mod.rs index 17afa0738c7..12436af7ca2 100644 --- a/integration-tests/src/tests/standard_cases/mod.rs +++ b/integration-tests/src/tests/standard_cases/mod.rs @@ -13,7 +13,6 @@ use near_primitives::errors::{ }; use near_primitives::hash::{hash, CryptoHash}; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::types::{AccountId, Balance, TrieNodesCount}; use near_primitives::views::{ AccessKeyView, AccountView, ExecutionMetadataView, FinalExecutionOutcomeView, @@ -1616,7 +1615,6 @@ pub fn test_chunk_nodes_cache_mode(node: impl Node, runtime_config: RuntimeConfi vec![DeployContractAction { code: test_utils::encode(&[2]), namespace: Namespace::default(), - routing_table: RoutingTable::default(), } .into()], alice_account(), diff --git a/integration-tests/src/user/mod.rs b/integration-tests/src/user/mod.rs index ff3316cb197..01d889c47c8 100644 --- a/integration-tests/src/user/mod.rs +++ b/integration-tests/src/user/mod.rs @@ -9,7 +9,6 @@ use near_primitives::delegate_action::{DelegateAction, NonDelegateAction, Signed use near_primitives::hash::CryptoHash; use near_primitives::namespace::Namespace; use near_primitives::receipt::Receipt; -use near_primitives::routing_table::RoutingTable; use near_primitives::test_utils::create_user_test_signer; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, @@ -135,7 +134,6 @@ pub trait User { vec![Action::DeployContract(DeployContractAction { code, namespace, - routing_table: RoutingTable::default(), })], ) } diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index d29bc2c4a92..8c998748ea4 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -54,6 +54,7 @@ pub enum FunctionCallError { /// A trap happened during execution of a binary WasmTrap(WasmTrap), HostError(HostError), + NamespaceDoesNotExistError(String), } /// Serializable version of `FunctionCallError`. Must never reorder/remove elements, can only @@ -91,6 +92,7 @@ pub enum FunctionCallErrorSer { // error borsh serialized at correct index _EVMError, ExecutionError(String), + NamespaceDoesNotExistError(String), } #[derive(Debug, strum::IntoStaticStr, thiserror::Error)] @@ -343,6 +345,9 @@ impl From for FunctionCallErrorSer { FunctionCallError::WasmTrap(ref _e) => { FunctionCallErrorSer::ExecutionError(outer_err.to_string()) } + FunctionCallError::NamespaceDoesNotExistError(namespace) => { + FunctionCallErrorSer::NamespaceDoesNotExistError(namespace) + } } } } @@ -417,6 +422,9 @@ impl fmt::Display for FunctionCallError { FunctionCallError::HostError(e) => e.fmt(f), FunctionCallError::LinkError { msg } => write!(f, "{}", msg), FunctionCallError::WasmTrap(trap) => write!(f, "WebAssembly trap: {}", trap), + FunctionCallError::NamespaceDoesNotExistError(namespace) => { + write!(f, "Namespace DNE: {}", namespace) + } } } } diff --git a/runtime/near-vm-logic/src/receipt_manager.rs b/runtime/near-vm-logic/src/receipt_manager.rs index 3765aa5072b..4ee53fd4457 100644 --- a/runtime/near-vm-logic/src/receipt_manager.rs +++ b/runtime/near-vm-logic/src/receipt_manager.rs @@ -4,7 +4,6 @@ use crate::External; use near_crypto::PublicKey; use near_primitives::namespace::Namespace; use near_primitives::receipt::DataReceiver; -use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, StakeAction, TransferAction, @@ -162,7 +161,6 @@ impl ReceiptManager { Action::DeployContract(DeployContractAction { code, namespace: Namespace::default(), - routing_table: RoutingTable::default(), }), ); Ok(()) diff --git a/runtime/runtime-params-estimator/src/action_costs.rs b/runtime/runtime-params-estimator/src/action_costs.rs index be800dfbc88..d029b1a5b37 100644 --- a/runtime/runtime-params-estimator/src/action_costs.rs +++ b/runtime/runtime-params-estimator/src/action_costs.rs @@ -15,7 +15,6 @@ use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermi use near_primitives::hash::CryptoHash; use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt}; -use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::Action; use near_primitives::types::{AccountId, Gas}; use std::iter; @@ -618,7 +617,6 @@ fn deploy_action(size: ActionSize) -> Action { Action::DeployContract(near_primitives::transaction::DeployContractAction { code: near_test_contracts::sized_contract(size.deploy_contract() as usize), namespace: Namespace::default(), - routing_table: RoutingTable::default(), }) } diff --git a/runtime/runtime-params-estimator/src/lib.rs b/runtime/runtime-params-estimator/src/lib.rs index 793fcce3386..8f0abe3e47f 100644 --- a/runtime/runtime-params-estimator/src/lib.rs +++ b/runtime/runtime-params-estimator/src/lib.rs @@ -94,7 +94,6 @@ use near_crypto::{KeyType, SecretKey}; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; use near_primitives::contract::ContractCode; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::runtime::fees::RuntimeFeesConfig; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, @@ -651,7 +650,6 @@ fn deploy_contract_cost( let actions = vec![Action::DeployContract(DeployContractAction { code: code_factory(), namespace: Namespace::default(), // TODO: non-default options? - routing_table: RoutingTable::default(), })]; tb.transaction_from_actions(sender, receiver, actions) }; diff --git a/runtime/runtime-params-estimator/src/utils.rs b/runtime/runtime-params-estimator/src/utils.rs index 17a6077432a..ed6dee28715 100644 --- a/runtime/runtime-params-estimator/src/utils.rs +++ b/runtime/runtime-params-estimator/src/utils.rs @@ -3,7 +3,6 @@ use crate::estimator_context::EstimatorContext; use crate::gas_cost::{GasCost, NonNegativeTolerance}; use crate::transaction_builder::TransactionBuilder; use near_primitives::namespace::Namespace; -use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::{ Action, DeployContractAction, FunctionCallAction, SignedTransaction, }; @@ -274,7 +273,6 @@ pub(crate) fn fn_cost_in_contract( let setup = vec![Action::DeployContract(DeployContractAction { code: code.to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })]; let setup_tx = tb.transaction_from_actions(account.clone(), account.clone(), setup); diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index e378ad8e9c4..0e810eac5f6 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -56,12 +56,8 @@ pub(crate) fn execute_function_call( ) -> Result { let account_id = runtime_ext.account_id(); tracing::debug!(target: "runtime", %account_id, "Calling the contract"); - let (resolved_namespace, resolved_method_name) = account - .routing_table() - .resolve_method(&function_call.method_name) - .map(|(namespace, method_name)| (namespace.clone(), method_name.as_str())) - .unwrap_or((Namespace::default(), &function_call.method_name)); // fallback: default namespace, same method name - let code_hash = match account.code_hashes().get(&resolved_namespace) { + + let code_hash = match account.code_hashes().get(&function_call.namespace) { Some(code_hash) => *code_hash, None => { return Ok(VMOutcome::nop_outcome(FunctionCallError::CompilationError( @@ -70,7 +66,7 @@ pub(crate) fn execute_function_call( } }; - let code = match runtime_ext.get_code(resolved_namespace.clone(), code_hash) { + let code = match runtime_ext.get_code(function_call.namespace.clone(), code_hash) { Ok(Some(code)) => code, Ok(None) => { let error = FunctionCallError::CompilationError(CompilationError::CodeDoesNotExist { @@ -125,8 +121,7 @@ pub(crate) fn execute_function_call( } let result = near_vm_runner::run( &code, - // &function_call.method_name, - resolved_method_name, + &function_call.method_name, runtime_ext, context, &config.wasm_config, @@ -254,6 +249,11 @@ pub(crate) fn action_function_call( metrics::FUNCTION_CALL_PROCESSED_HOST_ERRORS .with_label_values(&[inner_err.into()]) .inc(); + }, + FunctionCallError::NamespaceDoesNotExistError(ref namespace) => { + metrics::FUNCTION_CALL_PROCESSED_NAMESPACE_DOES_NOT_EXIST_ERRORS + .with_label_values(&[namespace]) + .inc(); } } // Update action result with the abort error converted to the @@ -504,8 +504,6 @@ pub(crate) fn action_deploy_contract( ); account.set_code_hash_for(deploy_contract.namespace.clone(), *code.hash()); set_code(state_update, account_id.clone(), deploy_contract.namespace.clone(), &code); - // TODO: Accounting for routing table storage costs - account.routing_table_mut().merge(deploy_contract.routing_table.clone()); // Precompile the contract and store result (compiled code or error) in the database. // Note, that contract compilation costs are already accounted in deploy cost using // special logic in estimator (see get_runtime_config() function). diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 7dc93d3f448..94b41388a31 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -1601,7 +1601,6 @@ mod tests { use near_primitives::contract::ContractCode; use near_primitives::hash::hash; use near_primitives::namespace::Namespace; - use near_primitives::routing_table::RoutingTable; use near_primitives::shard_layout::ShardUId; use near_primitives::test_utils::{account_new, MockEpochInfoProvider}; use near_primitives::transaction::DeployContractAction; @@ -2529,7 +2528,6 @@ mod tests { let actions = vec![Action::DeployContract(DeployContractAction { code: wasm_code.clone(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })]; let receipts = vec![create_receipt_with_actions(alice_account(), signer, actions)]; diff --git a/runtime/runtime/src/metrics.rs b/runtime/runtime/src/metrics.rs index 8b2e90b8e4b..7ea4a6bc343 100644 --- a/runtime/runtime/src/metrics.rs +++ b/runtime/runtime/src/metrics.rs @@ -105,3 +105,12 @@ pub static FUNCTION_CALL_PROCESSED_CACHE_ERRORS: Lazy = Lazy::new ) .unwrap() }); +pub static FUNCTION_CALL_PROCESSED_NAMESPACE_DOES_NOT_EXIST_ERRORS: Lazy = + Lazy::new(|| { + try_create_int_counter_vec( + "near_function_call_processed_namespace_does_not_exist_errors", + "The number of function calls resulting in namespace does not exist errors, since starting this node", + &["error_type"], + ) + .unwrap() + }); diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index a08114d1bd2..a338396af0d 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -551,7 +551,6 @@ mod tests { use near_primitives::delegate_action::{DelegateAction, NonDelegateAction}; use near_primitives::hash::{hash, CryptoHash}; use near_primitives::namespace::Namespace; - use near_primitives::routing_table::RoutingTable; use near_primitives::test_utils::account_new; use near_primitives::transaction::{ CreateAccountAction, DeleteAccountAction, DeleteKeyAction, StakeAction, TransferAction, @@ -1451,7 +1450,6 @@ mod tests { vec![Action::DeployContract(DeployContractAction { code: vec![1; 5], namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], CryptoHash::default(), ); diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs index 6ae8bb7c98d..3da70c627bd 100644 --- a/runtime/runtime/tests/test_async_calls.rs +++ b/runtime/runtime/tests/test_async_calls.rs @@ -5,7 +5,6 @@ use near_primitives::account::{AccessKeyPermission, FunctionCallPermission}; use near_primitives::hash::CryptoHash; use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, ReceiptEnum}; -use near_primitives::routing_table::RoutingTable; use near_primitives::serialize::to_base64; use near_primitives::types::AccountId; @@ -794,7 +793,7 @@ fn test_account_factory() { method_names: vec!["call_promise".to_string(), "hello".to_string()], })); }, - a3, Action::DeployContract(DeployContractAction{code,namespace,routing_table}), { + a3, Action::DeployContract(DeployContractAction{code,namespace}), { assert_eq!(code, near_test_contracts::rs_contract()); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { @@ -931,7 +930,7 @@ fn test_create_account_add_key_call_delete_key_delete_account() { assert_eq!(access_key.nonce, 1); assert_eq!(access_key.permission, AccessKeyPermission::FullAccess); }, - a3, Action::DeployContract(DeployContractAction{code, namespace, routing_table}), { + a3, Action::DeployContract(DeployContractAction{code, namespace}), { assert_eq!(code, near_test_contracts::rs_contract()); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { diff --git a/test-utils/runtime-tester/src/fuzzing.rs b/test-utils/runtime-tester/src/fuzzing.rs index 4d10610ab3b..9678e2f70af 100644 --- a/test-utils/runtime-tester/src/fuzzing.rs +++ b/test-utils/runtime-tester/src/fuzzing.rs @@ -3,7 +3,6 @@ use near_crypto::{InMemorySigner, KeyType, PublicKey}; use near_primitives::{ account::{AccessKey, AccessKeyPermission, FunctionCallPermission}, namespace::Namespace, - routing_table::RoutingTable, transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, FunctionCallAction, TransferAction, @@ -219,7 +218,6 @@ impl TransactionConfig { actions: vec![Action::DeployContract(DeployContractAction { code: scope.available_contracts[contract_id].code.clone(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], }) }); diff --git a/tools/state-viewer/src/contract_accounts.rs b/tools/state-viewer/src/contract_accounts.rs index 5dac1ebbda5..fba62d2df25 100644 --- a/tools/state-viewer/src/contract_accounts.rs +++ b/tools/state-viewer/src/contract_accounts.rs @@ -489,7 +489,6 @@ mod tests { use near_primitives::hash::CryptoHash; use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; - use near_primitives::routing_table::RoutingTable; use near_primitives::transaction::{ Action, CreateAccountAction, DeployContractAction, ExecutionMetadata, ExecutionOutcome, ExecutionOutcomeWithProof, ExecutionStatus, FunctionCallAction, TransferAction, @@ -590,7 +589,6 @@ mod tests { Action::DeployContract(DeployContractAction { code: vec![], namespace: Namespace::default(), - routing_table: RoutingTable::default(), }), ], ); diff --git a/tools/state-viewer/src/state_dump.rs b/tools/state-viewer/src/state_dump.rs index febb6b6e92a..6b1779d8801 100644 --- a/tools/state-viewer/src/state_dump.rs +++ b/tools/state-viewer/src/state_dump.rs @@ -303,7 +303,6 @@ mod test { use near_crypto::{InMemorySigner, KeyFile, KeyType, PublicKey, SecretKey}; use near_primitives::account::id::AccountId; use near_primitives::namespace::Namespace; - use near_primitives::routing_table::RoutingTable; use near_primitives::state_record::StateRecord; use near_primitives::transaction::{Action, DeployContractAction, SignedTransaction}; use near_primitives::types::{ @@ -447,7 +446,6 @@ mod test { vec![Action::DeployContract(DeployContractAction { code: near_test_contracts::base_rs_contract().to_vec(), namespace: Namespace::default(), - routing_table: RoutingTable::default(), })], genesis_hash, ); From b6743a0c0eccca6de58c3c9c64f97bb0e3d3eef1 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Wed, 24 May 2023 12:11:23 +0900 Subject: [PATCH 7/9] mismatch test + some cleanup --- chain/client/src/test_utils.rs | 4 +- chain/rosetta-rpc/src/models.rs | 1 - core/primitives/src/state_record.rs | 4 +- core/primitives/src/trie_key.rs | 2 +- core/primitives/src/types.rs | 4 +- .../limit_contract_functions_number.rs | 4 +- .../src/tests/client/process_blocks.rs | 64 +++++++++++++++++-- runtime/runtime/src/actions.rs | 8 +-- runtime/runtime/src/genesis.rs | 4 +- 9 files changed, 72 insertions(+), 23 deletions(-) diff --git a/chain/client/src/test_utils.rs b/chain/client/src/test_utils.rs index 78463c90a6c..efcbfdeb5f1 100644 --- a/chain/client/src/test_utils.rs +++ b/chain/client/src/test_utils.rs @@ -1893,10 +1893,10 @@ impl TestEnv { /// This function assumes that account has been deployed and that /// `InMemorySigner::from_seed` produces a valid signer that has it's key /// deployed already. - pub fn call_main(&mut self, account: &AccountId) -> FinalExecutionOutcomeView { + pub fn call_main(&mut self, account: &AccountId, namespace: Namespace) -> FinalExecutionOutcomeView { let signer = InMemorySigner::from_seed(account.clone(), KeyType::ED25519, account.as_str()); let actions = vec![Action::FunctionCall(FunctionCallAction { - namespace: Namespace::default(), + namespace, method_name: "main".to_string(), args: vec![], gas: 3 * 10u64.pow(14), diff --git a/chain/rosetta-rpc/src/models.rs b/chain/rosetta-rpc/src/models.rs index 71974503ae7..1224eaccb9f 100644 --- a/chain/rosetta-rpc/src/models.rs +++ b/chain/rosetta-rpc/src/models.rs @@ -1,4 +1,3 @@ -use near_primitives::namespace::Namespace; use paperclip::actix::{api_v2_errors, Apiv2Schema}; use near_primitives::hash::CryptoHash; diff --git a/core/primitives/src/state_record.rs b/core/primitives/src/state_record.rs index 75508991093..7c5f9adab87 100644 --- a/core/primitives/src/state_record.rs +++ b/core/primitives/src/state_record.rs @@ -7,8 +7,8 @@ use crate::trie_key::trie_key_parsers::{ parse_account_id_from_access_key_key, parse_account_id_from_account_key, parse_account_id_from_contract_code_key, parse_account_id_from_contract_data_key, parse_account_id_from_received_data_key, parse_data_id_from_received_data_key, - parse_data_key_from_contract_data_key, parse_namespace_from_contract_code_key, - parse_parts_from_contract_data_key, parse_public_key_from_access_key_key, + parse_namespace_from_contract_code_key, parse_parts_from_contract_data_key, + parse_public_key_from_access_key_key, }; use crate::types::AccountId; use borsh::BorshDeserialize; diff --git a/core/primitives/src/trie_key.rs b/core/primitives/src/trie_key.rs index 1b26d465428..c6b30174261 100644 --- a/core/primitives/src/trie_key.rs +++ b/core/primitives/src/trie_key.rs @@ -309,7 +309,7 @@ pub mod trie_key_parsers { ) }) .and_then(|s| { - Namespace::try_from(s).map(|n| (n, s.len())).map_err(|e| { + Namespace::try_from(s).map(|n| (n, s.len())).map_err(|_| { std::io::Error::new( std::io::ErrorKind::InvalidData, "could not decode namespace part of contract data trie key as utf-8", diff --git a/core/primitives/src/types.rs b/core/primitives/src/types.rs index f5d06072b91..6f6a6dc6015 100644 --- a/core/primitives/src/types.rs +++ b/core/primitives/src/types.rs @@ -107,7 +107,7 @@ impl StateChangesKinds { TrieKey::Account { account_id } => { Some(Ok(StateChangeKind::AccountTouched { account_id })) } - TrieKey::ContractCode { account_id, namespace } => { + TrieKey::ContractCode { account_id, namespace: _ } => { Some(Ok(StateChangeKind::ContractCodeTouched { account_id })) } TrieKey::AccessKey { account_id, .. } => { @@ -316,7 +316,7 @@ impl StateChanges { }, )); } - TrieKey::ContractData { account_id, namespace, key } => { + TrieKey::ContractData { account_id, namespace: _, key } => { // TODO: Namespace here? state_changes.extend(changes.into_iter().map( |RawStateChange { cause, data }| StateChangeWithCause { diff --git a/integration-tests/src/tests/client/features/limit_contract_functions_number.rs b/integration-tests/src/tests/client/features/limit_contract_functions_number.rs index 684dec2bce9..9fe5c8589ed 100644 --- a/integration-tests/src/tests/client/features/limit_contract_functions_number.rs +++ b/integration-tests/src/tests/client/features/limit_contract_functions_number.rs @@ -59,11 +59,11 @@ fn verify_contract_limits_upgrade( }; let account = "test0".parse().unwrap(); - let old_outcome = env.call_main(&account); + let old_outcome = env.call_main(&account, Namespace::default()); env.upgrade_protocol(new_protocol_version); - let new_outcome = env.call_main(&account); + let new_outcome = env.call_main(&account, Namespace::default()); assert_matches!(old_outcome.status, FinalExecutionStatus::SuccessValue(_)); let e = match new_outcome.status { diff --git a/integration-tests/src/tests/client/process_blocks.rs b/integration-tests/src/tests/client/process_blocks.rs index a342513baeb..e4fa92ef1e0 100644 --- a/integration-tests/src/tests/client/process_blocks.rs +++ b/integration-tests/src/tests/client/process_blocks.rs @@ -46,8 +46,8 @@ use near_o11y::WithSpanContextExt; use near_primitives::block::{Approval, ApprovalInner}; use near_primitives::block_header::BlockHeader; use near_primitives::epoch_manager::RngSeed; -use near_primitives::errors::InvalidTxError; -use near_primitives::errors::TxExecutionError; +use near_primitives::errors::{ActionError, InvalidTxError}; +use near_primitives::errors::{ActionErrorKind, TxExecutionError}; use near_primitives::hash::{hash, CryptoHash}; use near_primitives::merkle::{verify_hash, PartialMerkleTree}; use near_primitives::receipt::DelayedReceiptIndices; @@ -82,6 +82,7 @@ use near_store::test_utils::create_test_node_storage_with_cold; use near_store::test_utils::create_test_store; use near_store::NodeStorage; use near_store::{get, DBCol, Store, TrieChanges}; +use near_vm_errors::FunctionCallErrorSer; use nearcore::config::{GenesisExt, TESTING_INIT_BALANCE, TESTING_INIT_STAKE}; use nearcore::NEAR_BASE; use rand::prelude::StdRng; @@ -2844,7 +2845,7 @@ fn test_execution_metadata() { }; // Call the contract and get the execution outcome. - let execution_outcome = env.call_main(&"test0".parse().unwrap()); + let execution_outcome = env.call_main(&"test0".parse().unwrap(), Namespace::default()); // Now, let's assert that we get the cost breakdown we expect. let config = RuntimeConfigStore::test().get_config(PROTOCOL_VERSION).clone(); @@ -2937,10 +2938,7 @@ fn test_execution_metadata_namespaced() { }; // Call the contract and get the execution outcome. - // TODO: new version of call_main that accepts namespace - let execution_outcome = env.call_main(&"test0".parse().unwrap()); - - dbg!(&execution_outcome); + let execution_outcome = env.call_main(&"test0".parse().unwrap(), namespace.clone()); // Now, let's assert that we get the cost breakdown we expect. let config = RuntimeConfigStore::test().get_config(PROTOCOL_VERSION).clone(); @@ -2994,6 +2992,58 @@ fn test_execution_metadata_namespaced() { assert_eq!(expected_receipt_cost, actual_receipt_cost) } +#[test] +fn test_execution_metadata_namespaced_mismatch() { + // Prepare TestEnv with a very simple WASM contract. + let wasm_code = wat::parse_str( + r#" +(module + (import "env" "block_index" (func $block_index (result i64))) + (func (export "main") + (call $block_index) + drop + ) +)"#, + ) + .unwrap(); + + let mut env = { + let epoch_length = 5; + let mut genesis = + Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1); + genesis.config.epoch_length = epoch_length; + let chain_genesis = ChainGenesis::new(&genesis); + let mut env = TestEnv::builder(chain_genesis) + .runtime_adapters(create_nightshade_runtimes(&genesis, 1)) + .build(); + + deploy_test_contract( + &mut env, + "test0".parse().unwrap(), + Namespace::default(), // deploy to default namespace but call explicit namespace + &wasm_code, + epoch_length, + 1, + ); + env + }; + + let namespace = Namespace::from("namespace"); + + // Call the contract and get the execution outcome. + let execution_outcome = env.call_main(&"test0".parse().unwrap(), namespace.clone()); + + assert_eq!( + execution_outcome.status, + FinalExecutionStatus::Failure(TxExecutionError::ActionError(ActionError { + index: Some(0), + kind: ActionErrorKind::FunctionCallError( + FunctionCallErrorSer::NamespaceDoesNotExistError(namespace.to_string()) + ) + })) + ); +} + #[test] fn test_epoch_protocol_version_change() { init_test_logger(); diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 0e810eac5f6..428c76891dd 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -13,7 +13,6 @@ use near_primitives::contract::ContractCode; use near_primitives::delegate_action::{DelegateAction, SignedDelegateAction}; use near_primitives::errors::{ActionError, ActionErrorKind, InvalidAccessKeyError, RuntimeError}; use near_primitives::hash::CryptoHash; -use near_primitives::namespace::Namespace; use near_primitives::receipt::{ActionReceipt, Receipt, ReceiptEnum}; use near_primitives::runtime::config::AccountCreationConfig; use near_primitives::runtime::fees::RuntimeFeesConfig; @@ -60,8 +59,8 @@ pub(crate) fn execute_function_call( let code_hash = match account.code_hashes().get(&function_call.namespace) { Some(code_hash) => *code_hash, None => { - return Ok(VMOutcome::nop_outcome(FunctionCallError::CompilationError( - CompilationError::CodeDoesNotExist { account_id: account_id.clone() }, + return Ok(VMOutcome::nop_outcome(FunctionCallError::NamespaceDoesNotExistError( + function_call.namespace.to_string(), ))); } }; @@ -249,7 +248,7 @@ pub(crate) fn action_function_call( metrics::FUNCTION_CALL_PROCESSED_HOST_ERRORS .with_label_values(&[inner_err.into()]) .inc(); - }, + } FunctionCallError::NamespaceDoesNotExistError(ref namespace) => { metrics::FUNCTION_CALL_PROCESSED_NAMESPACE_DOES_NOT_EXIST_ERRORS .with_label_values(&[namespace]) @@ -990,6 +989,7 @@ mod tests { use near_primitives::delegate_action::NonDelegateAction; use near_primitives::errors::InvalidAccessKeyError; use near_primitives::hash::hash; + use near_primitives::namespace::Namespace; use near_primitives::runtime::migration_data::MigrationFlags; use near_primitives::transaction::CreateAccountAction; use near_primitives::trie_key::TrieKey; diff --git a/runtime/runtime/src/genesis.rs b/runtime/runtime/src/genesis.rs index d311c366c8a..362ae67a7f2 100644 --- a/runtime/runtime/src/genesis.rs +++ b/runtime/runtime/src/genesis.rs @@ -42,13 +42,13 @@ impl<'a> StorageComputer<'a> { StateRecord::Account { account_id, .. } => { Some((account_id.clone(), self.config.num_bytes_account)) } - StateRecord::Data { account_id, namespace, data_key, value } => { + StateRecord::Data { account_id, namespace: _, data_key, value } => { // TODO: Accounting let storage_usage = self.config.num_extra_bytes_record + data_key.len() as u64 + value.len() as u64; Some((account_id.clone(), storage_usage)) } - StateRecord::Contract { account_id, namespace, code } => { + StateRecord::Contract { account_id, namespace: _, code } => { // TODO: Accounting Some((account_id.clone(), code.len() as u64)) } From 58c63084655358cc55f8cbd5d5d8243881433242 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Wed, 24 May 2023 12:52:42 +0900 Subject: [PATCH 8/9] update promise_batch_action_deploy_contract and test contracts --- core/primitives/src/transaction.rs | 5 +- .../test-contract-rs/src/lib.rs | 56 ++++++++++++++++++- runtime/near-vm-logic/src/logic.rs | 8 ++- runtime/near-vm-logic/src/receipt_manager.rs | 7 +-- .../near-vm-logic/src/tests/gas_counter.rs | 9 ++- runtime/near-vm-logic/src/tests/miscs.rs | 11 +++- runtime/near-vm-logic/src/tests/promises.rs | 19 ++++++- .../near-vm-logic/src/tests/view_method.rs | 2 +- runtime/near-vm-runner/src/imports.rs | 2 +- .../src/transaction_builder.rs | 2 +- runtime/runtime/src/lib.rs | 3 + runtime/runtime/tests/test_async_calls.rs | 4 +- tools/state-viewer/src/state_dump.rs | 2 +- 13 files changed, 109 insertions(+), 21 deletions(-) diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs index 94cc48620a2..3dc16715ac8 100644 --- a/core/primitives/src/transaction.rs +++ b/core/primitives/src/transaction.rs @@ -119,11 +119,11 @@ impl From for Action { BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone, )] pub struct DeployContractAction { + #[serde(default)] + pub namespace: Namespace, /// WebAssembly binary #[serde(with = "base64_format")] pub code: Vec, - #[serde(default)] - pub namespace: Namespace, } impl From for Action { @@ -145,6 +145,7 @@ impl fmt::Debug for DeployContractAction { BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone, )] pub struct FunctionCallAction { + #[serde(default)] pub namespace: Namespace, pub method_name: String, #[serde(with = "base64_format")] diff --git a/runtime/near-test-contracts/test-contract-rs/src/lib.rs b/runtime/near-test-contracts/test-contract-rs/src/lib.rs index 2638be47657..9fd8e114372 100644 --- a/runtime/near-test-contracts/test-contract-rs/src/lib.rs +++ b/runtime/near-test-contracts/test-contract-rs/src/lib.rs @@ -48,6 +48,8 @@ extern "C" { fn promise_create( account_id_len: u64, account_id_ptr: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -59,6 +61,8 @@ extern "C" { promise_index: u64, account_id_len: u64, account_id_ptr: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -73,9 +77,17 @@ extern "C" { // # Promise API actions # // ####################### fn promise_batch_action_create_account(promise_index: u64); - fn promise_batch_action_deploy_contract(promise_index: u64, code_len: u64, code_ptr: u64); + fn promise_batch_action_deploy_contract( + promise_index: u64, + namespace_len: u64, + namespace_ptr: u64, + code_len: u64, + code_ptr: u64, + ); fn promise_batch_action_function_call( promise_index: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -86,6 +98,8 @@ extern "C" { #[cfg(feature = "latest_protocol")] fn promise_batch_action_function_call_weight( promise_index: u64, + namespace_len: u64, + namespace_ptr: u64, method_name_len: u64, method_name_ptr: u64, arguments_len: u64, @@ -621,6 +635,7 @@ fn call_promise() { for arg in input_args.as_array().unwrap() { let actual_id = if let Some(create) = arg.get("create") { let account_id = create["account_id"].as_str().unwrap().as_bytes(); + let namespace = create["namespace"].as_str().unwrap().as_bytes(); let method_name = create["method_name"].as_str().unwrap().as_bytes(); let arguments = serde_json::to_vec(&create["arguments"]).unwrap(); let amount = create["amount"].as_str().unwrap().parse::().unwrap(); @@ -628,6 +643,8 @@ fn call_promise() { promise_create( account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name.len() as u64, method_name.as_ptr() as u64, arguments.len() as u64, @@ -638,6 +655,7 @@ fn call_promise() { } else if let Some(then) = arg.get("then") { let promise_index = then["promise_index"].as_i64().unwrap() as u64; let account_id = then["account_id"].as_str().unwrap().as_bytes(); + let namespace = then["namespace"].as_str().unwrap().as_bytes(); let method_name = then["method_name"].as_str().unwrap().as_bytes(); let arguments = serde_json::to_vec(&then["arguments"]).unwrap(); let amount = then["amount"].as_str().unwrap().parse::().unwrap(); @@ -646,6 +664,8 @@ fn call_promise() { promise_index, account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name.len() as u64, method_name.as_ptr() as u64, arguments.len() as u64, @@ -677,21 +697,27 @@ fn call_promise() { promise_index } else if let Some(action) = arg.get("action_deploy_contract") { let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let namespace = action["namespace"].as_str().unwrap().as_bytes(); let code = from_base64(action["code"].as_str().unwrap()); promise_batch_action_deploy_contract( promise_index, + namespace.len() as u64, + namespace.as_ptr() as u64, code.len() as u64, code.as_ptr() as u64, ); promise_index } else if let Some(action) = arg.get("action_function_call") { let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let namespace = action["namespace"].as_str().unwrap().as_bytes(); let method_name = action["method_name"].as_str().unwrap().as_bytes(); let arguments = serde_json::to_vec(&action["arguments"]).unwrap(); let amount = action["amount"].as_str().unwrap().parse::().unwrap(); let gas = action["gas"].as_i64().unwrap() as u64; promise_batch_action_function_call( promise_index, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name.len() as u64, method_name.as_ptr() as u64, arguments.len() as u64, @@ -788,6 +814,7 @@ fn attach_unspent_gas_but_burn_all_gas() { let account_id = "alice.near"; let promise_idx = promise_batch_create(account_id.len() as u64, account_id.as_ptr() as u64); + let namespace = ""; let method_name = "f"; let arguments_ptr = 0; let arguments_len = 0; @@ -796,6 +823,8 @@ fn attach_unspent_gas_but_burn_all_gas() { let gas_weight = 1; promise_batch_action_function_call_weight( promise_idx, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name.len() as u64, method_name.as_ptr() as u64, arguments_ptr, @@ -817,6 +846,7 @@ fn attach_unspent_gas_but_use_all_gas() { let account_id = "alice.near"; let promise_idx = promise_batch_create(account_id.len() as u64, account_id.as_ptr() as u64); + let namespace = ""; let method_name = "f"; let arguments_ptr = 0; let arguments_len = 0; @@ -825,6 +855,8 @@ fn attach_unspent_gas_but_use_all_gas() { let gas_weight = 1; promise_batch_action_function_call_weight( promise_idx, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name.len() as u64, method_name.as_ptr() as u64, arguments_ptr, @@ -840,6 +872,8 @@ fn attach_unspent_gas_but_use_all_gas() { let gas_weight = 0; promise_batch_action_function_call_weight( promise_idx, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name.len() as u64, method_name.as_ptr() as u64, arguments_ptr, @@ -924,6 +958,7 @@ pub unsafe fn sanity_check() { value_return(value.len() as u64, value.as_ptr() as u64); // Calling host functions that terminate execution via promises. + let namespace = ""; let method_name_panic = b"sanity_check_panic"; let args_panic = b""; let amount_zero = 0u128; @@ -932,6 +967,8 @@ pub unsafe fn sanity_check() { promise_create( account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name_panic.len() as u64, method_name_panic.as_ptr() as u64, args_panic.len() as u64, @@ -947,6 +984,8 @@ pub unsafe fn sanity_check() { promise_create( account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name_panic_utf8.len() as u64, method_name_panic_utf8.as_ptr() as u64, args_panic_utf8.len() as u64, @@ -972,6 +1011,8 @@ pub unsafe fn sanity_check() { promise_create( account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name_noop.len() as u64, method_name_noop.as_ptr() as u64, args_noop.len() as u64, @@ -988,6 +1029,8 @@ pub unsafe fn sanity_check() { 2, account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name_noop.len() as u64, method_name_noop.as_ptr() as u64, args_noop.len() as u64, @@ -1010,6 +1053,7 @@ pub unsafe fn sanity_check() { let amount_non_zero = 50_000_000_000_000_000_000_000u128; let contract_code = from_base64(input_args["contract_code"].as_str().unwrap()); let method_deployed_contract = input_args["method_name"].as_str().unwrap().as_bytes(); + let namespace = input_args["namespace"].as_str().unwrap().as_bytes(); let args_deployed_contract = from_base64(input_args["method_args"].as_str().unwrap()); assert_eq!( promise_batch_create(new_account_id.len() as u64, new_account_id.as_ptr() as u64), @@ -1022,11 +1066,15 @@ pub unsafe fn sanity_check() { ); promise_batch_action_deploy_contract( batch_promise_idx, + namespace.len() as u64, + namespace.as_ptr() as u64, contract_code.len() as u64, contract_code.as_ptr() as u64, ); promise_batch_action_function_call( batch_promise_idx, + namespace.len() as u64, + namespace.as_ptr() as u64, method_deployed_contract.len() as u64, method_deployed_contract.as_ptr() as u64, args_deployed_contract.len() as u64, @@ -1037,6 +1085,8 @@ pub unsafe fn sanity_check() { #[cfg(feature = "latest_protocol")] promise_batch_action_function_call_weight( batch_promise_idx, + namespace.len() as u64, + namespace.as_ptr() as u64, method_deployed_contract.len() as u64, method_deployed_contract.as_ptr() as u64, args_deployed_contract.len() as u64, @@ -1102,6 +1152,8 @@ pub unsafe fn sanity_check() { promise_create( account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name_noop.len() as u64, method_name_noop.as_ptr() as u64, args_noop.len() as u64, @@ -1118,6 +1170,8 @@ pub unsafe fn sanity_check() { 10, account_id.len() as u64, account_id.as_ptr() as u64, + namespace.len() as u64, + namespace.as_ptr() as u64, method_name_promise_results.len() as u64, method_name_promise_results.as_ptr() as u64, args_promise_results.len() as u64, diff --git a/runtime/near-vm-logic/src/logic.rs b/runtime/near-vm-logic/src/logic.rs index 4b78c5c28c4..cca99e0f3a4 100644 --- a/runtime/near-vm-logic/src/logic.rs +++ b/runtime/near-vm-logic/src/logic.rs @@ -13,6 +13,7 @@ use near_primitives::runtime::fees::RuntimeFeesConfig; use near_primitives::version::is_implicit_account_creation_enabled; use near_primitives_core::config::ExtCosts::*; use near_primitives_core::config::{ActionCosts, ExtCosts, VMConfig}; +use near_primitives_core::namespace::Namespace; use near_primitives_core::runtime::fees::{transfer_exec_fee, transfer_send_fee}; use near_primitives_core::types::{ AccountId, Balance, Compute, EpochHeight, Gas, GasDistribution, GasWeight, ProtocolVersion, @@ -1620,6 +1621,8 @@ impl<'a> VMLogic<'a> { pub fn promise_batch_action_deploy_contract( &mut self, promise_idx: u64, + namespace_len: u64, + namespace_ptr: u64, code_len: u64, code_ptr: u64, ) -> Result<()> { @@ -1643,7 +1646,10 @@ impl<'a> VMLogic<'a> { self.pay_action_base(ActionCosts::deploy_contract_base, sir)?; self.pay_action_per_byte(ActionCosts::deploy_contract_byte, code_len, sir)?; - self.receipt_manager.append_action_deploy_contract(receipt_idx, code)?; + let namespace = get_memory_or_register!(self, namespace_ptr, namespace_len)?; + let namespace = Namespace::try_from(namespace.as_ref()).unwrap_or_default(); // TODO: Proper error here instead of default + + self.receipt_manager.append_action_deploy_contract(receipt_idx, namespace, code)?; Ok(()) } diff --git a/runtime/near-vm-logic/src/receipt_manager.rs b/runtime/near-vm-logic/src/receipt_manager.rs index 4ee53fd4457..84c581fa27c 100644 --- a/runtime/near-vm-logic/src/receipt_manager.rs +++ b/runtime/near-vm-logic/src/receipt_manager.rs @@ -153,15 +153,12 @@ impl ReceiptManager { pub(crate) fn append_action_deploy_contract( &mut self, receipt_index: ReceiptIndex, + namespace: Namespace, code: Vec, ) -> logic::Result<()> { - // TODO: Namespaces here self.append_action( receipt_index, - Action::DeployContract(DeployContractAction { - code, - namespace: Namespace::default(), - }), + Action::DeployContract(DeployContractAction { code, namespace }), ); Ok(()) } diff --git a/runtime/near-vm-logic/src/tests/gas_counter.rs b/runtime/near-vm-logic/src/tests/gas_counter.rs index c0bdeffed9e..9c80368296c 100644 --- a/runtime/near-vm-logic/src/tests/gas_counter.rs +++ b/runtime/near-vm-logic/src/tests/gas_counter.rs @@ -585,9 +585,16 @@ fn out_of_gas_deploy_contract_byte() { /// function to trigger base + 26 bytes deployment costs (26 is arbitrary) fn deploy_contract(logic: &mut TestVMLogic) -> Result<(), VMLogicError> { let account_id = "rick.test"; + let namespace = logic.internal_mem_write(b""); let idx = promise_batch_create(logic, account_id)?; let code = logic.internal_mem_write(b"lorem ipsum with length 26"); - logic.promise_batch_action_deploy_contract(idx, code.len, code.ptr)?; + logic.promise_batch_action_deploy_contract( + idx, + namespace.len, + namespace.ptr, + code.len, + code.ptr, + )?; Ok(()) } diff --git a/runtime/near-vm-logic/src/tests/miscs.rs b/runtime/near-vm-logic/src/tests/miscs.rs index 56df65fc1f0..cfa8af782c7 100644 --- a/runtime/near-vm-logic/src/tests/miscs.rs +++ b/runtime/near-vm-logic/src/tests/miscs.rs @@ -381,15 +381,22 @@ fn test_contract_size_limit() { let mut logic = logic_builder.build(); let account_id = logic.internal_mem_write(b"alice"); + let namespace = logic.internal_mem_write(b""); let promise_id = logic .promise_batch_create(account_id.len, account_id.ptr) .expect("Number of promises is under the limit"); logic - .promise_batch_action_deploy_contract(promise_id, limit, 0) + .promise_batch_action_deploy_contract(promise_id, namespace.len, namespace.ptr, limit, 0) .expect("The length of the contract code is under the limit"); assert_eq!( - logic.promise_batch_action_deploy_contract(promise_id, limit + 1, 0), + logic.promise_batch_action_deploy_contract( + promise_id, + namespace.len, + namespace.ptr, + limit + 1, + 0 + ), Err(HostError::ContractSizeExceeded { size: limit + 1, limit }.into()) ); } diff --git a/runtime/near-vm-logic/src/tests/promises.rs b/runtime/near-vm-logic/src/tests/promises.rs index 42cb726fb59..3da60b7ce7b 100644 --- a/runtime/near-vm-logic/src/tests/promises.rs +++ b/runtime/near-vm-logic/src/tests/promises.rs @@ -120,19 +120,32 @@ fn test_promise_batch_action_deploy_contract() { let index = promise_create(&mut logic, b"rick.test", 0, 0).expect("should create a promise"); let index_ptr = logic.internal_mem_write(&index.to_le_bytes()).ptr; + let namespace = logic.internal_mem_write(b""); let code = logic.internal_mem_write(b"sample"); logic - .promise_batch_action_deploy_contract(123, code.len, code.ptr) + .promise_batch_action_deploy_contract(123, namespace.len, namespace.ptr, code.len, code.ptr) .expect_err("shouldn't accept not existent promise index"); let non_receipt = logic.promise_and(index_ptr, 1u64).expect("should create a non-receipt promise"); logic - .promise_batch_action_deploy_contract(non_receipt, code.len, code.ptr) + .promise_batch_action_deploy_contract( + non_receipt, + namespace.len, + namespace.ptr, + code.len, + code.ptr, + ) .expect_err("shouldn't accept non-receipt promise index"); logic - .promise_batch_action_deploy_contract(index, code.len, code.ptr) + .promise_batch_action_deploy_contract( + index, + namespace.len, + namespace.ptr, + code.len, + code.ptr, + ) .expect("should add an action to deploy contract"); assert_eq!(logic.used_gas().unwrap(), 5255774958146); let expected = serde_json::json!( diff --git a/runtime/near-vm-logic/src/tests/view_method.rs b/runtime/near-vm-logic/src/tests/view_method.rs index f0c9d9b6fe2..8f9633604fb 100644 --- a/runtime/near-vm-logic/src/tests/view_method.rs +++ b/runtime/near-vm-logic/src/tests/view_method.rs @@ -24,7 +24,7 @@ fn test_prohibited_view_methods() { test_prohibited!(promise_batch_create, 0, 0); test_prohibited!(promise_batch_then, 0, 0, 0); test_prohibited!(promise_batch_action_create_account, 0); - test_prohibited!(promise_batch_action_deploy_contract, 0, 0, 0); + test_prohibited!(promise_batch_action_deploy_contract, 0, 0, 0, 0, 0); test_prohibited!(promise_batch_action_function_call, 0, 0, 0, 0, 0, 0, 0, 0, 0); test_prohibited!(promise_batch_action_transfer, 0, 0); test_prohibited!(promise_batch_action_stake, 0, 0, 0, 0); diff --git a/runtime/near-vm-runner/src/imports.rs b/runtime/near-vm-runner/src/imports.rs index 36ee0467aff..9ff6452e408 100644 --- a/runtime/near-vm-runner/src/imports.rs +++ b/runtime/near-vm-runner/src/imports.rs @@ -175,7 +175,7 @@ imports! { // # Promise API actions # // ####################### promise_batch_action_create_account<[promise_index: u64] -> []>, - promise_batch_action_deploy_contract<[promise_index: u64, code_len: u64, code_ptr: u64] -> []>, + promise_batch_action_deploy_contract<[promise_index: u64, namespace_len: u64, namespace_ptr: u64, code_len: u64, code_ptr: u64] -> []>, promise_batch_action_function_call<[ promise_index: u64, namespace_len: u64, diff --git a/runtime/runtime-params-estimator/src/transaction_builder.rs b/runtime/runtime-params-estimator/src/transaction_builder.rs index b6d564cdd8c..bac1c279954 100644 --- a/runtime/runtime-params-estimator/src/transaction_builder.rs +++ b/runtime/runtime-params-estimator/src/transaction_builder.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use genesis_populate::get_account_id; use near_crypto::{InMemorySigner, KeyType}; use near_primitives::hash::CryptoHash; -use near_primitives::namespace::{self, Namespace}; +use near_primitives::namespace::Namespace; use near_primitives::transaction::{Action, FunctionCallAction, SignedTransaction}; use near_primitives::types::AccountId; use rand::prelude::ThreadRng; diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 94b41388a31..9de9fe30069 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -2578,6 +2578,7 @@ mod tests { alice_account(), signer.clone(), vec![Action::DeployContract(DeployContractAction { + namespace: Namespace::default(), code: near_test_contracts::rs_contract().to_vec(), })], ); @@ -2586,6 +2587,7 @@ mod tests { alice_account(), signer.clone(), vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "ext_sha256".to_string(), args: b"first".to_vec(), gas: 1, @@ -2597,6 +2599,7 @@ mod tests { alice_account(), signer.clone(), vec![Action::FunctionCall(FunctionCallAction { + namespace: Namespace::default(), method_name: "ext_sha256".to_string(), args: b"second".to_vec(), gas: 1, diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs index 3da70c627bd..1363a107219 100644 --- a/runtime/runtime/tests/test_async_calls.rs +++ b/runtime/runtime/tests/test_async_calls.rs @@ -793,7 +793,7 @@ fn test_account_factory() { method_names: vec!["call_promise".to_string(), "hello".to_string()], })); }, - a3, Action::DeployContract(DeployContractAction{code,namespace}), { + a3, Action::DeployContract(DeployContractAction{code,namespace: _}), { assert_eq!(code, near_test_contracts::rs_contract()); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { @@ -930,7 +930,7 @@ fn test_create_account_add_key_call_delete_key_delete_account() { assert_eq!(access_key.nonce, 1); assert_eq!(access_key.permission, AccessKeyPermission::FullAccess); }, - a3, Action::DeployContract(DeployContractAction{code, namespace}), { + a3, Action::DeployContract(DeployContractAction{code, namespace: _}), { assert_eq!(code, near_test_contracts::rs_contract()); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { diff --git a/tools/state-viewer/src/state_dump.rs b/tools/state-viewer/src/state_dump.rs index 6b1779d8801..3976b45cf83 100644 --- a/tools/state-viewer/src/state_dump.rs +++ b/tools/state-viewer/src/state_dump.rs @@ -182,7 +182,7 @@ pub fn state_dump_redis( println!("Data written: {}", account_id); } - if let StateRecord::Contract { account_id, namespace, code } = &sr { + if let StateRecord::Contract { account_id, namespace: _, code } = &sr { // TODO: dump namespace println!("Contract: {}", account_id); let redis_key = [b"code:", account_id.as_ref().as_bytes()].concat(); From 275c1e827f73933e0a2a096884a4f22f0ba044ec Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Thu, 25 May 2023 01:59:40 +0900 Subject: [PATCH 9/9] fix_contract_loading_cost test fix --- .../src/tests/client/features/fix_contract_loading_cost.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/tests/client/features/fix_contract_loading_cost.rs b/integration-tests/src/tests/client/features/fix_contract_loading_cost.rs index e5a0868eb14..071674bd34d 100644 --- a/integration-tests/src/tests/client/features/fix_contract_loading_cost.rs +++ b/integration-tests/src/tests/client/features/fix_contract_loading_cost.rs @@ -5,6 +5,7 @@ use near_chain_configs::Genesis; use near_client::test_utils::TestEnv; use near_primitives::types::{AccountId, BlockHeight}; use near_primitives::views::FinalExecutionStatus; +use near_primitives::namespace::Namespace; use nearcore::config::GenesisExt; /// Create a `TestEnv` with an account and a contract deployed to that account. @@ -20,7 +21,7 @@ fn prepare_env_with_contract( let mut env = TestEnv::builder(ChainGenesis::new(&genesis)) .runtime_adapters(create_nightshade_runtimes(&genesis, 1)) .build(); - deploy_test_contract(&mut env, account, &contract, epoch_length.clone(), 1); + deploy_test_contract(&mut env, account, Namespace::default(), &contract, epoch_length.clone(), 1); env }