git.delta.rocks / unique-network / refs/commits / b2966bbee392

difftreelog

source

client/rpc/src/pov_estimate.rs8.0 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use std::sync::Arc;1819use anyhow::anyhow;20use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc};21use parity_scale_codec::{Decode, Encode};22use sc_client_api::backend::Backend;23use sc_executor::NativeElseWasmExecutor;24use sc_rpc_api::DenyUnsafe;25use sc_service::{config::ExecutionStrategy, NativeExecutionDispatch};26use sp_api::{AsTrieBackend, BlockId, BlockT, ProvideRuntimeApi};27use sp_blockchain::HeaderBackend;28use sp_core::{29	offchain::{30		testing::{TestOffchainExt, TestTransactionPoolExt},31		OffchainDbExt, OffchainWorkerExt, TransactionPoolExt,32	},33	testing::TaskExecutor,34	traits::TaskExecutorExt,35	Bytes,36};37use sp_externalities::Extensions;38use sp_keystore::{testing::KeyStore, KeystoreExt};39use sp_runtime::traits::Header;40use sp_state_machine::{StateMachine, TrieBackendBuilder};41use trie_db::{Trie, TrieDBBuilder};42use up_common::types::opaque::RuntimeId;43use up_pov_estimate_rpc::{PovEstimateApi as PovEstimateRuntimeApi, PovInfo, TrieKeyValue};4445use crate::define_struct_for_server_api;4647type HasherOf<Block> = <<Block as BlockT>::Header as Header>::Hashing;48type StateOf<Block> = <sc_service::TFullBackend<Block> as Backend<Block>>::State;4950pub struct ExecutorParams {51	pub wasm_method: sc_service::config::WasmExecutionMethod,52	pub default_heap_pages: Option<u64>,53	pub max_runtime_instances: usize,54	pub runtime_cache_size: u8,55}5657#[cfg(feature = "unique-runtime")]58pub struct UniqueRuntimeExecutor;5960#[cfg(feature = "quartz-runtime")]61pub struct QuartzRuntimeExecutor;6263pub struct OpalRuntimeExecutor;6465#[cfg(feature = "unique-runtime")]66impl NativeExecutionDispatch for UniqueRuntimeExecutor {67	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;6869	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {70		unique_runtime::api::dispatch(method, data)71	}7273	fn native_version() -> sc_executor::NativeVersion {74		unique_runtime::native_version()75	}76}7778#[cfg(feature = "quartz-runtime")]79impl NativeExecutionDispatch for QuartzRuntimeExecutor {80	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;8182	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {83		quartz_runtime::api::dispatch(method, data)84	}8586	fn native_version() -> sc_executor::NativeVersion {87		quartz_runtime::native_version()88	}89}9091impl NativeExecutionDispatch for OpalRuntimeExecutor {92	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;9394	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {95		opal_runtime::api::dispatch(method, data)96	}9798	fn native_version() -> sc_executor::NativeVersion {99		opal_runtime::native_version()100	}101}102103#[cfg(feature = "pov-estimate")]104define_struct_for_server_api! {105	PovEstimate {106		client: Arc<Client>,107		backend: Arc<sc_service::TFullBackend<Block>>,108		deny_unsafe: DenyUnsafe,109		exec_params: ExecutorParams,110		runtime_id: RuntimeId,111	}112}113114#[rpc(server)]115#[async_trait]116pub trait PovEstimateApi<BlockHash> {117	#[method(name = "povinfo_estimateExtrinsicPoV")]118	fn estimate_extrinsic_pov(119		&self,120		encoded_xts: Vec<Bytes>,121		at: Option<BlockHash>,122	) -> Result<PovInfo>;123}124125#[allow(deprecated)]126#[cfg(feature = "pov-estimate")]127impl<C, Block> PovEstimateApiServer<<Block as BlockT>::Hash> for PovEstimate<C, Block>128where129	Block: BlockT,130	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,131	C::Api: PovEstimateRuntimeApi<Block>,132{133	fn estimate_extrinsic_pov(134		&self,135		encoded_xts: Vec<Bytes>,136		at: Option<<Block as BlockT>::Hash>,137	) -> Result<PovInfo> {138		self.deny_unsafe.check_if_safe()?;139140		let at = at.unwrap_or_else(|| self.client.info().best_hash);141		let state = self142			.backend143			.state_at(at)144			.map_err(|_| anyhow!("unable to fetch the state at {at:?}"))?;145146		match &self.runtime_id {147			#[cfg(feature = "unique-runtime")]148			RuntimeId::Unique => execute_extrinsic_in_sandbox::<Block, UniqueRuntimeExecutor>(149				state,150				&self.exec_params,151				encoded_xts,152			),153154			#[cfg(feature = "quartz-runtime")]155			RuntimeId::Quartz => execute_extrinsic_in_sandbox::<Block, QuartzRuntimeExecutor>(156				state,157				&self.exec_params,158				encoded_xts,159			),160161			RuntimeId::Opal => execute_extrinsic_in_sandbox::<Block, OpalRuntimeExecutor>(162				state,163				&self.exec_params,164				encoded_xts,165			),166167			runtime_id => Err(anyhow!("unknown runtime id {:?}", runtime_id).into()),168		}169	}170}171172fn full_extensions() -> Extensions {173	let mut extensions = Extensions::default();174	extensions.register(TaskExecutorExt::new(TaskExecutor::new()));175	let (offchain, _offchain_state) = TestOffchainExt::new();176	let (pool, _pool_state) = TestTransactionPoolExt::new();177	extensions.register(OffchainDbExt::new(offchain.clone()));178	extensions.register(OffchainWorkerExt::new(offchain));179	extensions.register(KeystoreExt(std::sync::Arc::new(KeyStore::new())));180	extensions.register(TransactionPoolExt::new(pool));181182	extensions183}184185fn execute_extrinsic_in_sandbox<Block, D>(186	state: StateOf<Block>,187	exec_params: &ExecutorParams,188	encoded_xts: Vec<Bytes>,189) -> Result<PovInfo>190where191	Block: BlockT,192	D: NativeExecutionDispatch + 'static,193{194	let backend = state.as_trie_backend().clone();195	let mut changes = Default::default();196	let runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(backend);197198	let proving_backend = TrieBackendBuilder::wrap(&backend)199		.with_recorder(Default::default())200		.build();201202	let runtime_code = runtime_code_backend203		.runtime_code()204		.map_err(|_| anyhow!("runtime code backend creation failed"))?;205206	let pre_root = *backend.root();207208	let executor = sc_service::new_native_or_wasm_executor(exec_params);209	let execution = ExecutionStrategy::NativeElseWasm;210211	let mut results = Vec::new();212213	for encoded_xt in encoded_xts {214		let encoded_bytes = encoded_xt.encode();215216		let xt_result = StateMachine::new(217			&proving_backend,218			&mut changes,219			&executor,220			"PovEstimateApi_pov_estimate",221			encoded_bytes.as_slice(),222			full_extensions(),223			&runtime_code,224			sp_core::testing::TaskExecutor::new(),225		)226		.execute(execution.into())227		.map_err(|e| anyhow!("failed to execute the extrinsic {:?}", e))?;228229		let xt_result = Decode::decode(&mut &*xt_result)230			.map_err(|e| anyhow!("failed to decode the extrinsic result {:?}", e))?;231232		results.push(xt_result);233	}234235	let root = proving_backend.root().clone();236237	let proof = proving_backend238		.extract_proof()239		.expect("A recorder was set and thus, a storage proof can be extracted; qed");240	let proof_size = proof.encoded_size();241242	let memory_db = proof.clone().into_memory_db();243244	let tree_db =245		TrieDBBuilder::<sp_trie::LayoutV1<HasherOf<Block>>>::new(&memory_db, &root).build();246247	let key_values = tree_db248		.iter()249		.map_err(|e| anyhow!("failed to retrieve tree db key values: {:?}", e))?250		.filter_map(|item| {251			let item = item.ok()?;252253			Some(TrieKeyValue {254				key: item.0,255				value: item.1,256			})257		})258		.collect();259260	let compact_proof = proof261		.clone()262		.into_compact_proof::<HasherOf<Block>>(pre_root)263		.map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?;264	let compact_proof_size = compact_proof.encoded_size();265266	let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0)267		.map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?;268	let compressed_proof_size = compressed_proof.len();269270	Ok(PovInfo {271		proof_size: proof_size as u64,272		compact_proof_size: compact_proof_size as u64,273		compressed_proof_size: compressed_proof_size as u64,274		results,275		key_values,276	})277}