Remove contracts RPCs (#12358)

* Remove contracts RPCs

* Remove serde as RPC serialization is no longer needed

* Rename folder to match crate name

* Compile fix

* Remove Byte wrapper
This commit is contained in:
Alexander Theißen
2022-10-02 17:16:45 +02:00
committed by GitHub
parent 54713ca17a
commit bb9d2fa75a
22 changed files with 103 additions and 792 deletions
+2 -24
View File
@@ -3371,7 +3371,7 @@ dependencies = [
"pallet-collective",
"pallet-contracts",
"pallet-contracts-primitives",
"pallet-contracts-rpc-runtime-api",
"pallet-contracts-runtime-api",
"pallet-conviction-voting",
"pallet-democracy",
"pallet-election-provider-multi-phase",
@@ -4825,7 +4825,6 @@ version = "3.0.0-dev"
dependencies = [
"jsonrpsee",
"node-primitives",
"pallet-contracts-rpc",
"pallet-mmr-rpc",
"pallet-transaction-payment-rpc",
"sc-chain-spec",
@@ -5530,10 +5529,6 @@ version = "6.0.0"
dependencies = [
"bitflags",
"parity-scale-codec",
"scale-info",
"serde",
"sp-core",
"sp-rpc",
"sp-runtime",
"sp-std",
]
@@ -5548,24 +5543,7 @@ dependencies = [
]
[[package]]
name = "pallet-contracts-rpc"
version = "4.0.0-dev"
dependencies = [
"jsonrpsee",
"pallet-contracts-primitives",
"pallet-contracts-rpc-runtime-api",
"parity-scale-codec",
"serde",
"serde_json",
"sp-api",
"sp-blockchain",
"sp-core",
"sp-rpc",
"sp-runtime",
]
[[package]]
name = "pallet-contracts-rpc-runtime-api"
name = "pallet-contracts-runtime-api"
version = "4.0.0-dev"
dependencies = [
"pallet-contracts-primitives",
+2 -2
View File
@@ -86,8 +86,8 @@ members = [
"frame/child-bounties",
"frame/collective",
"frame/contracts",
"frame/contracts/rpc",
"frame/contracts/rpc/runtime-api",
"frame/contracts/primitives",
"frame/contracts/runtime-api",
"frame/conviction-voting",
"frame/democracy",
"frame/fast-unstake",
-1
View File
@@ -14,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
jsonrpsee = { version = "0.15.1", features = ["server"] }
node-primitives = { version = "2.0.0", path = "../primitives" }
pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" }
pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" }
pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/rpc/" }
sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" }
-3
View File
@@ -108,7 +108,6 @@ where
+ Send
+ 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
C::Api: pallet_mmr_rpc::MmrRuntimeApi<Block, <Block as sp_runtime::traits::Block>::Hash>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: BabeApi<Block>,
@@ -118,7 +117,6 @@ where
B: sc_client_api::Backend<Block> + Send + Sync + 'static,
B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
{
use pallet_contracts_rpc::{Contracts, ContractsApiServer};
use pallet_mmr_rpc::{Mmr, MmrApiServer};
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use sc_consensus_babe_rpc::{Babe, BabeApiServer};
@@ -150,7 +148,6 @@ where
// Making synchronous calls in light client freezes the browser currently,
// more context: https://github.com/paritytech/substrate/pull/3480
// These RPCs should use an asynchronous caller instead.
io.merge(Contracts::new(client.clone()).into_rpc())?;
io.merge(Mmr::new(client.clone()).into_rpc())?;
io.merge(TransactionPayment::new(client.clone()).into_rpc())?;
io.merge(
+3 -3
View File
@@ -61,8 +61,8 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../
pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" }
pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" }
pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" }
pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/common/" }
pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" }
pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/primitives/" }
pallet-contracts-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/runtime-api/" }
pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" }
pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" }
pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" }
@@ -139,7 +139,7 @@ std = [
"pallet-collective/std",
"pallet-contracts/std",
"pallet-contracts-primitives/std",
"pallet-contracts-rpc-runtime-api/std",
"pallet-contracts-runtime-api/std",
"pallet-conviction-voting/std",
"pallet-democracy/std",
"pallet-elections-phragmen/std",
+1 -1
View File
@@ -1942,7 +1942,7 @@ impl_runtime_apis! {
}
}
impl pallet_contracts_rpc_runtime_api::ContractsApi<
impl pallet_contracts_runtime_api::ContractsApi<
Block, AccountId, Balance, BlockNumber, Hash,
>
for Runtime
+1 -1
View File
@@ -36,7 +36,7 @@ rand_pcg = { version = "0.3", optional = true }
frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true }
frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "common" }
pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "primitives" }
pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" }
sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" }
sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
@@ -15,23 +15,15 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
bitflags = "1.0"
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "2.0.0", default-features = false, features = ["derive"] }
serde = { version = "1", features = ["derive"], optional = true }
# Substrate Dependencies (This crate should not rely on frame)
sp-core = { version = "6.0.0", path = "../../../primitives/core", default-features = false }
sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" }
sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc", optional = true }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" }
[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"sp-rpc",
"serde",
]
@@ -21,32 +21,16 @@
use bitflags::bitflags;
use codec::{Decode, Encode};
use sp_core::Bytes;
use sp_runtime::{
traits::{Saturating, Zero},
DispatchError, RuntimeDebug,
};
use sp_std::prelude::*;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use sp_rpc::number::NumberOrHex;
/// Result type of a `bare_call` or `bare_instantiate` call.
///
/// It contains the execution result together with some auxiliary information.
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "std",
serde(
rename_all = "camelCase",
bound(serialize = "R: Serialize, Balance: Copy + Into<NumberOrHex>"),
bound(deserialize = "R: Deserialize<'de>, Balance: TryFrom<NumberOrHex>")
)
)]
pub struct ContractResult<R, Balance> {
/// How much gas was consumed during execution.
pub gas_consumed: u64,
@@ -80,7 +64,6 @@ pub struct ContractResult<R, Balance> {
///
/// The debug message is never generated during on-chain execution. It is reserved for
/// RPC calls.
#[cfg_attr(feature = "std", serde(with = "as_string"))]
pub debug_message: Vec<u8>,
/// The execution result of the wasm code.
pub result: R,
@@ -113,8 +96,6 @@ pub enum ContractAccessError {
bitflags! {
/// Flags used by a contract to customize exit behaviour.
#[derive(Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase", transparent))]
pub struct ReturnFlags: u32 {
/// If this bit is set all changes made by the contract execution are rolled back.
const REVERT = 0x0000_0001;
@@ -123,13 +104,11 @@ bitflags! {
/// Output of a contract call or instantiation which ran to completion.
#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct ExecReturnValue {
/// Flags passed along by `seal_return`. Empty when `seal_return` was never called.
pub flags: ReturnFlags,
/// Buffer passed along by `seal_return`. Empty when `seal_return` was never called.
pub data: Bytes,
pub data: Vec<u8>,
}
impl ExecReturnValue {
@@ -141,8 +120,6 @@ impl ExecReturnValue {
/// The result of a successful contract instantiation.
#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct InstantiateReturnValue<AccountId> {
/// The output of the called constructor.
pub result: ExecReturnValue,
@@ -152,63 +129,40 @@ pub struct InstantiateReturnValue<AccountId> {
/// The result of succesfully uploading a contract.
#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "std",
serde(
rename_all = "camelCase",
bound(serialize = "CodeHash: Serialize, Balance: Copy + Into<NumberOrHex>"),
bound(deserialize = "CodeHash: Deserialize<'de>, Balance: TryFrom<NumberOrHex>")
)
)]
pub struct CodeUploadReturnValue<CodeHash, Balance> {
/// The key under which the new code is stored.
pub code_hash: CodeHash,
/// The deposit that was reserved at the caller. Is zero when the code already existed.
#[cfg_attr(feature = "std", serde(with = "as_hex"))]
pub deposit: Balance,
}
/// Reference to an existing code hash or a new wasm module.
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub enum Code<Hash> {
/// A wasm module as raw bytes.
Upload(Bytes),
Upload(Vec<u8>),
/// The code hash of an on-chain wasm blob.
Existing(Hash),
}
impl<T: Into<Vec<u8>>, Hash> From<T> for Code<Hash> {
fn from(from: T) -> Self {
Code::Upload(Bytes(from.into()))
Code::Upload(from.into())
}
}
/// The amount of balance that was either charged or refunded in order to pay for storage.
#[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "std",
serde(
rename_all = "camelCase",
bound(serialize = "Balance: Copy + Into<NumberOrHex>"),
bound(deserialize = "Balance: TryFrom<NumberOrHex>")
)
)]
pub enum StorageDeposit<Balance> {
/// The transaction reduced storage consumption.
///
/// This means that the specified amount of balance was transferred from the involved
/// contracts to the call origin.
#[cfg_attr(feature = "std", serde(with = "as_hex"))]
Refund(Balance),
/// The transaction increased overall storage usage.
///
/// This means that the specified amount of balance was transferred from the call origin
/// to the contracts involved.
#[cfg_attr(feature = "std", serde(with = "as_hex"))]
Charge(Balance),
}
@@ -295,42 +249,3 @@ where
}
}
}
#[cfg(feature = "std")]
mod as_string {
use super::*;
use serde::{ser::Error, Deserializer, Serializer};
pub fn serialize<S: Serializer>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error> {
std::str::from_utf8(bytes)
.map_err(|e| S::Error::custom(format!("Debug buffer contains invalid UTF8: {}", e)))?
.serialize(serializer)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
Ok(String::deserialize(deserializer)?.into_bytes())
}
}
#[cfg(feature = "std")]
mod as_hex {
use super::*;
use serde::{de::Error as _, Deserializer, Serializer};
pub fn serialize<S, Balance>(balance: &Balance, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Balance: Copy + Into<NumberOrHex>,
{
Into::<NumberOrHex>::into(*balance).serialize(serializer)
}
pub fn deserialize<'de, D, Balance>(deserializer: D) -> Result<Balance, D::Error>
where
D: Deserializer<'de>,
Balance: TryFrom<NumberOrHex>,
{
Balance::try_from(NumberOrHex::deserialize(deserializer)?)
.map_err(|_| D::Error::custom("Cannot decode NumberOrHex to Balance"))
}
}
-30
View File
@@ -1,30 +0,0 @@
[package]
name = "pallet-contracts-rpc"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "Node-specific RPC methods for interaction with contracts."
readme = "README.md"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0" }
jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
serde = { version = "1", features = ["derive"] }
# Substrate Dependencies
pallet-contracts-primitives = { version = "6.0.0", path = "../common" }
pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" }
sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
sp-core = { version = "6.0.0", path = "../../../primitives/core" }
sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" }
sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" }
[dev-dependencies]
serde_json = "1"
-3
View File
@@ -1,3 +0,0 @@
Node-specific RPC methods for interaction with contracts.
License: Apache-2.0
@@ -1,7 +0,0 @@
Runtime API definition required by Contracts RPC extensions.
This API should be imported and implemented by the runtime,
of a node that wants to use the custom RPC extension
adding Contracts access methods.
License: Apache-2.0
-524
View File
@@ -1,524 +0,0 @@
// This file is part of Substrate.
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Node-specific RPC methods for interaction with contracts.
#![warn(unused_crate_dependencies)]
use std::{marker::PhantomData, sync::Arc};
use codec::Codec;
use jsonrpsee::{
core::{async_trait, Error as JsonRpseeError, RpcResult},
proc_macros::rpc,
types::error::{CallError, ErrorCode, ErrorObject},
};
use pallet_contracts_primitives::{
Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult,
};
use serde::{Deserialize, Serialize};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_core::Bytes;
use sp_rpc::number::NumberOrHex;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT},
};
pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi;
const RUNTIME_ERROR: i32 = 1;
const CONTRACT_DOESNT_EXIST: i32 = 2;
const KEY_DECODING_FAILED: i32 = 3;
pub type Weight = u64;
/// A rough estimate of how much gas a decent hardware consumes per second,
/// using native execution.
/// This value is used to set the upper bound for maximal contract calls to
/// prevent blocking the RPC for too long.
///
/// As 1 gas is equal to 1 weight we base this on the conducted benchmarks which
/// determined runtime weights:
/// <https://github.com/paritytech/substrate/pull/5446>
const GAS_PER_SECOND: Weight = 1_000_000_000_000;
/// The maximum amount of weight that the call and instantiate rpcs are allowed to consume.
/// This puts a ceiling on the weight limit that is supplied to the rpc as an argument.
const GAS_LIMIT: Weight = 5 * GAS_PER_SECOND;
/// A private newtype for converting `ContractAccessError` into an RPC error.
struct ContractAccessError(pallet_contracts_primitives::ContractAccessError);
impl From<ContractAccessError> for JsonRpseeError {
fn from(e: ContractAccessError) -> Self {
use pallet_contracts_primitives::ContractAccessError::*;
match e.0 {
DoesntExist => CallError::Custom(ErrorObject::owned(
CONTRACT_DOESNT_EXIST,
"The specified contract doesn't exist.",
None::<()>,
))
.into(),
KeyDecodingFailed => CallError::Custom(ErrorObject::owned(
KEY_DECODING_FAILED,
"Failed to decode the specified storage key.",
None::<()>,
))
.into(),
}
}
}
/// A struct that encodes RPC parameters required for a call to a smart-contract.
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct CallRequest<AccountId> {
origin: AccountId,
dest: AccountId,
value: NumberOrHex,
gas_limit: NumberOrHex,
storage_deposit_limit: Option<NumberOrHex>,
input_data: Bytes,
}
/// A struct that encodes RPC parameters required to instantiate a new smart-contract.
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct InstantiateRequest<AccountId, Hash> {
origin: AccountId,
value: NumberOrHex,
gas_limit: NumberOrHex,
storage_deposit_limit: Option<NumberOrHex>,
code: Code<Hash>,
data: Bytes,
salt: Bytes,
}
/// A struct that encodes RPC parameters required for a call to upload a new code.
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct CodeUploadRequest<AccountId> {
origin: AccountId,
code: Bytes,
storage_deposit_limit: Option<NumberOrHex>,
}
/// Contracts RPC methods.
#[rpc(client, server)]
pub trait ContractsApi<BlockHash, BlockNumber, AccountId, Balance, Hash>
where
Balance: Copy + TryFrom<NumberOrHex> + Into<NumberOrHex>,
{
/// Executes a call to a contract.
///
/// This call is performed locally without submitting any transactions. Thus executing this
/// won't change any state. Nonetheless, the calling state-changing contracts is still possible.
///
/// This method is useful for calling getter-like methods on contracts or to dry-run a
/// a contract call in order to determine the `gas_limit`.
#[method(name = "contracts_call")]
fn call(
&self,
call_request: CallRequest<AccountId>,
at: Option<BlockHash>,
) -> RpcResult<ContractExecResult<Balance>>;
/// Instantiate a new contract.
///
/// This instantiate is performed locally without submitting any transactions. Thus the contract
/// is not actually created.
///
/// This method is useful for UIs to dry-run contract instantiations.
#[method(name = "contracts_instantiate")]
fn instantiate(
&self,
instantiate_request: InstantiateRequest<AccountId, Hash>,
at: Option<BlockHash>,
) -> RpcResult<ContractInstantiateResult<AccountId, Balance>>;
/// Upload new code without instantiating a contract from it.
///
/// This upload is performed locally without submitting any transactions. Thus executing this
/// won't change any state.
///
/// This method is useful for UIs to dry-run code upload.
#[method(name = "contracts_upload_code")]
fn upload_code(
&self,
upload_request: CodeUploadRequest<AccountId>,
at: Option<BlockHash>,
) -> RpcResult<CodeUploadResult<Hash, Balance>>;
/// Returns the value under a specified storage `key` in a contract given by `address` param,
/// or `None` if it is not set.
#[method(name = "contracts_getStorage")]
fn get_storage(
&self,
address: AccountId,
key: Bytes,
at: Option<BlockHash>,
) -> RpcResult<Option<Bytes>>;
}
/// Contracts RPC methods.
pub struct Contracts<Client, Block> {
client: Arc<Client>,
_marker: PhantomData<Block>,
}
impl<Client, Block> Contracts<Client, Block> {
/// Create new `Contracts` with the given reference to the client.
pub fn new(client: Arc<Client>) -> Self {
Self { client, _marker: Default::default() }
}
}
#[async_trait]
impl<Client, Block, AccountId, Balance, Hash>
ContractsApiServer<
<Block as BlockT>::Hash,
<<Block as BlockT>::Header as HeaderT>::Number,
AccountId,
Balance,
Hash,
> for Contracts<Client, Block>
where
Block: BlockT,
Client: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
Client::Api: ContractsRuntimeApi<
Block,
AccountId,
Balance,
<<Block as BlockT>::Header as HeaderT>::Number,
Hash,
>,
AccountId: Codec,
Balance: Codec + Copy + TryFrom<NumberOrHex> + Into<NumberOrHex>,
Hash: Codec,
{
fn call(
&self,
call_request: CallRequest<AccountId>,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<ContractExecResult<Balance>> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(||
// If the block hash is not supplied assume the best block.
self.client.info().best_hash));
let CallRequest { origin, dest, value, gas_limit, storage_deposit_limit, input_data } =
call_request;
let value: Balance = decode_hex(value, "balance")?;
let gas_limit: u64 = decode_hex(gas_limit, "weight")?;
let storage_deposit_limit: Option<Balance> =
storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?;
limit_gas(gas_limit)?;
api.call(&at, origin, dest, value, gas_limit, storage_deposit_limit, input_data.to_vec())
.map_err(runtime_error_into_rpc_err)
}
fn instantiate(
&self,
instantiate_request: InstantiateRequest<AccountId, Hash>,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<ContractInstantiateResult<AccountId, Balance>> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(||
// If the block hash is not supplied assume the best block.
self.client.info().best_hash));
let InstantiateRequest {
origin,
value,
gas_limit,
storage_deposit_limit,
code,
data,
salt,
} = instantiate_request;
let value: Balance = decode_hex(value, "balance")?;
let gas_limit: u64 = decode_hex(gas_limit, "weight")?;
let storage_deposit_limit: Option<Balance> =
storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?;
limit_gas(gas_limit)?;
api.instantiate(
&at,
origin,
value,
gas_limit,
storage_deposit_limit,
code,
data.to_vec(),
salt.to_vec(),
)
.map_err(runtime_error_into_rpc_err)
}
fn upload_code(
&self,
upload_request: CodeUploadRequest<AccountId>,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<CodeUploadResult<Hash, Balance>> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(||
// If the block hash is not supplied assume the best block.
self.client.info().best_hash));
let CodeUploadRequest { origin, code, storage_deposit_limit } = upload_request;
let storage_deposit_limit: Option<Balance> =
storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?;
api.upload_code(&at, origin, code.to_vec(), storage_deposit_limit)
.map_err(runtime_error_into_rpc_err)
}
fn get_storage(
&self,
address: AccountId,
key: Bytes,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Option<Bytes>> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));
let result = api
.get_storage(&at, address, key.to_vec())
.map_err(runtime_error_into_rpc_err)?
.map_err(ContractAccessError)?
.map(Bytes);
Ok(result)
}
}
/// Converts a runtime trap into an RPC error.
fn runtime_error_into_rpc_err(err: impl std::fmt::Debug) -> JsonRpseeError {
CallError::Custom(ErrorObject::owned(
RUNTIME_ERROR,
"Runtime error",
Some(format!("{:?}", err)),
))
.into()
}
fn decode_hex<H: std::fmt::Debug + Copy, T: TryFrom<H>>(from: H, name: &str) -> RpcResult<T> {
from.try_into().map_err(|_| {
JsonRpseeError::Call(CallError::Custom(ErrorObject::owned(
ErrorCode::InvalidParams.code(),
format!("{:?} does not fit into the {} type", from, name),
None::<()>,
)))
})
}
fn limit_gas(gas_limit: Weight) -> RpcResult<()> {
if gas_limit > GAS_LIMIT {
Err(JsonRpseeError::Call(CallError::Custom(ErrorObject::owned(
ErrorCode::InvalidParams.code(),
format!(
"Requested gas limit is greater than maximum allowed: {} > {}",
gas_limit, GAS_LIMIT
),
None::<()>,
))))
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use pallet_contracts_primitives::{ContractExecResult, ContractInstantiateResult};
use sp_core::U256;
fn trim(json: &str) -> String {
json.chars().filter(|c| !c.is_whitespace()).collect()
}
#[test]
fn call_request_should_serialize_deserialize_properly() {
type Req = CallRequest<String>;
let req: Req = serde_json::from_str(
r#"
{
"origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
"dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom",
"value": "0x112210f4B16c1cb1",
"gasLimit": 1000000000000,
"storageDepositLimit": 5000,
"inputData": "0x8c97db39"
}
"#,
)
.unwrap();
assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64));
assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into()));
assert_eq!(req.value.into_u256(), U256::from(1234567890987654321u128));
}
#[test]
fn instantiate_request_should_serialize_deserialize_properly() {
type Req = InstantiateRequest<String, String>;
let req: Req = serde_json::from_str(
r#"
{
"origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
"value": "0x88",
"gasLimit": 42,
"code": { "existing": "0x1122" },
"data": "0x4299",
"salt": "0x9988"
}
"#,
)
.unwrap();
assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL");
assert_eq!(req.value.into_u256(), 0x88.into());
assert_eq!(req.gas_limit.into_u256(), 42.into());
assert_eq!(req.storage_deposit_limit, None);
assert_eq!(&*req.data, [0x42, 0x99].as_ref());
assert_eq!(&*req.salt, [0x99, 0x88].as_ref());
let code = match req.code {
Code::Existing(hash) => hash,
_ => panic!("json encoded an existing hash"),
};
assert_eq!(&code, "0x1122");
}
#[test]
fn code_upload_request_should_serialize_deserialize_properly() {
type Req = CodeUploadRequest<String>;
let req: Req = serde_json::from_str(
r#"
{
"origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
"code": "0x8c97db39",
"storageDepositLimit": 5000
}
"#,
)
.unwrap();
assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL");
assert_eq!(&*req.code, [0x8c, 0x97, 0xdb, 0x39].as_ref());
assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into()));
}
#[test]
fn call_result_should_serialize_deserialize_properly() {
fn test(expected: &str) {
let res: ContractExecResult<u32> = serde_json::from_str(expected).unwrap();
let actual = serde_json::to_string(&res).unwrap();
assert_eq!(actual, trim(expected).as_str());
}
test(
r#"{
"gasConsumed": 5000,
"gasRequired": 8000,
"storageDeposit": {"charge": 42000},
"debugMessage": "HelloWorld",
"result": {
"Ok": {
"flags": 5,
"data": "0x1234"
}
}
}"#,
);
test(
r#"{
"gasConsumed": 3400,
"gasRequired": 5200,
"storageDeposit": {"refund": 12000},
"debugMessage": "HelloWorld",
"result": {
"Err": "BadOrigin"
}
}"#,
);
}
#[test]
fn instantiate_result_should_serialize_deserialize_properly() {
fn test(expected: &str) {
let res: ContractInstantiateResult<String, u32> =
serde_json::from_str(expected).unwrap();
let actual = serde_json::to_string(&res).unwrap();
assert_eq!(actual, trim(expected).as_str());
}
test(
r#"{
"gasConsumed": 5000,
"gasRequired": 8000,
"storageDeposit": {"refund": 12000},
"debugMessage": "HelloWorld",
"result": {
"Ok": {
"result": {
"flags": 5,
"data": "0x1234"
},
"accountId": "5CiPP"
}
}
}"#,
);
test(
r#"{
"gasConsumed": 3400,
"gasRequired": 5200,
"storageDeposit": {"charge": 0},
"debugMessage": "HelloWorld",
"result": {
"Err": "BadOrigin"
}
}"#,
);
}
#[test]
fn code_upload_result_should_serialize_deserialize_properly() {
fn test(expected: &str) {
let res: CodeUploadResult<u32, u32> = serde_json::from_str(expected).unwrap();
let actual = serde_json::to_string(&res).unwrap();
assert_eq!(actual, trim(expected).as_str());
}
test(
r#"{
"Ok": {
"codeHash": 4711,
"deposit": 99
}
}"#,
);
test(
r#"{
"Err": "BadOrigin"
}"#,
);
}
}
@@ -1,12 +1,12 @@
[package]
name = "pallet-contracts-rpc-runtime-api"
name = "pallet-contracts-runtime-api"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "Runtime API definition required by Contracts RPC extensions."
description = "Runtime API definition used to provide dry-run capabilities"
readme = "README.md"
[package.metadata.docs.rs]
@@ -17,10 +17,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features =
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
# Substrate Dependencies
pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../common" }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" }
pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../primitives" }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" }
[features]
default = ["std"]
@@ -0,0 +1,7 @@
Runtime API definition used to provide dry-run capabilities
This API should be imported and implemented by the runtime,
of a node that wants to provide clients with dry-run
capabilities.
License: Apache-2.0
@@ -15,11 +15,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Runtime API definition required by Contracts RPC extensions.
//! Runtime API definition used to provide dry-run capabilities.
//!
//! This API should be imported and implemented by the runtime,
//! of a node that wants to use the custom RPC extension
//! adding Contracts access methods.
//! of a node that wants to provide clients with dry-run
//! capabilities.
#![cfg_attr(not(feature = "std"), no_std)]
+13 -14
View File
@@ -1384,7 +1384,6 @@ mod tests {
use frame_system::{EventRecord, Phase};
use pallet_contracts_primitives::ReturnFlags;
use pretty_assertions::assert_eq;
use sp_core::Bytes;
use sp_runtime::{traits::Hash, DispatchError};
use std::{
cell::RefCell,
@@ -1517,7 +1516,7 @@ mod tests {
}
fn exec_success() -> ExecResult {
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) })
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
}
fn exec_trapped() -> ExecResult {
@@ -1586,7 +1585,7 @@ mod tests {
let success_ch = MockLoader::insert(Call, move |ctx, _| {
assert_eq!(ctx.ext.value_transferred(), value);
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) })
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
});
ExtBuilder::default().build().execute_with(|| {
@@ -1621,13 +1620,13 @@ mod tests {
let success_ch = MockLoader::insert(Call, move |ctx, _| {
assert_eq!(ctx.ext.value_transferred(), value);
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) })
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
});
let delegate_ch = MockLoader::insert(Call, move |ctx, _| {
assert_eq!(ctx.ext.value_transferred(), value);
let _ = ctx.ext.delegate_call(success_ch, Vec::new())?;
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) })
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
});
ExtBuilder::default().build().execute_with(|| {
@@ -1662,7 +1661,7 @@ mod tests {
let dest = BOB;
let return_ch = MockLoader::insert(Call, |_, _| {
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(Vec::new()) })
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() })
});
ExtBuilder::default().build().execute_with(|| {
@@ -1715,7 +1714,7 @@ mod tests {
let origin = ALICE;
let dest = BOB;
let return_ch = MockLoader::insert(Call, |_, _| {
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![1, 2, 3, 4]) })
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] })
});
ExtBuilder::default().build().execute_with(|| {
@@ -1736,7 +1735,7 @@ mod tests {
let output = result.unwrap();
assert!(!output.did_revert());
assert_eq!(output.data, Bytes(vec![1, 2, 3, 4]));
assert_eq!(output.data, vec![1, 2, 3, 4]);
});
}
@@ -1747,7 +1746,7 @@ mod tests {
let origin = ALICE;
let dest = BOB;
let return_ch = MockLoader::insert(Call, |_, _| {
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(vec![1, 2, 3, 4]) })
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![1, 2, 3, 4] })
});
ExtBuilder::default().build().execute_with(|| {
@@ -1768,7 +1767,7 @@ mod tests {
let output = result.unwrap();
assert!(output.did_revert());
assert_eq!(output.data, Bytes(vec![1, 2, 3, 4]));
assert_eq!(output.data, vec![1, 2, 3, 4]);
});
}
@@ -2115,7 +2114,7 @@ mod tests {
#[test]
fn instantiation_work_with_success_output() {
let dummy_ch = MockLoader::insert(Constructor, |_, _| {
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![80, 65, 83, 83]) })
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![80, 65, 83, 83] })
});
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
@@ -2140,7 +2139,7 @@ mod tests {
&[],
None,
),
Ok((address, ref output)) if output.data == Bytes(vec![80, 65, 83, 83]) => address
Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address
);
// Check that the newly created account has the expected code hash and
@@ -2159,7 +2158,7 @@ mod tests {
#[test]
fn instantiation_fails_with_failing_output() {
let dummy_ch = MockLoader::insert(Constructor, |_, _| {
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(vec![70, 65, 73, 76]) })
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70, 65, 73, 76] })
});
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
@@ -2184,7 +2183,7 @@ mod tests {
&[],
None,
),
Ok((address, ref output)) if output.data == Bytes(vec![70, 65, 73, 76]) => address
Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address
);
// Check that the account has not been created.
+4 -4
View File
@@ -123,7 +123,7 @@ use pallet_contracts_primitives::{
StorageDeposit,
};
use scale_info::TypeInfo;
use sp_core::{crypto::UncheckedFrom, Bytes};
use sp_core::crypto::UncheckedFrom;
use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup};
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
@@ -512,7 +512,7 @@ pub mod pallet {
value,
gas_limit,
storage_deposit_limit.map(Into::into),
Code::Upload(Bytes(code)),
Code::Upload(code),
data,
salt,
None,
@@ -743,7 +743,7 @@ pub mod pallet {
value,
gas_limit,
storage_deposit_limit.map(Into::into),
Code::Upload(Bytes(code)),
Code::Upload(code),
data,
salt,
None,
@@ -1234,7 +1234,7 @@ where
let try_exec = || {
let schedule = T::Schedule::get();
let (extra_deposit, executable) = match code {
Code::Upload(Bytes(binary)) => {
Code::Upload(binary) => {
let executable = PrefabWasmModule::from_code(binary, &schedule, origin.clone())
.map_err(|(err, msg)| {
debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes()));
+7 -8
View File
@@ -44,7 +44,6 @@ use frame_support::{
};
use frame_system::{self as system, EventRecord, Phase};
use pretty_assertions::{assert_eq, assert_ne};
use sp_core::Bytes;
use sp_io::hashing::blake2_256;
use sp_keystore::{testing::KeyStore, KeystoreExt};
use sp_runtime::{
@@ -1722,7 +1721,7 @@ fn chain_extension_works() {
let result =
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false);
assert_eq!(TestExtension::last_seen_buffer(), input);
assert_eq!(result.result.unwrap().data, Bytes(input));
assert_eq!(result.result.unwrap().data, input);
// 1 = treat inputs as integer primitives and store the supplied integers
Contracts::bare_call(
@@ -1787,7 +1786,7 @@ fn chain_extension_works() {
.result
.unwrap();
assert_eq!(result.flags, ReturnFlags::REVERT);
assert_eq!(result.data, Bytes(vec![42, 99]));
assert_eq!(result.data, vec![42, 99]);
// diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer
// We set the MSB part to 1 (instead of 0) which routes the request into the second
@@ -1804,7 +1803,7 @@ fn chain_extension_works() {
.result
.unwrap();
assert_eq!(result.flags, ReturnFlags::REVERT);
assert_eq!(result.data, Bytes(vec![0x4B, 0x1D]));
assert_eq!(result.data, vec![0x4B, 0x1D]);
// Diverging to third chain extension that is disabled
// We set the MSB part to 2 (instead of 0) which routes the request into the third extension
@@ -2672,7 +2671,7 @@ fn ecdsa_recover() {
.result
.unwrap();
assert!(!result.did_revert());
assert_eq!(result.data.as_ref(), &EXPECTED_COMPRESSED_PUBLIC_KEY);
assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY);
})
}
@@ -3503,7 +3502,7 @@ fn contract_reverted() {
.result
.unwrap();
assert_eq!(result.result.flags, flags);
assert_eq!(result.result.data.0, buffer);
assert_eq!(result.result.data, buffer);
assert!(!<ContractInfoOf<Test>>::contains_key(result.account_id));
// Pass empty flags and therefore successfully instantiate the contract for later use.
@@ -3539,7 +3538,7 @@ fn contract_reverted() {
.result
.unwrap();
assert_eq!(result.flags, flags);
assert_eq!(result.data.0, buffer);
assert_eq!(result.data, buffer);
});
}
@@ -3559,7 +3558,7 @@ fn code_rejected_error_works() {
0,
GAS_LIMIT,
None,
Code::Upload(Bytes(wasm)),
Code::Upload(wasm),
vec![],
vec![],
true,
+46 -57
View File
@@ -281,7 +281,7 @@ mod tests {
};
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
use pretty_assertions::assert_eq;
use sp_core::{Bytes, H256};
use sp_core::H256;
use sp_runtime::DispatchError;
use std::{
borrow::BorrowMut,
@@ -341,8 +341,8 @@ mod tests {
}
/// The call is mocked and just returns this hardcoded value.
fn call_return_data() -> Bytes {
Bytes(vec![0xDE, 0xAD, 0xBE, 0xEF])
fn call_return_data() -> Vec<u8> {
vec![0xDE, 0xAD, 0xBE, 0xEF]
}
impl Default for MockExt {
@@ -404,7 +404,7 @@ mod tests {
});
Ok((
Contracts::<Test>::contract_address(&ALICE, &code_hash, salt),
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) },
ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() },
))
}
fn set_code_hash(&mut self, hash: CodeHash<Self::T>) -> Result<(), DispatchError> {
@@ -804,7 +804,7 @@ mod tests {
let mut mock_ext = MockExt::default();
let input = vec![0xff, 0x2a, 0x99, 0x88];
let result = execute(CODE, input.clone(), &mut mock_ext).unwrap();
assert_eq!(result.data.0, input);
assert_eq!(result.data, input);
assert_eq!(
&mock_ext.calls,
&[CallEntry { to: ALICE, value: 0x2a, data: input, allows_reentry: true }]
@@ -907,15 +907,15 @@ mod tests {
// value does not exist -> sentinel value returned
let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
// value did exist -> success
let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1,);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1,);
// value did exist -> success (zero sized type)
let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0,);
}
#[test]
@@ -977,13 +977,13 @@ mod tests {
let input = (63, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// sentinel returned
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
// value exists
let input = (64, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// true as u32 returned
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1);
// getter does not remove the value from storage
assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]);
@@ -991,7 +991,7 @@ mod tests {
let input = (19, [2u8; 19]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// true as u32 returned
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
// getter does not remove the value from storage
assert_eq!(ext.storage.get(&[2u8; 19].to_vec()).unwrap(), &([] as [u8; 0]));
}
@@ -1234,7 +1234,7 @@ mod tests {
let output = execute(CODE_ECDSA_TO_ETH_ADDRESS, vec![], MockExt::default()).unwrap();
assert_eq!(
output,
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x02; 20].to_vec()) }
ExecReturnValue { flags: ReturnFlags::empty(), data: [0x02; 20].to_vec() }
);
}
@@ -1311,7 +1311,7 @@ mod tests {
assert_eq!(
output,
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x22; 32].to_vec()) }
ExecReturnValue { flags: ReturnFlags::empty(), data: [0x22; 32].to_vec() }
);
}
@@ -1630,10 +1630,7 @@ mod tests {
fn return_from_start_fn() {
let output = execute(CODE_RETURN_FROM_START_FN, vec![], MockExt::default()).unwrap();
assert_eq!(
output,
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![1, 2, 3, 4]) }
);
assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] });
}
const CODE_TIMESTAMP_NOW: &str = r#"
@@ -1902,15 +1899,13 @@ mod tests {
output,
ExecReturnValue {
flags: ReturnFlags::empty(),
data: Bytes(
(
array_bytes::hex2array_unchecked::<32>(
"000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
),
42u64,
)
.encode()
),
data: (
array_bytes::hex2array_unchecked::<32>(
"000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
),
42u64,
)
.encode()
},
);
}
@@ -2124,7 +2119,7 @@ mod tests {
output,
ExecReturnValue {
flags: ReturnFlags::empty(),
data: Bytes(array_bytes::hex2bytes_unchecked("445566778899")),
data: array_bytes::hex2bytes_unchecked("445566778899"),
}
);
assert!(!output.did_revert());
@@ -2143,7 +2138,7 @@ mod tests {
output,
ExecReturnValue {
flags: ReturnFlags::REVERT,
data: Bytes(array_bytes::hex2bytes_unchecked("5566778899")),
data: array_bytes::hex2bytes_unchecked("5566778899"),
}
);
assert!(output.did_revert());
@@ -2306,7 +2301,7 @@ mod tests {
let result = execute(CODE_CALL_RUNTIME, call.encode(), &mut ext).unwrap();
assert_eq!(*ext.runtime_calls.borrow(), vec![call]);
// 0 = ReturnCode::Success
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
}
#[test]
@@ -2371,19 +2366,19 @@ mod tests {
// value did not exist before -> sentinel returned
let input = ([1u8; 32], [42u8, 48]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]);
// value do exist -> length of old value returned
let input = ([1u8; 32], [0u8; 0]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2);
assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]);
// value do exist -> length of old value returned (test for zero sized val)
let input = ([1u8; 32], [99u8]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]);
}
@@ -2442,19 +2437,19 @@ mod tests {
// value did not exist before -> sentinel returned
let input = (32, [1u8; 32], [42u8, 48]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]);
// value do exist -> length of old value returned
let input = (32, [1u8; 32], [0u8; 0]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2);
assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]);
// value do exist -> length of old value returned (test for zero sized val)
let input = (32, [1u8; 32], [99u8]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]);
}
@@ -2527,7 +2522,7 @@ mod tests {
let input = (63, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(
u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()),
u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
ReturnCode::KeyNotFound as u32
);
@@ -2535,21 +2530,21 @@ mod tests {
let input = (64, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(
u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()),
u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
ReturnCode::Success as u32
);
assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]);
assert_eq!(&result.data.0[4..], &[42u8]);
assert_eq!(&result.data[4..], &[42u8]);
// value exists (test for 0 sized)
let input = (19, [2u8; 19]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(
u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()),
u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
ReturnCode::Success as u32
);
assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), Some(&vec![]));
assert_eq!(&result.data.0[4..], &([] as [u8; 0]));
assert_eq!(&result.data[4..], &([] as [u8; 0]));
}
#[test]
@@ -2611,14 +2606,14 @@ mod tests {
let input = (32, [3u8; 32]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// sentinel returned
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
assert_eq!(ext.storage.get(&[3u8; 32].to_vec()), None);
// value did exist
let input = (64, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// length returned
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1);
// value cleared
assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None);
@@ -2626,14 +2621,14 @@ mod tests {
let input = (63, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// sentinel returned
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None);
// value exists
let input = (19, [2u8; 19]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
// length returned (test for 0 sized)
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0);
assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
// value cleared
assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None);
}
@@ -2710,7 +2705,7 @@ mod tests {
let input = (63, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(
u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()),
u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
ReturnCode::KeyNotFound as u32
);
@@ -2718,21 +2713,21 @@ mod tests {
let input = (64, [1u8; 64]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(
u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()),
u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
ReturnCode::Success as u32
);
assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None);
assert_eq!(&result.data.0[4..], &[42u8]);
assert_eq!(&result.data[4..], &[42u8]);
// value did exist -> length returned (test for 0 sized)
let input = (19, [2u8; 19]).encode();
let result = execute(CODE, input, &mut ext).unwrap();
assert_eq!(
u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()),
u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
ReturnCode::Success as u32
);
assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None);
assert_eq!(&result.data.0[4..], &[0u8; 0]);
assert_eq!(&result.data[4..], &[0u8; 0]);
}
#[test]
@@ -2769,10 +2764,7 @@ mod tests {
let output = execute(CODE_IS_CONTRACT, vec![], MockExt::default()).unwrap();
// The mock ext just always returns 1u32 (`true`).
assert_eq!(
output,
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(1u32.encode()) },
);
assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 1u32.encode() },);
}
#[test]
@@ -2906,10 +2898,7 @@ mod tests {
let output = execute(CODE_CALLER_IS_ORIGIN, vec![], MockExt::default()).unwrap();
// The mock ext just always returns 0u32 (`false`)
assert_eq!(
output,
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(0u32.encode()) },
);
assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 0u32.encode() },);
}
#[test]
@@ -30,7 +30,7 @@ use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight};
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
use pallet_contracts_proc_macro::define_env;
use sp_core::{crypto::UncheckedFrom, Bytes};
use sp_core::crypto::UncheckedFrom;
use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
use sp_runtime::traits::{Bounded, Zero};
use sp_sandbox::SandboxMemory;
@@ -483,10 +483,10 @@ where
TrapReason::Return(ReturnData { flags, data }) => {
let flags =
ReturnFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?;
Ok(ExecReturnValue { flags, data: Bytes(data) })
Ok(ExecReturnValue { flags, data })
},
TrapReason::Termination =>
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }),
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }),
TrapReason::SupervisorError(error) => return Err(error.into()),
}
}
@@ -494,7 +494,7 @@ where
// Check the exact type of the error.
match sandbox_result {
// No traps were generated. Proceed normally.
Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }),
Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }),
// `Error::Module` is returned only if instantiation or linking failed (i.e.
// wasm binary tried to import a function that is not provided by the host).
// This shouldn't happen because validation process ought to reject such binaries.
@@ -879,7 +879,7 @@ where
if let Ok(return_value) = call_outcome {
return Err(TrapReason::Return(ReturnData {
flags: return_value.flags.bits(),
data: return_value.data.0,
data: return_value.data,
}))
}
}