Skip to content

Commit

Permalink
feat: add possibility to provide new arguments in json format (#871)
Browse files Browse the repository at this point in the history
## Description

The PR adds a new option to pass init arguments in JSON format. 

## Performance / NEAR gas cost considerations

There are no changes in performance or gas cost.

## Testing

A corresponding unit test has been added.

## Additional information

The controller contract needs the change to allow passing generic JSON
object as initialise arguments.
  • Loading branch information
aleksuss committed Nov 28, 2023
1 parent fcbcc30 commit 9d10373
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 13 deletions.
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,11 @@ rpath = false
# it to actually happen when running tests with --release
lto = true
opt-level = 3

# The profile is needed for faster linking in case we need to run locally a small amount of tests or just test
# business logic rather than test gas cost. E.g. of using the profile with the cargo:
# `cargo test --profile fast-link --features mainnet-test name_of_test_we_want_execute`
[profile.fast-link]
inherits = "dev"
opt-level = 0
lto = false
2 changes: 1 addition & 1 deletion engine-tests/src/tests/sanity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ fn test_num_wasm_functions() {
let module = walrus::ModuleConfig::default()
.parse(runner.code.code())
.unwrap();
let expected_number = 1550;
let expected_number = 1600;
let actual_number = module.funcs.iter().count();

assert!(
Expand Down
96 changes: 84 additions & 12 deletions engine-types/src/parameters/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,44 @@ pub enum NewCallArgs {
}

impl NewCallArgs {
/// Creates a `NewCallArs` from the provided bytes which could be represented
/// in JSON or Borsh format. Supporting arguments in JSON format starting from V4.
pub fn deserialize(bytes: &[u8]) -> Result<Self, borsh::maybestd::io::Error> {
Self::try_from_slice(bytes).map_or_else(
|_| LegacyNewCallArgs::try_from_slice(bytes).map(Self::V1),
Ok,
)
Self::try_from_json(bytes).or_else(|_| {
Self::try_from_slice(bytes).map_or_else(
|_| LegacyNewCallArgs::try_from_slice(bytes).map(Self::V1),
Ok,
)
})
}

/// Returns a genesis hash of the Hashchain if present.
#[must_use]
pub const fn initial_hashchain(&self) -> Option<RawH256> {
match self {
Self::V4(args) => args.initial_hashchain,
Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
}
}

fn try_from_json(bytes: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice::<NewCallJsonArgs>(bytes).map(Into::into)
}
}

impl From<NewCallJsonArgs> for NewCallArgs {
fn from(value: NewCallJsonArgs) -> Self {
match value {
NewCallJsonArgs::V1(args) => Self::V4(args),
}
}
}

/// JSON encoded new parameters.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum NewCallJsonArgs {
V1(NewCallArgsV4),
}

/// Old Borsh-encoded parameters for the `new` function.
Expand Down Expand Up @@ -75,9 +99,10 @@ pub struct NewCallArgsV3 {
pub key_manager: AccountId,
}

#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
pub struct NewCallArgsV4 {
/// Chain id, according to the EIP-115 / ethereum-lists spec.
#[serde(with = "chain_id_deserialize")]
pub chain_id: RawU256,
/// Account which can upgrade this contract.
/// Use empty to disable updatability.
Expand All @@ -93,14 +118,14 @@ pub struct NewCallArgsV4 {

/// Borsh-encoded parameters for the `set_owner` function.
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
pub struct SetOwnerArgs {
pub new_owner: AccountId,
}

/// Borsh-encoded parameters for the `set_upgrade_delay_blocks` function.
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
pub struct SetUpgradeDelayBlocksArgs {
pub upgrade_delay_blocks: u64,
}
Expand All @@ -117,14 +142,14 @@ pub struct SubmitArgs {
}

#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
pub struct StartHashchainArgs {
pub block_height: u64,
pub block_hashchain: RawH256,
}

/// Fungible token storage balance
#[derive(Default, Debug, serde::Serialize, serde::Deserialize)]
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct StorageBalance {
pub total: Yocto,
pub available: Yocto,
Expand All @@ -148,7 +173,7 @@ pub struct PausePrecompilesCallArgs {
}

#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
pub struct ResultLog {
pub address: Address,
pub topics: Vec<RawU256>,
Expand All @@ -157,7 +182,7 @@ pub struct ResultLog {

/// The status of a transaction.
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
pub enum TransactionStatus {
Succeed(Vec<u8>),
Revert(Vec<u8>),
Expand Down Expand Up @@ -203,7 +228,7 @@ impl AsRef<[u8]> for TransactionStatus {
/// Borsh-encoded parameters for the `call`, `call_with_args`, `deploy_code`,
/// and `deploy_with_input` methods.
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
pub struct SubmitResult {
version: u8,
pub status: TransactionStatus,
Expand Down Expand Up @@ -317,6 +342,27 @@ pub struct RelayerKeyArgs {

pub type FullAccessKeyArgs = RelayerKeyArgs;

mod chain_id_deserialize {
use crate::types::{u256_to_arr, RawU256};
use primitive_types::U256;
use serde::{Deserialize, Deserializer, Serializer};

pub fn deserialize<'de, D>(deserializer: D) -> Result<RawU256, D::Error>
where
D: Deserializer<'de>,
{
u64::deserialize(deserializer).map(|v| u256_to_arr(&(v.into())))
}

pub fn serialize<S>(value: &RawU256, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let chain_id = U256::from_big_endian(value.as_slice()).low_u64();
serializer.serialize_u64(chain_id)
}
}

pub mod errors {
use crate::{account_id::ParseAccountError, String, ToString};

Expand Down Expand Up @@ -431,4 +477,30 @@ mod tests {

assert_eq!(args.public_key, public_key);
}

#[test]
fn test_deserialize_new_call_args_json() {
let chain_id = 1_313_161_559;
let json = serde_json::json!({
"chain_id": chain_id,
"owner_id": "aurora",
"upgrade_delay_blocks": 10,
"key_manager": "manager.near",
"initial_hashchain": null
});
let arguments = NewCallArgs::deserialize(&serde_json::to_vec(&json).unwrap());
let Ok(NewCallArgs::V4(arguments)) = arguments else {
panic!("Wrong type of arguments");
};
let value = serde_json::to_value(arguments).unwrap();
assert_eq!(value.get("chain_id").unwrap().as_u64(), Some(chain_id));

let outdated = serde_json::json!({
"chain_id": chain_id,
"owner_id": "aurora",
"upgrade_delay_blocks": 19
});
let arguments = NewCallArgs::deserialize(&serde_json::to_vec(&outdated).unwrap());
assert!(matches!(arguments, Err(_)));
}
}

0 comments on commit 9d10373

Please sign in to comment.