mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 17:28:00 +00:00
Initial: Offchain Workers (#1942)
* Refactor state-machine stuff. * Fix tests. * WiP * WiP2 * Service support for offchain workers. * Service support for offchain workers. * Testing offchain worker. * Initial version working. * Pass side effects in call. * Pass OffchainExt in context. * Submit extrinsics to the pool. * Support inherents. * Insert to inherents pool. * Inserting to the pool asynchronously. * Add test to offchain worker. * Implement convenience syntax for modules. * Dispatching offchain worker through executive. * Fix offchain test. * Remove offchain worker from timestamp. * Update Cargo.lock. * Address review comments. * Use latest patch version for futures. * Add CLI parameter for offchain worker. * Fix compilation. * Fix test. * Fix extrinsics format for tests. * Fix RPC test. * Bump spec version. * Fix executive. * Fix support macro. * Address grumbles. * Bump runtime
This commit is contained in:
@@ -17,15 +17,15 @@
|
||||
use super::api::BlockBuilder as BlockBuilderApi;
|
||||
use std::vec::Vec;
|
||||
use parity_codec::Encode;
|
||||
use crate::blockchain::HeaderBackend;
|
||||
use runtime_primitives::ApplyOutcome;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::{
|
||||
Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef
|
||||
};
|
||||
use primitives::H256;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use primitives::{H256, ExecutionContext};
|
||||
use crate::blockchain::HeaderBackend;
|
||||
use crate::runtime_api::Core;
|
||||
use crate::error;
|
||||
use runtime_primitives::{ApplyOutcome, ExecutionContext};
|
||||
|
||||
|
||||
/// Utility for building new (valid) blocks from a stream of extrinsics.
|
||||
|
||||
@@ -19,12 +19,12 @@ use parity_codec::{Encode, Decode};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::Block as BlockT;
|
||||
use state_machine::{
|
||||
self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, ExecutionStrategy
|
||||
self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, ExecutionStrategy, NeverOffchainExt,
|
||||
};
|
||||
use executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
|
||||
use hash_db::Hasher;
|
||||
use trie::MemoryDB;
|
||||
use primitives::{H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue};
|
||||
use primitives::{H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue, OffchainExt};
|
||||
|
||||
use crate::backend;
|
||||
use crate::error;
|
||||
@@ -42,12 +42,15 @@ where
|
||||
/// Execute a call to a contract on top of state in a block of given hash.
|
||||
///
|
||||
/// No changes are made.
|
||||
fn call(
|
||||
fn call<
|
||||
O: OffchainExt,
|
||||
>(
|
||||
&self,
|
||||
id: &BlockId<B>,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
strategy: ExecutionStrategy,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> Result<Vec<u8>, error::Error>;
|
||||
|
||||
/// Execute a contextual call on top of state in a block of a given hash.
|
||||
@@ -56,6 +59,7 @@ where
|
||||
/// Before executing the method, passed header is installed as the current header
|
||||
/// of the execution context.
|
||||
fn contextual_call<
|
||||
O: OffchainExt,
|
||||
PB: Fn() -> error::Result<B::Header>,
|
||||
EM: Fn(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -73,6 +77,7 @@ where
|
||||
prepare_environment_block: PB,
|
||||
execution_manager: ExecutionManager<EM>,
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> error::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone;
|
||||
|
||||
/// Extract RuntimeVersion of given block
|
||||
@@ -84,6 +89,7 @@ where
|
||||
///
|
||||
/// No changes are made.
|
||||
fn call_at_state<
|
||||
O: OffchainExt,
|
||||
S: state_machine::Backend<H>,
|
||||
F: FnOnce(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -98,6 +104,7 @@ where
|
||||
call_data: &[u8],
|
||||
manager: ExecutionManager<F>,
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> Result<(NativeOrEncoded<R>, S::Transaction, Option<MemoryDB<H>>), error::Error>;
|
||||
|
||||
/// Execute a call to a contract on top of given state, gathering execution proof.
|
||||
@@ -140,7 +147,10 @@ pub struct LocalCallExecutor<B, E> {
|
||||
impl<B, E> LocalCallExecutor<B, E> {
|
||||
/// Creates new instance of local call executor.
|
||||
pub fn new(backend: Arc<B>, executor: E) -> Self {
|
||||
LocalCallExecutor { backend, executor }
|
||||
LocalCallExecutor {
|
||||
backend,
|
||||
executor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,17 +171,19 @@ where
|
||||
{
|
||||
type Error = E::Error;
|
||||
|
||||
fn call(&self,
|
||||
fn call<O: OffchainExt>(&self,
|
||||
id: &BlockId<Block>,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
strategy: ExecutionStrategy
|
||||
strategy: ExecutionStrategy,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> error::Result<Vec<u8>> {
|
||||
let mut changes = OverlayedChanges::default();
|
||||
let state = self.backend.state_at(*id)?;
|
||||
let return_data = state_machine::new(
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
side_effects_handler,
|
||||
&mut changes,
|
||||
&self.executor,
|
||||
method,
|
||||
@@ -187,6 +199,7 @@ where
|
||||
}
|
||||
|
||||
fn contextual_call<
|
||||
O: OffchainExt,
|
||||
PB: Fn() -> error::Result<Block::Header>,
|
||||
EM: Fn(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -204,6 +217,7 @@ where
|
||||
prepare_environment_block: PB,
|
||||
execution_manager: ExecutionManager<EM>,
|
||||
native_call: Option<NC>,
|
||||
mut side_effects_handler: Option<&mut O>,
|
||||
) -> Result<NativeOrEncoded<R>, error::Error> where ExecutionManager<EM>: Clone {
|
||||
let state = self.backend.state_at(*at)?;
|
||||
if method != "Core_initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) {
|
||||
@@ -211,6 +225,7 @@ where
|
||||
state_machine::new(
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
side_effects_handler.as_mut().map(|x| &mut **x),
|
||||
changes,
|
||||
&self.executor,
|
||||
"Core_initialise_block",
|
||||
@@ -226,6 +241,7 @@ where
|
||||
let result = state_machine::new(
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
side_effects_handler,
|
||||
changes,
|
||||
&self.executor,
|
||||
method,
|
||||
@@ -248,12 +264,13 @@ where
|
||||
fn runtime_version(&self, id: &BlockId<Block>) -> error::Result<RuntimeVersion> {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let state = self.backend.state_at(*id)?;
|
||||
let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage());
|
||||
let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage(), NeverOffchainExt::new());
|
||||
self.executor.runtime_version(&mut ext)
|
||||
.ok_or(error::ErrorKind::VersionInvalid.into())
|
||||
}
|
||||
|
||||
fn call_at_state<
|
||||
O: OffchainExt,
|
||||
S: state_machine::Backend<Blake2Hasher>,
|
||||
F: FnOnce(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -268,10 +285,12 @@ where
|
||||
call_data: &[u8],
|
||||
manager: ExecutionManager<F>,
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> error::Result<(NativeOrEncoded<R>, S::Transaction, Option<MemoryDB<Blake2Hasher>>)> {
|
||||
state_machine::new(
|
||||
state,
|
||||
self.backend.changes_trie_storage(),
|
||||
side_effects_handler,
|
||||
changes,
|
||||
&self.executor,
|
||||
method,
|
||||
|
||||
@@ -33,9 +33,9 @@ use runtime_primitives::traits::{
|
||||
Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash,
|
||||
ApiRef, ProvideRuntimeApi, Digest, DigestItem, AuthorityIdFor
|
||||
};
|
||||
use runtime_primitives::{BuildStorage, ExecutionContext};
|
||||
use runtime_primitives::BuildStorage;
|
||||
use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi};
|
||||
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue};
|
||||
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue, ExecutionContext};
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use primitives::storage::well_known_keys;
|
||||
use parity_codec::{Encode, Decode};
|
||||
@@ -43,7 +43,7 @@ use state_machine::{
|
||||
DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
|
||||
ExecutionStrategy, ExecutionManager, prove_read,
|
||||
ChangesTrieRootsStorage, ChangesTrieStorage,
|
||||
key_changes, key_changes_proof, OverlayedChanges,
|
||||
key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt,
|
||||
};
|
||||
use hash_db::Hasher;
|
||||
|
||||
@@ -84,6 +84,8 @@ pub struct ExecutionStrategies {
|
||||
pub importing: ExecutionStrategy,
|
||||
/// Execution strategy used when constructing blocks.
|
||||
pub block_construction: ExecutionStrategy,
|
||||
/// Execution strategy used for offchain workers.
|
||||
pub offchain_worker: ExecutionStrategy,
|
||||
/// Execution strategy used in other cases.
|
||||
pub other: ExecutionStrategy,
|
||||
}
|
||||
@@ -94,6 +96,7 @@ impl Default for ExecutionStrategies {
|
||||
syncing: ExecutionStrategy::NativeElseWasm,
|
||||
importing: ExecutionStrategy::NativeElseWasm,
|
||||
block_construction: ExecutionStrategy::AlwaysWasm,
|
||||
offchain_worker: ExecutionStrategy::NativeWhenPossible,
|
||||
other: ExecutionStrategy::NativeElseWasm,
|
||||
}
|
||||
}
|
||||
@@ -343,7 +346,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
pub fn authorities_at(&self, id: &BlockId<Block>) -> error::Result<Vec<AuthorityIdFor<Block>>> {
|
||||
match self.backend.blockchain().cache().and_then(|cache| cache.authorities_at(*id)) {
|
||||
Some(cached_value) => Ok(cached_value),
|
||||
None => self.executor.call(id, "Core_authorities", &[], ExecutionStrategy::NativeElseWasm)
|
||||
None => self.executor.call(id, "Core_authorities", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new())
|
||||
.and_then(|r| Vec::<AuthorityIdFor<Block>>::decode(&mut &r[..])
|
||||
.ok_or_else(|| error::ErrorKind::InvalidAuthoritiesSet.into()))
|
||||
}
|
||||
@@ -871,7 +874,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
}),
|
||||
}
|
||||
};
|
||||
let (_, storage_update, changes_update) = self.executor.call_at_state::<_, _, NeverNativeValue, fn() -> _>(
|
||||
let (_, storage_update, changes_update) = self.executor.call_at_state::<_, _, _, NeverNativeValue, fn() -> _>(
|
||||
transaction_state,
|
||||
&mut overlay,
|
||||
"Core_execute_block",
|
||||
@@ -881,6 +884,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
_ => get_execution_manager(self.execution_strategies().importing),
|
||||
},
|
||||
None,
|
||||
NeverOffchainExt::new(),
|
||||
)?;
|
||||
|
||||
overlay.commit_prospective();
|
||||
@@ -1339,7 +1343,8 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
|
||||
Block: BlockT<Hash=H256>
|
||||
{
|
||||
fn call_api_at<
|
||||
R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe
|
||||
R: Encode + Decode + PartialEq,
|
||||
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
|
||||
>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
@@ -1348,15 +1353,22 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
native_call: Option<NC>,
|
||||
context: ExecutionContext
|
||||
context: ExecutionContext,
|
||||
) -> error::Result<NativeOrEncoded<R>> {
|
||||
let manager = match context {
|
||||
ExecutionContext::BlockConstruction => self.execution_strategies.block_construction.get_manager(),
|
||||
ExecutionContext::Syncing => self.execution_strategies.syncing.get_manager(),
|
||||
ExecutionContext::Importing => self.execution_strategies.importing.get_manager(),
|
||||
ExecutionContext::OffchainWorker(_) => self.execution_strategies.offchain_worker.get_manager(),
|
||||
ExecutionContext::Other => self.execution_strategies.other.get_manager(),
|
||||
};
|
||||
self.executor.contextual_call::<_, fn(_,_) -> _,_,_>(
|
||||
|
||||
let mut offchain_extensions = match context {
|
||||
ExecutionContext::OffchainWorker(ext) => Some(ext),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.executor.contextual_call::<_, _, fn(_,_) -> _,_,_>(
|
||||
at,
|
||||
function,
|
||||
&args,
|
||||
@@ -1365,6 +1377,7 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
|
||||
|| self.prepare_environment_block(at),
|
||||
manager,
|
||||
native_call,
|
||||
offchain_extensions.as_mut(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ mod tests {
|
||||
state_machine::new(
|
||||
backend,
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
state_machine::NeverOffchainExt::new(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_initialise_block",
|
||||
@@ -102,6 +103,7 @@ mod tests {
|
||||
state_machine::new(
|
||||
backend,
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
state_machine::NeverOffchainExt::new(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
@@ -114,6 +116,7 @@ mod tests {
|
||||
let (ret_data, _, _) = state_machine::new(
|
||||
backend,
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
state_machine::NeverOffchainExt::new(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"BlockBuilder_finalise_block",
|
||||
@@ -160,6 +163,7 @@ mod tests {
|
||||
let _ = state_machine::new(
|
||||
&backend,
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
state_machine::NeverOffchainExt::new(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
@@ -188,6 +192,7 @@ mod tests {
|
||||
let _ = state_machine::new(
|
||||
&backend,
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
state_machine::NeverOffchainExt::new(),
|
||||
&mut overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
@@ -216,6 +221,7 @@ mod tests {
|
||||
let r = state_machine::new(
|
||||
&backend,
|
||||
Some(&InMemoryChangesTrieStorage::new()),
|
||||
state_machine::NeverOffchainExt::new(),
|
||||
&mut overlay,
|
||||
&Executor::new(None),
|
||||
"Core_execute_block",
|
||||
|
||||
@@ -21,11 +21,11 @@ use std::{collections::HashSet, sync::Arc, panic::UnwindSafe, result, marker::Ph
|
||||
use futures::{IntoFuture, Future};
|
||||
|
||||
use parity_codec::{Encode, Decode};
|
||||
use primitives::{H256, Blake2Hasher, convert_hash, NativeOrEncoded};
|
||||
use primitives::{H256, Blake2Hasher, convert_hash, NativeOrEncoded, OffchainExt};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT};
|
||||
use state_machine::{self, Backend as StateBackend, CodeExecutor, OverlayedChanges, ExecutionStrategy,
|
||||
create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager};
|
||||
create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager, NeverOffchainExt};
|
||||
use hash_db::Hasher;
|
||||
|
||||
use crate::backend::RemoteBackend;
|
||||
@@ -80,7 +80,16 @@ where
|
||||
{
|
||||
type Error = ClientError;
|
||||
|
||||
fn call(&self, id: &BlockId<Block>, method: &str, call_data: &[u8], _strategy: ExecutionStrategy)
|
||||
fn call<
|
||||
O: OffchainExt,
|
||||
>(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
_strategy: ExecutionStrategy,
|
||||
_side_effects_handler: Option<&mut O>,
|
||||
)
|
||||
-> ClientResult<Vec<u8>> {
|
||||
let block_hash = self.blockchain.expect_block_hash_from_id(id)?;
|
||||
let block_header = self.blockchain.expect_header(id.clone())?;
|
||||
@@ -95,6 +104,7 @@ where
|
||||
}
|
||||
|
||||
fn contextual_call<
|
||||
O: OffchainExt,
|
||||
PB: Fn() -> ClientResult<Block::Header>,
|
||||
EM: Fn(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -112,22 +122,24 @@ where
|
||||
_prepare_environment_block: PB,
|
||||
execution_manager: ExecutionManager<EM>,
|
||||
_native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
|
||||
// it is only possible to execute contextual call if changes are empty
|
||||
if !changes.is_empty() || initialised_block.is_some() {
|
||||
return Err(ClientErrorKind::NotAvailableOnLightClient.into());
|
||||
}
|
||||
|
||||
self.call(at, method, call_data, (&execution_manager).into()).map(NativeOrEncoded::Encoded)
|
||||
self.call(at, method, call_data, (&execution_manager).into(), side_effects_handler).map(NativeOrEncoded::Encoded)
|
||||
}
|
||||
|
||||
fn runtime_version(&self, id: &BlockId<Block>) -> ClientResult<RuntimeVersion> {
|
||||
let call_result = self.call(id, "version", &[], ExecutionStrategy::NativeElseWasm)?;
|
||||
let call_result = self.call(id, "version", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new())?;
|
||||
RuntimeVersion::decode(&mut call_result.as_slice())
|
||||
.ok_or_else(|| ClientErrorKind::VersionInvalid.into())
|
||||
}
|
||||
|
||||
fn call_at_state<
|
||||
O: OffchainExt,
|
||||
S: StateBackend<Blake2Hasher>,
|
||||
FF: FnOnce(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -142,6 +154,7 @@ where
|
||||
_call_data: &[u8],
|
||||
_m: ExecutionManager<FF>,
|
||||
_native_call: Option<NC>,
|
||||
_side_effects_handler: Option<&mut O>,
|
||||
) -> ClientResult<(NativeOrEncoded<R>, S::Transaction, Option<MemoryDB<Blake2Hasher>>)> {
|
||||
Err(ClientErrorKind::NotAvailableOnLightClient.into())
|
||||
}
|
||||
@@ -201,15 +214,24 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
{
|
||||
type Error = ClientError;
|
||||
|
||||
fn call(&self, id: &BlockId<Block>, method: &str, call_data: &[u8], strategy: ExecutionStrategy)
|
||||
-> ClientResult<Vec<u8>> {
|
||||
fn call<
|
||||
O: OffchainExt,
|
||||
>(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
strategy: ExecutionStrategy,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> ClientResult<Vec<u8>> {
|
||||
match self.backend.is_local_state_available(id) {
|
||||
true => self.local.call(id, method, call_data, strategy),
|
||||
false => self.remote.call(id, method, call_data, strategy),
|
||||
true => self.local.call(id, method, call_data, strategy, side_effects_handler),
|
||||
false => self.remote.call(id, method, call_data, strategy, side_effects_handler),
|
||||
}
|
||||
}
|
||||
|
||||
fn contextual_call<
|
||||
O: OffchainExt,
|
||||
PB: Fn() -> ClientResult<Block::Header>,
|
||||
EM: Fn(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -227,12 +249,14 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
prepare_environment_block: PB,
|
||||
_manager: ExecutionManager<EM>,
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
|
||||
// there's no actual way/need to specify native/wasm execution strategy on light node
|
||||
// => we can safely ignore passed values
|
||||
|
||||
match self.backend.is_local_state_available(at) {
|
||||
true => CallExecutor::contextual_call::<
|
||||
_,
|
||||
_,
|
||||
fn(
|
||||
Result<NativeOrEncoded<R>, Local::Error>,
|
||||
@@ -250,8 +274,10 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
prepare_environment_block,
|
||||
ExecutionManager::NativeWhenPossible,
|
||||
native_call,
|
||||
side_effects_handler,
|
||||
).map_err(|e| ClientErrorKind::Execution(Box::new(e.to_string())).into()),
|
||||
false => CallExecutor::contextual_call::<
|
||||
_,
|
||||
_,
|
||||
fn(
|
||||
Result<NativeOrEncoded<R>, Remote::Error>,
|
||||
@@ -269,6 +295,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
prepare_environment_block,
|
||||
ExecutionManager::NativeWhenPossible,
|
||||
native_call,
|
||||
side_effects_handler,
|
||||
).map_err(|e| ClientErrorKind::Execution(Box::new(e.to_string())).into()),
|
||||
}
|
||||
}
|
||||
@@ -281,6 +308,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
}
|
||||
|
||||
fn call_at_state<
|
||||
O: OffchainExt,
|
||||
S: StateBackend<Blake2Hasher>,
|
||||
FF: FnOnce(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
@@ -295,11 +323,13 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
call_data: &[u8],
|
||||
_manager: ExecutionManager<FF>,
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
) -> ClientResult<(NativeOrEncoded<R>, S::Transaction, Option<MemoryDB<Blake2Hasher>>)> {
|
||||
// there's no actual way/need to specify native/wasm execution strategy on light node
|
||||
// => we can safely ignore passed values
|
||||
|
||||
CallExecutor::call_at_state::<
|
||||
_,
|
||||
_,
|
||||
fn(
|
||||
Result<NativeOrEncoded<R>, Remote::Error>,
|
||||
@@ -315,6 +345,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
call_data,
|
||||
ExecutionManager::NativeWhenPossible,
|
||||
native_call,
|
||||
side_effects_handler,
|
||||
).map_err(|e| ClientErrorKind::Execution(Box::new(e.to_string())).into())
|
||||
}
|
||||
|
||||
@@ -509,7 +540,7 @@ mod tests {
|
||||
let local_executor = RemoteCallExecutor::new(Arc::new(backend.blockchain().clone()), Arc::new(OkCallFetcher::new(vec![1])));
|
||||
let remote_executor = RemoteCallExecutor::new(Arc::new(backend.blockchain().clone()), Arc::new(OkCallFetcher::new(vec![2])));
|
||||
let remote_or_local = RemoteOrLocalCallExecutor::new(backend, remote_executor, local_executor);
|
||||
assert_eq!(remote_or_local.call(&BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm).unwrap(), vec![1]);
|
||||
assert_eq!(remote_or_local.call(&BlockId::Number(1), "test_method", &[], ExecutionStrategy::NativeElseWasm).unwrap(), vec![2]);
|
||||
assert_eq!(remote_or_local.call(&BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new()).unwrap(), vec![1]);
|
||||
assert_eq!(remote_or_local.call(&BlockId::Number(1), "test_method", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new()).unwrap(), vec![2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,12 @@ pub use state_machine::OverlayedChanges;
|
||||
pub use primitives::NativeOrEncoded;
|
||||
#[doc(hidden)]
|
||||
pub use runtime_primitives::{
|
||||
traits::{AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef, RuntimeApiInfo},
|
||||
generic::BlockId, transaction_validity::TransactionValidity, ExecutionContext,
|
||||
traits::{AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, Header as HeaderT, ApiRef, RuntimeApiInfo},
|
||||
generic::BlockId, transaction_validity::TransactionValidity,
|
||||
};
|
||||
#[doc(hidden)]
|
||||
pub use primitives::{ExecutionContext, OffchainExt};
|
||||
#[doc(hidden)]
|
||||
pub use runtime_version::{ApiId, RuntimeVersion, ApisVec, create_apis_vec};
|
||||
#[doc(hidden)]
|
||||
pub use rstd::{slice, mem};
|
||||
@@ -91,7 +93,10 @@ pub trait ApiExt<Block: BlockT> {
|
||||
pub trait CallRuntimeAt<Block: BlockT> {
|
||||
/// Calls the given api function with the given encoded arguments at the given block
|
||||
/// and returns the encoded result.
|
||||
fn call_api_at<R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe>(
|
||||
fn call_api_at<
|
||||
R: Encode + Decode + PartialEq,
|
||||
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
|
||||
>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
@@ -99,7 +104,7 @@ pub trait CallRuntimeAt<Block: BlockT> {
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
native_call: Option<NC>,
|
||||
context: ExecutionContext
|
||||
context: ExecutionContext,
|
||||
) -> error::Result<NativeOrEncoded<R>>;
|
||||
|
||||
/// Returns the runtime version at the given block.
|
||||
@@ -132,3 +137,4 @@ decl_runtime_apis! {
|
||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user