Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ members = [
"core/panic-handler",
"core/primitives",
"core/rpc",
"core/rpc/primitives",
"core/rpc-servers",
"core/serializer",
"core/service",
Expand Down
1 change: 1 addition & 0 deletions core/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ runtime_version = { package = "sr-version", path = "../sr-version" }
serde_json = "1.0"
session = { package = "substrate-session", path = "../session" }
sr-primitives = { path = "../sr-primitives" }
rpc-primitives = { package = "substrate-rpc-primitives", path = "primitives" }
state_machine = { package = "substrate-state-machine", path = "../state-machine" }
substrate-executor = { path = "../executor" }
substrate-keystore = { path = "../keystore" }
Expand Down
1 change: 1 addition & 0 deletions core/rpc/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ runtime_version = { package = "sr-version", path = "../../sr-version" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
txpool = { package = "substrate-transaction-graph", path = "../../transaction-pool/graph" }
rpc-primitives = { package = "substrate-rpc-primitives", path = "../../rpc/primitives" }
2 changes: 1 addition & 1 deletion core/rpc/api/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
//! Substrate blockchain API.

pub mod error;
pub mod number;

use jsonrpc_core::Result as RpcResult;
use jsonrpc_core::futures::Future;
use jsonrpc_derive::rpc;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use rpc_primitives::number;
use self::error::{FutureResult, Result};

pub use self::gen_client::Client as ChainClient;
Expand Down
9 changes: 9 additions & 0 deletions core/rpc/primitives/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "substrate-rpc-primitives"
version = "2.0.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
primitives = { package = "substrate-primitives", path = "../../primitives" }
21 changes: 21 additions & 0 deletions core/rpc/primitives/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

//! Substrate RPC primitives and utilities.

#![warn(missing_docs)]

pub mod number;
1 change: 1 addition & 0 deletions core/rpc/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use client::{
};
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use primitives::{H256, Blake2Hasher};
use rpc_primitives::number;
use sr_primitives::{
generic::{BlockId, SignedBlock},
traits::{Block as BlockT, Header, NumberFor},
Expand Down
10 changes: 8 additions & 2 deletions node/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,17 @@ pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisCo
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
)?
.with_rpc_extensions(|client, pool| {
use node_rpc::accounts::{Accounts, AccountsApi};
use node_rpc::{
accounts::{Accounts, AccountsApi},
contracts::{Contracts, ContractsApi},
};

let mut io = jsonrpc_core::IoHandler::default();
io.extend_with(
AccountsApi::to_delegate(Accounts::new(client, pool))
AccountsApi::to_delegate(Accounts::new(client.clone(), pool))
);
io.extend_with(
ContractsApi::to_delegate(Contracts::new(client))
);
io
})?
Expand Down
38 changes: 38 additions & 0 deletions node/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@

#![cfg_attr(not(feature = "std"), no_std)]

use rstd::prelude::*;
use sr_primitives::{
generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature
};

#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use codec::{Encode, Decode};

/// An index to a block.
pub type BlockNumber = u32;

Expand Down Expand Up @@ -67,10 +72,43 @@ pub type BlockId = generic::BlockId<Block>;
/// Opaque, encoded, unchecked extrinsic.
pub type UncheckedExtrinsic = OpaqueExtrinsic;

/// A result of execution of a contract.
#[derive(Eq, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum ContractExecResult {
/// The contract returned successfully.
///
/// There is a status code and, optionally, some data returned by the contract.
Success {
/// Status code returned by the contract.
status: u8,
/// Output data returned by the contract.
///
/// Can be empty.
data: Vec<u8>,
},
/// The contract execution either trapped or returned an error.
Error,
}

client::decl_runtime_apis! {
/// The API to query account account nonce (aka index).
pub trait AccountNonceApi {
/// Get current account nonce of given `AccountId`.
fn account_nonce(account: AccountId) -> Index;
}

/// The API to interact with contracts without using executive.
pub trait ContractsApi {
/// Perform a call from a specified account to a given contract.
///
/// See the contracts' `call` dispatchable function for more details.
fn call(
origin: AccountId,
dest: AccountId,
value: Balance,
gas_limit: u64,
input_data: Vec<u8>,
) -> ContractExecResult;
}
}
1 change: 1 addition & 0 deletions node/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ codec = { package = "parity-scale-codec", version = "1.0.0" }
serde = { version = "1.0", features = ["derive"] }
sr-primitives = { path = "../../core/sr-primitives" }
substrate-primitives = { path = "../../core/primitives" }
rpc-primitives = { package = "substrate-rpc-primitives", path = "../../core/rpc/primitives" }
transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" }

[dev-dependencies]
Expand Down
4 changes: 1 addition & 3 deletions node/rpc/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ use transaction_pool::txpool::{self, Pool};

pub use self::gen_client::Client as AccountsClient;

const RUNTIME_ERROR: i64 = 1;

/// Accounts RPC methods.
#[rpc]
pub trait AccountsApi {
Expand Down Expand Up @@ -75,7 +73,7 @@ where
let at = BlockId::hash(best);

let nonce = api.account_nonce(&at, account.clone()).map_err(|e| Error {
code: ErrorCode::ServerError(RUNTIME_ERROR),
code: ErrorCode::ServerError(crate::constants::RUNTIME_ERROR),
message: "Unable to query nonce.".into(),
data: Some(format!("{:?}", e).into()),
})?;
Expand Down
116 changes: 116 additions & 0 deletions node/rpc/src/contracts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

//! Node-specific RPC methods for interaction with contracts.

use std::sync::Arc;

use serde::{Serialize, Deserialize};
use client::blockchain::HeaderBackend;
use jsonrpc_core::{Error, ErrorCode, Result};
use jsonrpc_derive::rpc;
use node_primitives::{
AccountId, Balance, Block, BlockId, ContractExecResult, ContractsApi as ContractsRuntimeApi,
};
use sr_primitives::traits::{
self,
Block as BlockT,
};
use rpc_primitives::number;

/// 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 {
origin: AccountId,
dest: AccountId,
value: Balance,
gas_limit: number::NumberOrHex<u64>,
input_data: Vec<u8>,
}

/// Contracts RPC methods.
#[rpc]
pub trait ContractsApi<BlockHash> {
/// 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.
#[rpc(name = "contracts_call")]
fn call(
&self,
call_request: CallRequest,
at: Option<BlockHash>,
) -> Result<ContractExecResult>;
}

/// An implementation of contract specific RPC methods.
pub struct Contracts<C> {
client: Arc<C>,
}

impl<C> Contracts<C> {
/// Create new `Contracts` with the given reference to the client.
pub fn new(client: Arc<C>) -> Self {
Contracts { client }
}
}

impl<C> ContractsApi<<Block as BlockT>::Hash> for Contracts<C>
where
C: Send + Sync + 'static,
C: traits::ProvideRuntimeApi,
C: HeaderBackend<Block>,
C::Api: ContractsRuntimeApi<Block>,
{
fn call(
&self,
call_request: CallRequest,
at: Option<<Block as BlockT>::Hash>,
) -> Result<ContractExecResult> {
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,
input_data
} = call_request;
let gas_limit = gas_limit.to_number().map_err(|e| Error {
code: ErrorCode::InvalidParams,
message: e,
data: None,
})?;

let exec_result = api
.call(&at, origin, dest, value, gas_limit, input_data)
.map_err(|e| Error {
code: ErrorCode::ServerError(crate::constants::RUNTIME_ERROR),
message: "Runtime trapped while executing a contract.".into(),
data: Some(format!("{:?}", e).into()),
})?;

Ok(exec_result)
}
}
8 changes: 8 additions & 0 deletions node/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,11 @@
#![warn(missing_docs)]

