Skip to content

Commit

Permalink
core: make StoreKey, StoreValue and FunctionArgs serde serialisable (#…
Browse files Browse the repository at this point in the history
…8985)

Derive serialisation code for StoreKey, StoreVlaue and FunctionArgs
primitive types and then use those types more in various structures
which so far has been using raw `Vec<u8>` instead.

This improves self-documentation of the code (the type of the struct
field indicates what it is) and moves base64 format declaration to the
primitive types rather than having to annotate individual structures
with `#[serde(with = ...)]`.

On the flip side, it does add a couple `.into()` calls when converting
between one of the aforementioned types and `Vec<u8>`.
  • Loading branch information
mina86 committed May 2, 2023
1 parent de5c218 commit 416b38c
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 50 deletions.
5 changes: 2 additions & 3 deletions core/primitives-core/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ pub mod base64_format {
serializer.serialize_str(&to_base64(data))
}

pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
T: From<Vec<u8>>,
{
let s = String::deserialize(deserializer)?;
from_base64(&s).map_err(|err| de::Error::custom(err.to_string())).map(Into::into)
from_base64(&s).map_err(|err| de::Error::custom(err.to_string()))
}
}

Expand Down
20 changes: 9 additions & 11 deletions core/primitives/src/state_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::trie_key::trie_key_parsers::{
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,
};
use crate::types::AccountId;
use crate::types::{AccountId, StoreKey, StoreValue};
use borsh::BorshDeserialize;
use near_crypto::PublicKey;
use std::fmt::{Display, Formatter};
Expand All @@ -20,13 +20,7 @@ pub enum StateRecord {
/// Account information.
Account { account_id: AccountId, account: Account },
/// Data records inside the contract, encoded in base64.
Data {
account_id: AccountId,
#[serde(with = "base64_format")]
data_key: Vec<u8>,
#[serde(with = "base64_format")]
value: Vec<u8>,
},
Data { account_id: AccountId, data_key: StoreKey, value: StoreValue },
/// Contract code encoded in base64.
Contract {
account_id: AccountId,
Expand Down Expand Up @@ -63,7 +57,11 @@ 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 })
Some(StateRecord::Data {
account_id,
data_key: data_key.to_vec().into(),
value: value.into(),
})
}
col::CONTRACT_CODE => Some(StateRecord::Contract {
account_id: parse_account_id_from_contract_code_key(&key).unwrap(),
Expand Down Expand Up @@ -107,8 +105,8 @@ impl Display for StateRecord {
f,
"Storage {:?},{:?}: {:?}",
account_id,
to_printable(data_key),
to_printable(value)
to_printable(data_key.as_ref()),
to_printable(value.as_ref())
),
StateRecord::Contract { account_id, code: _ } => {
write!(f, "Code for {:?}: ...", account_id)
Expand Down
52 changes: 41 additions & 11 deletions core/primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use crate::challenge::ChallengesResult;
use crate::errors::EpochError;
use crate::hash::CryptoHash;
use crate::receipt::Receipt;
use crate::serialize::base64_format;
use crate::serialize::dec_format;
use crate::trie_key::TrieKey;
use borsh::{BorshDeserialize, BorshSerialize};
use derive_more::{AsRef as DeriveAsRef, From as DeriveFrom};
use near_crypto::PublicKey;
/// Reexport primitive types
pub use near_primitives_core::types::*;
Expand Down Expand Up @@ -50,31 +50,61 @@ pub struct AccountInfo {
/// NOTE: Currently, this type is only used in the view_client and RPC to be able to transparently
/// pretty-serialize the bytes arrays as base64-encoded strings (see `serialize.rs`).
#[derive(
Debug, Clone, PartialEq, Eq, DeriveAsRef, DeriveFrom, BorshSerialize, BorshDeserialize,
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
derive_more::Deref,
derive_more::From,
derive_more::Into,
BorshSerialize,
BorshDeserialize,
)]
#[as_ref(forward)]
pub struct StoreKey(Vec<u8>);
#[serde(transparent)]
pub struct StoreKey(#[serde(with = "base64_format")] Vec<u8>);

/// This type is used to mark values returned from store (arrays of bytes).
///
/// NOTE: Currently, this type is only used in the view_client and RPC to be able to transparently
/// pretty-serialize the bytes arrays as base64-encoded strings (see `serialize.rs`).
#[derive(
Debug, Clone, PartialEq, Eq, DeriveAsRef, DeriveFrom, BorshSerialize, BorshDeserialize,
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
derive_more::Deref,
derive_more::From,
derive_more::Into,
BorshSerialize,
BorshDeserialize,
)]
#[as_ref(forward)]
pub struct StoreValue(Vec<u8>);
#[serde(transparent)]
pub struct StoreValue(#[serde(with = "base64_format")] Vec<u8>);

/// This type is used to mark function arguments.
///
/// NOTE: The main reason for this to exist (except the type-safety) is that the value is
/// transparently serialized and deserialized as a base64-encoded string when serde is used
/// (serde_json).
#[derive(
Debug, Clone, PartialEq, Eq, DeriveAsRef, DeriveFrom, BorshSerialize, BorshDeserialize,
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
derive_more::Deref,
derive_more::From,
derive_more::Into,
BorshSerialize,
BorshDeserialize,
)]
#[as_ref(forward)]
pub struct FunctionArgs(Vec<u8>);
#[serde(transparent)]
pub struct FunctionArgs(#[serde(with = "base64_format")] Vec<u8>);

/// A structure used to indicate the kind of state changes due to transaction/receipt processing, etc.
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
Expand Down Expand Up @@ -441,7 +471,7 @@ impl StateRootNode {
PartialEq,
PartialOrd,
Ord,
DeriveAsRef,
derive_more::AsRef,
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Expand Down
30 changes: 16 additions & 14 deletions core/primitives/src/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,8 @@ impl From<AccessKeyView> for AccessKey {
/// Item of the state, key and value are serialized in base64 and proof for inclusion of given state item.
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct StateItem {
#[serde(with = "base64_format")]
pub key: Vec<u8>,
#[serde(with = "base64_format")]
pub value: Vec<u8>,
pub key: StoreKey,
pub value: StoreValue,
/// Deprecated, always empty, eventually will be deleted.
// TODO(mina86): This was deprecated in 1.30. Get rid of the field
// altogether at 1.33 or something.
Expand Down Expand Up @@ -306,7 +304,7 @@ pub enum QueryRequest {
},
ViewState {
account_id: AccountId,
#[serde(rename = "prefix_base64", with = "base64_format")]
#[serde(rename = "prefix_base64")]
prefix: StoreKey,
#[serde(default, skip_serializing_if = "is_false")]
include_proof: bool,
Expand All @@ -321,7 +319,7 @@ pub enum QueryRequest {
CallFunction {
account_id: AccountId,
method_name: String,
#[serde(rename = "args_base64", with = "base64_format")]
#[serde(rename = "args_base64")]
args: FunctionArgs,
},
}
Expand Down Expand Up @@ -1111,8 +1109,7 @@ pub enum ActionView {
},
FunctionCall {
method_name: String,
#[serde(with = "base64_format")]
args: Vec<u8>,
args: FunctionArgs,
gas: Gas,
#[serde(with = "dec_format")]
deposit: Balance,
Expand Down Expand Up @@ -1152,7 +1149,7 @@ impl From<Action> for ActionView {
}
Action::FunctionCall(action) => ActionView::FunctionCall {
method_name: action.method_name,
args: action.args,
args: action.args.into(),
gas: action.gas,
deposit: action.deposit,
},
Expand Down Expand Up @@ -1186,7 +1183,12 @@ impl TryFrom<ActionView> for Action {
Action::DeployContract(DeployContractAction { code })
}
ActionView::FunctionCall { method_name, args, gas, deposit } => {
Action::FunctionCall(FunctionCallAction { method_name, args, gas, deposit })
Action::FunctionCall(FunctionCallAction {
method_name,
args: args.into(),
gas,
deposit,
})
}
ActionView::Transfer { deposit } => Action::Transfer(TransferAction { deposit }),
ActionView::Stake { stake, public_key } => {
Expand Down Expand Up @@ -2036,7 +2038,7 @@ pub enum StateChangesRequestView {
},
DataChanges {
account_ids: Vec<AccountId>,
#[serde(rename = "key_prefix_base64", with = "base64_format")]
#[serde(rename = "key_prefix_base64")]
key_prefix: StoreKey,
},
}
Expand Down Expand Up @@ -2160,14 +2162,14 @@ pub enum StateChangeValueView {
},
DataUpdate {
account_id: AccountId,
#[serde(rename = "key_base64", with = "base64_format")]
#[serde(rename = "key_base64")]
key: StoreKey,
#[serde(rename = "value_base64", with = "base64_format")]
#[serde(rename = "value_base64")]
value: StoreValue,
},
DataDeletion {
account_id: AccountId,
#[serde(rename = "key_base64", with = "base64_format")]
#[serde(rename = "key_base64")]
key: StoreKey,
},
ContractCodeUpdate {
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/src/tests/client/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ fn test_patch_state() {
env.clients[0].chain.patch_state(SandboxStatePatch::new(vec![StateRecord::Data {
account_id: "test0".parse().unwrap(),
data_key: state_item.key,
value: b"world".to_vec(),
value: b"world".to_vec().into(),
}]));

do_blocks(&mut env, 9, 20);
let state = env.query_state("test0".parse().unwrap());
assert_eq!(state.len(), 1);
assert_eq!(state[0].value, b"world");
assert_eq!(state[0].value.as_slice(), b"world");
}

#[test]
Expand Down
6 changes: 5 additions & 1 deletion integration-tests/src/tests/runtime/state_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@ fn assert_view_state(

let values = want_values
.iter()
.map(|(key, value)| StateItem { key: key.to_vec(), value: value.to_vec(), proof: vec![] })
.map(|(key, value)| StateItem {
key: key.to_vec().into(),
value: value.to_vec().into(),
proof: vec![],
})
.collect::<Vec<_>>();

let view_state =
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/src/tests/standard_cases/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ fn create_runtime_with_expensive_storage() -> RuntimeNode {
}
records.push(StateRecord::Data {
account_id: bob_account(),
data_key: b"test".to_vec(),
value: b"123".to_vec(),
data_key: b"test".to_vec().into(),
value: b"123".to_vec().into(),
});
RuntimeNode::new_from_genesis_and_config(&alice_account(), genesis, runtime_config)
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/runtime/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ impl GenesisStateApplier {
storage.modify(|state_update| {
state_update.set(
TrieKey::ContractData {
key: data_key.clone(),
key: data_key.clone().into(),
account_id: account_id.clone(),
},
value.clone(),
value.clone().into(),
);
})
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1526,7 +1526,7 @@ impl Runtime {
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);
state_update.set(TrieKey::ContractData { key: data_key.into(), account_id }, value.into());
}
StateRecord::Contract { account_id, 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");
Expand Down
4 changes: 2 additions & 2 deletions runtime/runtime/src/state_viewer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ impl TrieViewer {
for item in &mut iter {
let (key, value) = item?;
values.push(StateItem {
key: key[acc_sep_len..].to_vec(),
value: value,
key: key[acc_sep_len..].to_vec().into(),
value: value.into(),
proof: vec![],
});
}
Expand Down
2 changes: 1 addition & 1 deletion tools/state-viewer/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub(crate) fn dump_account_storage(
let record = StateRecord::from_raw_key_value(key.to_vec(), value).unwrap();
match record {
StateRecord::Data { account_id: _, data_key: _, value } => {
fs::write(output, value).unwrap();
fs::write(output, value.as_slice()).unwrap();
println!(
"Dump contract storage under key {} of account {} into file {}",
storage_key,
Expand Down

0 comments on commit 416b38c

Please sign in to comment.