--- a/Cargo.lock +++ b/Cargo.lock @@ -12843,6 +12843,7 @@ "sp-blockchain", "sp-core", "sp-externalities", + "sp-keystore", "sp-rpc", "sp-runtime", "sp-state-machine", --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ 'runtime/unique', 'runtime/tests', ] -default-members = ['node/*', 'runtime/opal'] +default-members = ['node/*', 'client/*', 'runtime/opal'] package.version = "0.9.36" [profile.release] --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -25,6 +25,7 @@ sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } sp-blockchain = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-keystore = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } sp-rpc = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } --- a/client/rpc/src/pov_estimate.rs +++ b/client/rpc/src/pov_estimate.rs @@ -16,7 +16,8 @@ use std::sync::Arc; -use codec::Encode; +use codec::{Encode, Decode}; +use sp_externalities::Extensions; use up_pov_estimate_rpc::{PovEstimateApi as PovEstimateRuntimeApi}; use up_common::types::opaque::RuntimeId; @@ -24,14 +25,21 @@ use sc_service::{NativeExecutionDispatch, config::ExecutionStrategy}; use sp_state_machine::{StateMachine, TrieBackendBuilder}; -use jsonrpsee::{ - core::RpcResult as Result, - proc_macros::rpc, -}; +use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc}; use anyhow::anyhow; use sc_client_api::backend::Backend; use sp_blockchain::HeaderBackend; +use sp_core::{ + Bytes, + offchain::{ + testing::{TestOffchainExt, TestTransactionPoolExt}, + OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, + }, + testing::TaskExecutor, + traits::TaskExecutorExt, +}; +use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_api::{AsTrieBackend, BlockId, BlockT, ProvideRuntimeApi}; use sc_executor::NativeElseWasmExecutor; @@ -113,93 +121,137 @@ #[rpc(server)] #[async_trait] pub trait PovEstimateApi { - #[method(name = "unique_povEstimate")] - fn pov_estimate(&self, encoded_xt: Vec, at: Option) -> Result; + #[method(name = "unique_estimateExtrinsicPoV")] + fn estimate_extrinsic_pov(&self, encoded_xt: Bytes, at: Option) -> Result; } #[allow(deprecated)] #[cfg(feature = "pov-estimate")] -impl - PovEstimateApiServer<::Hash> for PovEstimate +impl PovEstimateApiServer<::Hash> for PovEstimate where Block: BlockT, C: 'static + ProvideRuntimeApi + HeaderBackend, C::Api: PovEstimateRuntimeApi, { - fn pov_estimate(&self, encoded_xt: Vec, at: Option<::Hash>,) -> Result { - self.deny_unsafe.check_if_safe()?; + fn estimate_extrinsic_pov( + &self, + encoded_xt: Bytes, + at: Option<::Hash>, + ) -> Result { + self.deny_unsafe.check_if_safe()?; let at = BlockId::::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - let state = self.backend.state_at(at).map_err(|_| anyhow!("unable to fetch the state at {at:?}"))?; - match &self.runtime_id { - #[cfg(feature = "unique-runtime")] - RuntimeId::Unique => execute_extrinsic_in_sandbox::(state, &self.exec_params, encoded_xt), + let state = self + .backend + .state_at(at) + .map_err(|_| anyhow!("unable to fetch the state at {at:?}"))?; - #[cfg(feature = "quartz-runtime")] - RuntimeId::Quartz => execute_extrinsic_in_sandbox::(state, &self.exec_params, encoded_xt), + match &self.runtime_id { + #[cfg(feature = "unique-runtime")] + RuntimeId::Unique => execute_extrinsic_in_sandbox::( + state, + &self.exec_params, + encoded_xt, + ), - RuntimeId::Opal => execute_extrinsic_in_sandbox::(state, &self.exec_params, encoded_xt), + #[cfg(feature = "quartz-runtime")] + RuntimeId::Quartz => execute_extrinsic_in_sandbox::( + state, + &self.exec_params, + encoded_xt, + ), + + RuntimeId::Opal => execute_extrinsic_in_sandbox::( + state, + &self.exec_params, + encoded_xt, + ), - runtime_id => Err(anyhow!("unknown runtime id {:?}", runtime_id).into()), - } + runtime_id => Err(anyhow!("unknown runtime id {:?}", runtime_id).into()), + } } } -fn execute_extrinsic_in_sandbox(state: StateOf, exec_params: &ExecutorParams, encoded_xt: Vec) -> Result +fn full_extensions() -> Extensions { + let mut extensions = Extensions::default(); + extensions.register(TaskExecutorExt::new(TaskExecutor::new())); + let (offchain, _offchain_state) = TestOffchainExt::new(); + let (pool, _pool_state) = TestTransactionPoolExt::new(); + extensions.register(OffchainDbExt::new(offchain.clone())); + extensions.register(OffchainWorkerExt::new(offchain)); + extensions.register(KeystoreExt(std::sync::Arc::new(KeyStore::new()))); + extensions.register(TransactionPoolExt::new(pool)); + + extensions +} + +fn execute_extrinsic_in_sandbox( + state: StateOf, + exec_params: &ExecutorParams, + encoded_xt: Bytes, +) -> Result where - Block: BlockT, - D: NativeExecutionDispatch + 'static, + Block: BlockT, + D: NativeExecutionDispatch + 'static, { - let backend = state.as_trie_backend().clone(); - let mut changes = Default::default(); - let runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(backend); + let backend = state.as_trie_backend().clone(); + let mut changes = Default::default(); + let runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(backend); - let proving_backend = - TrieBackendBuilder::wrap(&backend).with_recorder(Default::default()).build(); + let proving_backend = TrieBackendBuilder::wrap(&backend) + .with_recorder(Default::default()) + .build(); - let runtime_code = runtime_code_backend.runtime_code() - .map_err(|_| anyhow!("runtime code backend creation failed"))?; + let runtime_code = runtime_code_backend + .runtime_code() + .map_err(|_| anyhow!("runtime code backend creation failed"))?; - let pre_root = *backend.root(); + let pre_root = *backend.root(); - let executor = NativeElseWasmExecutor::::new( - exec_params.wasm_method, - exec_params.default_heap_pages, - exec_params.max_runtime_instances, - exec_params.runtime_cache_size, - ); - let execution = ExecutionStrategy::NativeElseWasm; + let executor = NativeElseWasmExecutor::::new( + exec_params.wasm_method, + exec_params.default_heap_pages, + exec_params.max_runtime_instances, + exec_params.runtime_cache_size, + ); + let execution = ExecutionStrategy::NativeElseWasm; - StateMachine::new( - &proving_backend, - &mut changes, - &executor, - "PovEstimateApi_pov_estimate", - encoded_xt.as_slice(), - sp_externalities::Extensions::default(), - &runtime_code, - sp_core::testing::TaskExecutor::new(), - ) - .execute(execution.into()) - .map_err(|e| anyhow!("failed to execute the extrinsic {:?}", e))?; + let encoded_bytes = encoded_xt.encode(); - let proof = proving_backend - .extract_proof() - .expect("A recorder was set and thus, a storage proof can be extracted; qed"); - let proof_size = proof.encoded_size(); - let compact_proof = proof - .clone() - .into_compact_proof::>(pre_root) - .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?; - let compact_proof_size = compact_proof.encoded_size(); + let xt_result = StateMachine::new( + &proving_backend, + &mut changes, + &executor, + "PovEstimateApi_pov_estimate", + encoded_bytes.as_slice(), + full_extensions(), + &runtime_code, + sp_core::testing::TaskExecutor::new(), + ) + .execute(execution.into()) + .map_err(|e| anyhow!("failed to execute the extrinsic {:?}", e))?; + + let xt_result = Decode::decode(&mut &*xt_result) + .map_err(|e| anyhow!("failed to decode the extrinsic result {:?}", e))?; + + let proof = proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed"); + let proof_size = proof.encoded_size(); + let compact_proof = proof + .clone() + .into_compact_proof::>(pre_root) + .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?; + let compact_proof_size = compact_proof.encoded_size(); - let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0) - .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?; - let compressed_proof_size = compressed_proof.len(); + let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0) + .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?; + let compressed_proof_size = compressed_proof.len(); - Ok(PovInfo { - proof_size: proof_size as u64, - compact_proof_size: compact_proof_size as u64, - compressed_proof_size: compressed_proof_size as u64, - }) + Ok(PovInfo { + proof_size: proof_size as u64, + compact_proof_size: compact_proof_size as u64, + compressed_proof_size: compressed_proof_size as u64, + result: xt_result, + }) } --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -67,6 +67,8 @@ use fc_mapping_sync::{MappingSyncWorker, SyncStrategy}; use up_common::types::opaque::*; + +#[cfg(feature = "pov-estimate")] use crate::chain_spec::RuntimeIdentification; // RMRK @@ -517,8 +519,12 @@ .for_each(|()| futures::future::ready(())), ); + #[cfg(feature = "pov-estimate")] let rpc_backend = backend.clone(); + + #[cfg(feature = "pov-estimate")] let runtime_id = parachain_config.chain_spec.runtime_id(); + let rpc_builder = Box::new(move |deny_unsafe, subscription_task_executor| { let full_deps = unique_rpc::FullDeps { #[cfg(feature = "pov-estimate")] @@ -1058,8 +1064,13 @@ let rpc_pool = transaction_pool.clone(); let rpc_network = network.clone(); let rpc_frontier_backend = frontier_backend.clone(); + + #[cfg(feature = "pov-estimate")] let rpc_backend = backend.clone(); + + #[cfg(feature = "pov-estimate")] let runtime_id = config.chain_spec.runtime_id(); + let rpc_builder = Box::new(move |deny_unsafe, subscription_executor| { let full_deps = unique_rpc::FullDeps { #[cfg(feature = "pov-estimate")] --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -48,6 +48,7 @@ RmrkPartType, RmrkTheme, }; +#[cfg(feature = "pov-estimate")] type FullBackend = sc_service::TFullBackend; /// Extra dependencies for GRANDPA @@ -84,7 +85,7 @@ pub deny_unsafe: DenyUnsafe, /// EthFilterApi pool. pub filter_pool: Option, - + #[cfg(feature = "pov-estimate")] pub runtime_id: RuntimeId, /// Executor params for PoV estimating @@ -271,7 +272,16 @@ io.merge(Rmrk::new(client.clone()).into_rpc())?; #[cfg(feature = "pov-estimate")] - io.merge(PovEstimate::new(client.clone(), backend, deny_unsafe, exec_params, runtime_id).into_rpc())?; + io.merge( + PovEstimate::new( + client.clone(), + backend, + deny_unsafe, + exec_params, + runtime_id, + ) + .into_rpc(), + )?; if let Some(filter_pool) = filter_pool { io.merge( --- a/primitives/pov-estimate-rpc/src/lib.rs +++ b/primitives/pov-estimate-rpc/src/lib.rs @@ -16,24 +16,25 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::Serialize; use sp_runtime::ApplyExtrinsicResult; +use sp_core::Bytes; #[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[derive(Debug, TypeInfo)] pub struct PovInfo { - pub proof_size: u64, - pub compact_proof_size: u64, - pub compressed_proof_size: u64, + pub proof_size: u64, + pub compact_proof_size: u64, + pub compressed_proof_size: u64, + pub result: ApplyExtrinsicResult, } sp_api::decl_runtime_apis! { - pub trait PovEstimateApi { - fn pov_estimate(uxt: Block::Extrinsic) -> ApplyExtrinsicResult; - } + pub trait PovEstimateApi { + fn pov_estimate(uxt: Bytes) -> ApplyExtrinsicResult; + } } --- a/runtime/common/runtime_apis.rs +++ b/runtime/common/runtime_apis.rs @@ -35,11 +35,11 @@ ) => { use sp_std::prelude::*; use sp_api::impl_runtime_apis; - use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160}; + use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160, Bytes}; use sp_runtime::{ Permill, traits::Block as BlockT, - transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError, InvalidTransaction}, + transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, DispatchError, }; use fp_rpc::TransactionStatus; @@ -780,12 +780,24 @@ impl up_pov_estimate_rpc::PovEstimateApi for Runtime { #[allow(unused_variables)] - fn pov_estimate(uxt: ::Extrinsic) -> ApplyExtrinsicResult { + fn pov_estimate(uxt: Bytes) -> ApplyExtrinsicResult { #[cfg(feature = "pov-estimate")] - return Executive::apply_extrinsic(uxt); + { + use codec::Decode; + + let uxt_decode = <::Extrinsic as Decode>::decode(&mut &*uxt) + .map_err(|_| DispatchError::Other("failed to decode the extrinsic")); + + let uxt = match uxt_decode { + Ok(uxt) => uxt, + Err(err) => return Ok(err.into()), + }; + + Executive::apply_extrinsic(uxt) + } #[cfg(not(feature = "pov-estimate"))] - return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + return Ok(unsupported!()); } }