pub mod accounts;
pub mod contracts;

mod constants {
/// A status code indicating an error happened while trying to call into the runtime.
///
/// This typically means that the runtime trapped.
pub const RUNTIME_ERROR: i64 = 1;
}
29 changes: 27 additions & 2 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use support::{
use primitives::u32_trait::{_1, _2, _3, _4};
use node_primitives::{
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
Moment, Signature,
Moment, Signature, ContractExecResult,
};
use babe::{AuthorityId as BabeId};
use grandpa::fg_primitives::{self, ScheduledChange};
Expand Down Expand Up @@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version.
spec_version: 156,
impl_version: 157,
impl_version: 158,
apis: RUNTIME_API_VERSIONS,
};

Expand Down Expand Up @@ -654,6 +654,31 @@ impl_runtime_apis! {
}
}

impl node_primitives::ContractsApi<Block> for Runtime {
fn call(
origin: AccountId,
dest: AccountId,
value: Balance,
gas_limit: u64,
input_data: Vec<u8>,
) -> ContractExecResult {
let exec_result = Contracts::bare_call(
origin,
dest.into(),
value,
gas_limit,
input_data,
);
match exec_result {
Ok(v) => ContractExecResult::Success {
status: v.status,
data: v.data,
},
Err(_) => ContractExecResult::Error,
}
}
}

impl substrate_session::SessionKeys<Block> for Runtime {
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string"));
Expand Down
Loading