Unverified Commit a20a35b6 authored by Zeke Mostov's avatar Zeke Mostov Committed by GitHub
Browse files

Allow staking miner to use different election algorithms (#3752)



* WIP

* Dry run cmd working

* Monitor cmd works

* Configure balance with parameter type

* Comments

* cleannnn

* Add balancing to PhragMMS

* Move OffchainRanomBalancing to common

* DRY mine_unchecked over config.solver

* FMT

* Apply suggestions from code review
Co-authored-by: default avatarKian Paimani <5588131+kianenigma@users.noreply.github.com>

* Improve docs for any_runtime_unit!

* Some cleanup

* fmt

* Correct capitilaztion

* Improve version mismatch log

* Revert "Improve version mismatch log"

This reverts commit 57570403

.

* Apply suggestions from code review
Co-authored-by: default avatarKian Paimani <5588131+kianenigma@users.noreply.github.com>

* Remove Balancing struct and use Balancing Parameter type instead

* update Substrate
Co-authored-by: default avatarKian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: parity-processbot <>
parent 4c8dda20
Pipeline #156455 passed with stages
in 42 minutes and 7 seconds
This diff is collapsed.
......@@ -22,6 +22,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-npos-elections = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
......@@ -90,6 +91,7 @@ std = [
"libsecp256k1/std",
"runtime-parachains/std",
"xcm/std",
"sp-npos-elections/std",
]
runtime-benchmarks = [
"libsecp256k1/hmac",
......
......@@ -55,3 +55,30 @@ impl pallet_election_provider_multi_phase::BenchmarkingConfig for BenchmarkConfi
const MINER_MAXIMUM_VOTERS: u32 = 15_000;
const MAXIMUM_TARGETS: u32 = 2000;
}
/// Maximum number of iterations for balancing that will be executed in the embedded miner of
/// pallet-election-provider-multi-phase.
pub const MINER_MAX_ITERATIONS: u32 = 10;
/// A source of random balance for the NPoS Solver, which is meant to be run by the OCW election
/// miner.
pub struct OffchainRandomBalancing;
impl frame_support::pallet_prelude::Get<Option<(usize, sp_npos_elections::ExtendedBalance)>>
for OffchainRandomBalancing
{
fn get() -> Option<(usize, sp_npos_elections::ExtendedBalance)> {
use sp_runtime::{codec::Decode, traits::TrailingZeroInput};
let iters = match MINER_MAX_ITERATIONS {
0 => 0,
max @ _ => {
let seed = sp_io::offchain::random_seed();
let random = <u32>::decode(&mut TrailingZeroInput::new(&seed))
.expect("input is padded with zeroes; qed") %
max.saturating_add(1);
random as usize
},
};
Some((iters, 0))
}
}
......@@ -356,7 +356,6 @@ parameter_types! {
pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
// miner configs
pub const MinerMaxIterations: u32 = 10;
pub OffchainRepeat: BlockNumber = 5;
}
......@@ -384,7 +383,6 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type RewardHandler = (); // nothing to do upon rewards
type SignedPhase = SignedPhase;
type SolutionImprovementThreshold = SolutionImprovementThreshold;
type MinerMaxIterations = MinerMaxIterations;
type MinerMaxWeight = OffchainSolutionWeightLimit; // For now use the one from staking.
type MinerMaxLength = OffchainSolutionLengthLimit;
type OffchainRepeat = OffchainRepeat;
......@@ -393,6 +391,11 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type Solution = NposCompactSolution24;
type OnChainAccuracy = Perbill;
type Fallback = Fallback;
type Solver = frame_election_provider_support::SequentialPhragmen<
AccountId,
pallet_election_provider_multi_phase::SolutionAccuracyOf<Runtime>,
runtime_common::elections::OffchainRandomBalancing,
>;
type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig;
type ForceOrigin = EnsureOneOf<
AccountId,
......
......@@ -362,7 +362,6 @@ parameter_types! {
pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
// miner configs
pub const MinerMaxIterations: u32 = 10;
pub OffchainRepeat: BlockNumber = 5;
}
......@@ -390,7 +389,6 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type SlashHandler = (); // burn slashes
type RewardHandler = (); // nothing to do upon rewards
type SolutionImprovementThreshold = SolutionImprovementThreshold;
type MinerMaxIterations = MinerMaxIterations;
type MinerMaxWeight = OffchainSolutionWeightLimit; // For now use the one from staking.
type MinerMaxLength = OffchainSolutionLengthLimit;
type OffchainRepeat = OffchainRepeat;
......@@ -399,6 +397,11 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type OnChainAccuracy = Perbill;
type Solution = NposCompactSolution16;
type Fallback = Fallback;
type Solver = frame_election_provider_support::SequentialPhragmen<
AccountId,
pallet_election_provider_multi_phase::SolutionAccuracyOf<Runtime>,
runtime_common::elections::OffchainRandomBalancing,
>;
type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig;
type ForceOrigin = EnsureOneOf<
AccountId,
......
......@@ -342,7 +342,6 @@ parameter_types! {
pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
// miner configs
pub const MinerMaxIterations: u32 = 10;
pub OffchainRepeat: BlockNumber = 5;
}
......@@ -370,7 +369,6 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type SlashHandler = (); // burn slashes
type RewardHandler = (); // nothing to do upon rewards
type SolutionImprovementThreshold = SolutionImprovementThreshold;
type MinerMaxIterations = MinerMaxIterations;
type MinerMaxWeight = OffchainSolutionWeightLimit; // For now use the one from staking.
type MinerMaxLength = OffchainSolutionLengthLimit;
type OffchainRepeat = OffchainRepeat;
......@@ -379,6 +377,11 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type OnChainAccuracy = Perbill;
type Solution = NposCompactSolution16;
type Fallback = Fallback;
type Solver = frame_election_provider_support::SequentialPhragmen<
AccountId,
pallet_election_provider_multi_phase::SolutionAccuracyOf<Runtime>,
runtime_common::elections::OffchainRandomBalancing,
>;
type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig;
type ForceOrigin = EnsureRoot<AccountId>;
type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo<Runtime>;
......
......@@ -22,11 +22,13 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-npos-elections = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-election-provider-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-election-provider-multi-phase = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
......
......@@ -23,7 +23,7 @@ use codec::Encode;
use frame_support::traits::Currency;
/// Forcefully create the snapshot. This can be used to compute the election at anytime.
fn force_create_snapshot<T: EPM::Config>(ext: &mut Ext) -> Result<(), Error> {
fn force_create_snapshot<T: EPM::Config>(ext: &mut Ext) -> Result<(), Error<T>> {
ext.execute_with(|| {
if <EPM::Snapshot<T>>::exists() {
log::info!(target: LOG_TARGET, "snapshot already exists.");
......@@ -112,7 +112,7 @@ macro_rules! dry_run_cmd_for { ($runtime:ident) => { paste::paste! {
shared: SharedConfig,
config: DryRunConfig,
signer: Signer,
) -> Result<(), Error> {
) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> {
use $crate::[<$runtime _runtime_exports>]::*;
let mut ext = crate::create_election_ext::<Runtime, Block>(
shared.uri.clone(),
......@@ -121,7 +121,8 @@ macro_rules! dry_run_cmd_for { ($runtime:ident) => { paste::paste! {
).await?;
force_create_snapshot::<Runtime>(&mut ext)?;
let (raw_solution, witness) = crate::mine_unchecked::<Runtime>(&mut ext, config.iterations, false)?;
let (raw_solution, witness) = crate::mine_with::<Runtime>(&config.solver, &mut ext)?;
let nonce = crate::get_account_info::<Runtime>(client, &signer.account, config.at)
.await?
.map(|i| i.nonce)
......@@ -148,7 +149,9 @@ macro_rules! dry_run_cmd_for { ($runtime:ident) => { paste::paste! {
});
log::info!(target: LOG_TARGET, "dispatch result is {:?}", dispatch_result);
let outcome = rpc_decode::<sp_runtime::ApplyExtrinsicResult>(client, "system_dryRun", params!{ bytes }).await?;
let outcome = rpc_decode::<sp_runtime::ApplyExtrinsicResult>(client, "system_dryRun", params!{ bytes })
.await
.map_err::<Error<Runtime>, _>(Into::into)?;
log::info!(target: LOG_TARGET, "dry-run outcome is {:?}", outcome);
Ok(())
}
......
......@@ -18,20 +18,22 @@
use crate::{prelude::*, Error, SharedConfig};
use codec::Encode;
use frame_election_provider_support::SequentialPhragmen;
use std::io::Write;
macro_rules! emergency_solution_cmd_for { ($runtime:ident) => { paste::paste! {
/// Execute the emergency-solution command.
pub(crate) async fn [<emergency_solution_cmd_ $runtime>](
shared: SharedConfig,
) -> Result<(), Error> {
) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> {
use $crate::[<$runtime _runtime_exports>]::*;
let mut ext = crate::create_election_ext::<Runtime, Block>(shared.uri.clone(), None, vec![]).await?;
ext.execute_with(|| {
assert!(EPM::Pallet::<Runtime>::current_phase().is_emergency());
// NOTE: this internally calls feasibility_check, but we just re-do it here as an easy way
// to get a `ReadySolution`.
let (raw_solution, _) = <EPM::Pallet<Runtime>>::mine_solution(50)?;
let (raw_solution, _) =
<EPM::Pallet<Runtime>>::mine_solution::<SequentialPhragmen<AccountId, sp_runtime::Perbill>>()?;
log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score);
let ready_solution = EPM::Pallet::<Runtime>::feasibility_check(raw_solution, EPM::ElectionCompute::Signed)?;
let encoded_ready = ready_solution.encode();
......
......@@ -38,9 +38,11 @@ mod signer;
pub(crate) use prelude::*;
pub(crate) use signer::get_account_info;
use frame_election_provider_support::NposSolver;
use frame_support::traits::Get;
use jsonrpsee_ws_client::{WsClient, WsClientBuilder};
use remote_externalities::{Builder, Mode, OnlineConfig};
use sp_npos_elections::ExtendedBalance;
use sp_runtime::traits::Block as BlockT;
use structopt::StructOpt;
......@@ -193,15 +195,43 @@ macro_rules! any_runtime {
}
}
#[derive(Debug, thiserror::Error)]
enum Error {
/// Same as [`any_runtime`], but instead of returning a `Result`, this simply returns `()`. Useful
/// for situations where the result is not useful and un-ergonomic to handle.
#[macro_export]
macro_rules! any_runtime_unit {
($($code:tt)*) => {
unsafe {
match $crate::RUNTIME {
$crate::AnyRuntime::Polkadot => {
#[allow(unused)]
use $crate::polkadot_runtime_exports::*;
let _ = $($code)*;
},
$crate::AnyRuntime::Kusama => {
#[allow(unused)]
use $crate::kusama_runtime_exports::*;
let _ = $($code)*;
},
$crate::AnyRuntime::Westend => {
#[allow(unused)]
use $crate::westend_runtime_exports::*;
let _ = $($code)*;
}
}
}
}
}
#[derive(frame_support::DebugNoBound, thiserror::Error)]
enum Error<T: EPM::Config> {
Io(#[from] std::io::Error),
Jsonrpsee(#[from] jsonrpsee_ws_client::types::Error),
JsonRpsee(#[from] jsonrpsee_ws_client::types::Error),
RpcHelperError(#[from] rpc_helpers::RpcHelperError),
Codec(#[from] codec::Error),
Crypto(sp_core::crypto::SecretStringError),
RemoteExternalities(&'static str),
PalletMiner(EPM::unsigned::MinerError),
PalletElection(EPM::ElectionError),
PalletMiner(EPM::unsigned::MinerError<T>),
PalletElection(EPM::ElectionError<T>),
PalletFeasibility(EPM::FeasibilityError),
AccountDoesNotExists,
IncorrectPhase,
......@@ -209,33 +239,33 @@ enum Error {
VersionMismatch,
}
impl From<sp_core::crypto::SecretStringError> for Error {
fn from(e: sp_core::crypto::SecretStringError) -> Error {
impl<T: EPM::Config> From<sp_core::crypto::SecretStringError> for Error<T> {
fn from(e: sp_core::crypto::SecretStringError) -> Error<T> {
Error::Crypto(e)
}
}
impl From<EPM::unsigned::MinerError> for Error {
fn from(e: EPM::unsigned::MinerError) -> Error {
impl<T: EPM::Config> From<EPM::unsigned::MinerError<T>> for Error<T> {
fn from(e: EPM::unsigned::MinerError<T>) -> Error<T> {
Error::PalletMiner(e)
}
}
impl From<EPM::ElectionError> for Error {
fn from(e: EPM::ElectionError) -> Error {
impl<T: EPM::Config> From<EPM::ElectionError<T>> for Error<T> {
fn from(e: EPM::ElectionError<T>) -> Error<T> {
Error::PalletElection(e)
}
}
impl From<EPM::FeasibilityError> for Error {
fn from(e: EPM::FeasibilityError) -> Error {
impl<T: EPM::Config> From<EPM::FeasibilityError> for Error<T> {
fn from(e: EPM::FeasibilityError) -> Error<T> {
Error::PalletFeasibility(e)
}
}
impl std::fmt::Display for Error {
impl<T: EPM::Config> std::fmt::Display for Error<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Error as std::fmt::Debug>::fmt(self, f)
<Error<T> as std::fmt::Debug>::fmt(self, f)
}
}
......@@ -249,6 +279,58 @@ enum Command {
EmergencySolution,
}
#[derive(Debug, Clone, StructOpt)]
enum Solvers {
SeqPhragmen {
#[structopt(long, default_value = "10")]
iterations: usize,
},
PhragMMS {
#[structopt(long, default_value = "10")]
iterations: usize,
},
}
/// Mine a solution with the given `solver`.
fn mine_with<T>(
solver: &Solvers,
ext: &mut Ext,
) -> Result<(EPM::RawSolution<EPM::SolutionOf<T>>, u32), Error<T>>
where
T: EPM::Config,
T::Solver: NposSolver<Error = sp_npos_elections::Error>,
{
use frame_election_provider_support::{PhragMMS, SequentialPhragmen};
match solver {
Solvers::SeqPhragmen { iterations } => {
BalanceIterations::set(*iterations);
mine_unchecked::<
T,
SequentialPhragmen<
<T as frame_system::Config>::AccountId,
sp_runtime::Perbill,
Balancing,
>,
>(ext, false)
},
Solvers::PhragMMS { iterations } => {
BalanceIterations::set(*iterations);
mine_unchecked::<
T,
PhragMMS<<T as frame_system::Config>::AccountId, sp_runtime::Perbill, Balancing>,
>(ext, false)
},
}
}
frame_support::parameter_types! {
/// Number of balancing iterations for a solution algorithm. Set based on the [`Solvers`] CLI
/// config.
pub static BalanceIterations: usize = 10;
pub static Balancing: Option<(usize, ExtendedBalance)> = Some((BalanceIterations::get(), 0));
}
#[derive(Debug, Clone, StructOpt)]
struct MonitorConfig {
/// They type of event to listen to.
......@@ -259,8 +341,8 @@ struct MonitorConfig {
#[structopt(long, default_value = "head", possible_values = &["head", "finalized"])]
listen: String,
#[structopt(long, short, default_value = "10")]
iterations: usize,
#[structopt(subcommand)]
solver: Solvers,
}
#[derive(Debug, Clone, StructOpt)]
......@@ -269,8 +351,8 @@ struct DryRunConfig {
#[structopt(long)]
at: Option<Hash>,
#[structopt(long, short, default_value = "10")]
iterations: usize,
#[structopt(subcommand)]
solver: Solvers,
}
#[derive(Debug, Clone, StructOpt)]
......@@ -303,7 +385,7 @@ async fn create_election_ext<T: EPM::Config, B: BlockT>(
uri: String,
at: Option<B::Hash>,
additional: Vec<String>,
) -> Result<Ext, Error> {
) -> Result<Ext, Error<T>> {
use frame_support::{storage::generator::StorageMap, traits::PalletInfo};
use sp_core::hashing::twox_128;
......@@ -327,13 +409,20 @@ async fn create_election_ext<T: EPM::Config, B: BlockT>(
/// Compute the election at the given block number. It expects to NOT be `Phase::Off`. In other
/// words, the snapshot must exists on the given externalities.
fn mine_unchecked<T: EPM::Config>(
fn mine_unchecked<T, S>(
ext: &mut Ext,
iterations: usize,
do_feasibility: bool,
) -> Result<(EPM::RawSolution<EPM::SolutionOf<T>>, u32), Error> {
) -> Result<(EPM::RawSolution<EPM::SolutionOf<T>>, u32), Error<T>>
where
T: EPM::Config,
S: NposSolver<
Error = <<T as EPM::Config>::Solver as NposSolver>::Error,
AccountId = <<T as EPM::Config>::Solver as NposSolver>::AccountId,
>,
{
ext.execute_with(|| {
let (solution, _) = <EPM::Pallet<T>>::mine_solution(iterations)?;
let (solution, _) =
<EPM::Pallet<T>>::mine_solution::<S>().map_err::<Error<T>, _>(Into::into)?;
if do_feasibility {
let _ = <EPM::Pallet<T>>::feasibility_check(
solution.clone(),
......@@ -346,7 +435,7 @@ fn mine_unchecked<T: EPM::Config>(
}
#[allow(unused)]
fn mine_dpos<T: EPM::Config>(ext: &mut Ext) -> Result<(), Error> {
fn mine_dpos<T: EPM::Config>(ext: &mut Ext) -> Result<(), Error<T>> {
ext.execute_with(|| {
use std::collections::BTreeMap;
use EPM::RoundSnapshot;
......@@ -383,10 +472,10 @@ fn mine_dpos<T: EPM::Config>(ext: &mut Ext) -> Result<(), Error> {
})
}
pub(crate) async fn check_versions<T: frame_system::Config>(
pub(crate) async fn check_versions<T: frame_system::Config + EPM::Config>(
client: &WsClient,
print: bool,
) -> Result<(), Error> {
) -> Result<(), Error<T>> {
let linked_version = T::Version::get();
let on_chain_version = rpc_helpers::rpc::<sp_version::RuntimeVersion>(
client,
......@@ -486,7 +575,7 @@ async fn main() {
}
log::info!(target: LOG_TARGET, "connected to chain {:?}", chain);
let _ = any_runtime! {
any_runtime_unit! {
check_versions::<Runtime>(&client, true).await
};
......@@ -498,9 +587,18 @@ async fn main() {
let outcome = any_runtime! {
match command.clone() {
Command::Monitor(c) => monitor_cmd(&client, shared, c, signer_account).await,
Command::DryRun(c) => dry_run_cmd(&client, shared, c, signer_account).await,
Command::EmergencySolution => emergency_solution_cmd(shared.clone()).await,
Command::Monitor(c) => monitor_cmd(&client, shared, c, signer_account).await
.map_err(|e| {
log::error!(target: LOG_TARGET, "Monitor error: {:?}", e);
}),
Command::DryRun(c) => dry_run_cmd(&client, shared, c, signer_account).await
.map_err(|e| {
log::error!(target: LOG_TARGET, "DryRun error: {:?}", e);
}),
Command::EmergencySolution => emergency_solution_cmd(shared.clone()).await
.map_err(|e| {
log::error!(target: LOG_TARGET, "EmergencySolution error: {:?}", e);
}),
}
};
log::info!(target: LOG_TARGET, "round of execution finished. outcome = {:?}", outcome);
......
......@@ -30,10 +30,11 @@ use sc_transaction_pool_api::TransactionStatus;
async fn ensure_signed_phase<T: EPM::Config, B: BlockT>(
client: &WsClient,
at: B::Hash,
) -> Result<(), Error> {
) -> Result<(), Error<T>> {
let key = sp_core::storage::StorageKey(EPM::CurrentPhase::<T>::hashed_key().to_vec());
let phase = get_storage::<EPM::Phase<BlockNumber>>(client, params! {key, at})
.await?
.await
.map_err::<Error<T>, _>(Into::into)?
.unwrap_or_default();
if phase.is_signed() {
......@@ -50,7 +51,7 @@ async fn ensure_no_previous_solution<
>(
ext: &mut Ext,
us: &AccountId,
) -> Result<(), Error> {
) -> Result<(), Error<T>> {
use EPM::signed::SignedSubmissions;
ext.execute_with(|| {
if <SignedSubmissions<T>>::get().iter().any(|ss| &ss.who == us) {
......@@ -68,7 +69,7 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! {
shared: SharedConfig,
config: MonitorConfig,
signer: Signer,
) -> Result<(), Error> {
) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> {
use $crate::[<$runtime _runtime_exports>]::*;
let (sub, unsub) = if config.listen == "head" {
("chain_subscribeNewHeads", "chain_unsubscribeNewHeads")
......@@ -109,7 +110,8 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! {
continue;
}
let (raw_solution, witness) = crate::mine_unchecked::<Runtime>(&mut ext, config.iterations, true)?;
let (raw_solution, witness) = crate::mine_with::<Runtime>(&config.solver, &mut ext)?;
log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score);
let nonce = crate::get_account_info::<Runtime>(client, &signer.account, Some(hash))
......@@ -149,8 +151,7 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! {
TransactionStatus::InBlock(hash) => {
log::info!(target: LOG_TARGET, "included at {:?}", hash);
let key = frame_support::storage::storage_prefix(b"System", b"Events");
let events =get_storage::<
Vec<frame_system::EventRecord<Event, <Block as BlockT>::Hash>>
let events = get_storage::<Vec<frame_system::EventRecord<Event, <Block as BlockT>::Hash>>,
>(client, params!{ key, hash }).await?.unwrap_or_default();
log::info!(target: LOG_TARGET, "events at inclusion {:?}", events);
}
......
......@@ -20,6 +20,18 @@ use super::*;
use jsonrpsee_ws_client::types::traits::Client;
pub(crate) use jsonrpsee_ws_client::types::v2::params::JsonRpcParams;
#[derive(frame_support::DebugNoBound, thiserror::Error)]
pub(crate) enum RpcHelperError {
JsonRpsee(#[from] jsonrpsee_ws_client::types::Error),
Codec(#[from] codec::Error),
}
impl std::fmt::Display for RpcHelperError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<RpcHelperError as std::fmt::Debug>::fmt(self, f)
}
}
#[macro_export]
macro_rules! params {
($($param:expr),*) => {
......@@ -41,8 +53,11 @@ pub(crate) async fn rpc<'a, Ret: serde::de::DeserializeOwned>(
client: &WsClient,
method: &'a str,
params: JsonRpcParams<'a>,
) -> Result<Ret, Error> {
client.request::<Ret>(method, params).await.map_err(Into::into)
) -> Result<Ret, RpcHelperError> {
client
.request::<Ret>(method, params)
.await
.map_err::<RpcHelperError, _>(Into::into)
}
/// Make the rpc request, decode the outcome into `Dec`. Don't use for storage, it will fail for
......@@ -51,57 +66,26 @@ pub(crate) async fn rpc_decode<'a, Dec: codec::Decode>(
client: &WsClient,
method: &'a str,
params: JsonRpcParams<'a>,
) -> Result<Dec, Error> {
let bytes = rpc::<sp_core::Bytes>(client, method, params).await?;
<Dec as codec::Decode>::decode(&mut &*bytes.0).map_err(Into::into)
) -> Result<Dec, RpcHelperError> {
let bytes = rpc::<sp_core::Bytes>(client, method, params)
.await
.map_err::<RpcHelperError, _>(Into::into)?;
<Dec as codec::Decode>::decode(&mut &*bytes.0).map_err::<RpcHelperError, _>(Into::into)
}
/// Get the storage item.
pub(crate) async fn get_storage<'a, T: codec::Decode>(
client: &WsClient,
params: JsonRpcParams<'a>,
) -> Result<Option<T>, Error> {
let maybe_bytes = rpc::<Option<sp_core::Bytes>>(client, "state_getStorage", params).await?;
) -> Result<Option<T>, RpcHelperError> {
let maybe_bytes = rpc::<Option<sp_core::Bytes>>(client, "state_getStorage", params)
.await