Add an RPC method for calling a contract. (#3563)

* Sketch

* Some work on docs.

* Doc improvements.

* More docs.

* Some more docs.

* Yet another comment.

* Bump impl_version.

* Accept the block hash

* Use NumberOrHex

* Update node/rpc/src/contracts.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Move rpc/primitives
This commit is contained in:
Sergei Pepyakin
2019-09-12 13:30:10 +02:00
committed by GitHub
parent 294d172187
commit 4daac15d22
18 changed files with 279 additions and 27 deletions
+2 -10
View File
@@ -75,11 +75,12 @@ pub type ExecResult = Result<ExecReturnValue, ExecError>;
/// wrap the error string into an ExecutionError with the provided buffer and return from the
/// enclosing function. This macro is used instead of .map_err(..)? in order to avoid taking
/// ownership of buffer unless there is an error.
#[macro_export]
macro_rules! try_or_exec_error {
($e:expr, $buffer:expr) => {
match $e {
Ok(val) => val,
Err(reason) => return Err(ExecError { reason, buffer: $buffer }),
Err(reason) => return Err($crate::exec::ExecError { reason, buffer: $buffer }),
}
}
}
@@ -191,15 +192,6 @@ pub trait Loader<T: Trait> {
fn load_main(&self, code_hash: &CodeHash<T>) -> Result<Self::Executable, &'static str>;
}
/// Struct that records a request to deposit an event with a list of topics.
#[cfg_attr(any(feature = "std", test), derive(Debug, PartialEq, Eq))]
pub struct IndexedEvent<T: Trait> {
/// A list of topics this event will be deposited with.
pub topics: Vec<T::Hash>,
/// The event to deposit.
pub event: Event<T>,
}
/// A trait that represent a virtual machine.
///
/// You can view a virtual machine as something that takes code, an input data buffer,
+32 -9
View File
@@ -98,11 +98,13 @@ mod rent;
#[cfg(test)]
mod tests;
use crate::exec::{ExecutionContext, ExecResult};
use crate::exec::ExecutionContext;
use crate::account_db::{AccountDb, DirectAccountDb};
pub use crate::gas::{Gas, GasMeter};
use crate::wasm::{WasmLoader, WasmVm};
pub use crate::gas::{Gas, GasMeter};
pub use crate::exec::{ExecResult, ExecReturnValue, ExecError, StatusCode};
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use primitives::crypto::UncheckedFrom;
@@ -573,9 +575,9 @@ decl_module! {
let origin = ensure_signed(origin)?;
let dest = T::Lookup::lookup(dest)?;
Self::execute_wasm(origin, gas_limit, |ctx, gas_meter| {
ctx.call(dest, value, gas_meter, data)
})
Self::bare_call(origin, dest, value, gas_limit, data)
.map(|_| ())
.map_err(|e| e.reason)
}
/// Creates a new contract from the `codehash` generated by `put_code`, optionally transferring some balance.
@@ -601,6 +603,8 @@ decl_module! {
ctx.instantiate(endowment, gas_meter, &code_hash, data)
.map(|(_address, output)| output)
})
.map(|_| ())
.map_err(|e| e.reason)
}
/// Allows block producers to claim a small reward for evicting a contract. If a block producer
@@ -645,16 +649,37 @@ decl_module! {
}
impl<T: Trait> Module<T> {
/// Perform a call to a specified contract.
///
/// This function is similar to `Self::call`, but doesn't perform any lookups and better
/// suitable for calling directly from Rust.
pub fn bare_call(
origin: T::AccountId,
dest: T::AccountId,
value: BalanceOf<T>,
gas_limit: Gas,
input_data: Vec<u8>,
) -> ExecResult {
Self::execute_wasm(origin, gas_limit, |ctx, gas_meter| {
ctx.call(dest, value, gas_meter, input_data)
})
}
fn execute_wasm(
origin: T::AccountId,
gas_limit: Gas,
func: impl FnOnce(&mut ExecutionContext<T, WasmVm, WasmLoader>, &mut GasMeter<T>) -> ExecResult
) -> Result {
) -> ExecResult {
// Pay for the gas upfront.
//
// NOTE: it is very important to avoid any state changes before
// paying for the gas.
let (mut gas_meter, imbalance) = gas::buy_gas::<T>(&origin, gas_limit)?;
let (mut gas_meter, imbalance) =
try_or_exec_error!(
gas::buy_gas::<T>(&origin, gas_limit),
// We don't have a spare buffer here in the first place, so create a new empty one.
Vec::new()
);
let cfg = Config::preload();
let vm = WasmVm::new(&cfg.schedule);
@@ -705,8 +730,6 @@ impl<T: Trait> Module<T> {
});
result
.map(|_| ())
.map_err(|e| e.reason)
}
fn restore_to(