Update bridges subtree (#5165)

* Squashed 'bridges/' changes from 1602249f0a..f220d2fcca

f220d2fcca Polkadot staging update (#1356)
02fd3d497c fix parse_transaction on Rialto+Millau (#1360)
bc191fd9a2 update parity-scale-codec to 3.1.2 (#1359)
a37226e79c update chain versions (#1358)
ff5d539fcb Update Substrate/Polkadot/Cumulus references (#1353)
1581f60cd5 Support dedicated lanes for pallets (#962)
0a7ccf5c57 ignore more "increase" alerts that are sometimes signalling NoData at startup (#1351)
31165127cc added no_stack_overflow_when_decoding_nested_call_during_dispatch test (#1349)
7000619eb8 replace From<>InboundLaneApi with direct storage reads (#1348)
515df10ccc added alerts for relay balances (#1347)
b56f6a87de Mortal conversion rate updater transactions (#1257)
20f2f331ec edition = "2021" (#1346)
99147d4f75 update regex to 1.5.5 (#1345)
686191f379 use DecodeLimit when decoding incoming calls (#1344)
a70c276006 get rid of '[No Data] Messages from Millau to Rialto are not being delivered' warnings (#1342)
01f29b8ac1 fix conversion rate metric in dashboards (#1341)
51c3bf351f Increase rate from metric when estimating fee (#1340)
3bb9c4f68f fix generator scripts to be consistent with updatedrelay output (#1339)
0475a1667b fixed mess with conversion rates (#1338)
d8fdd7d716 synchronize relay cli changes and token swap generator script (#1337)
6e928137a5 fix conversion rate override in token swap (#1336)
62d4a4811d override conversion rate in tokens swap generator (#1335)
ed9e1c839c fi typo in generator script (#1334)
3254b5af7a Override conversion rate when computing message fee (#1261)
66df68b5b8 Revert "Revert "override conversion rate in estimate-message-fee RPC (#1189)" (#1275)" (#1333)
0ca6fc6ef8 fix clippy issues (#1332)
5414b2fffb Reinitialize bridge relay subcommand (#1331)
a63d95ba7d removed extra *_RUNTIME_VERSION consts from relay code (#1330)
59fb18a310 fix typo in alert expression (#1329)
a6267a47ee Using-same-fork metric for finality and complex relay (#1327)
88d684d37e use mortal transactions in transaction resubmitter (#1326)
8ff88b6844 impl Decode for SignedExtensions (otherwise transaction resubmitter panicks) (#1325)
1ed09854f0 Encode and estimate Rococo/Wococo/Kusama/Polkadot messages (#1322)
ddb4517e13 Add some tests to check integrity of chain constants + bridge configuration (#1316)
bdeedb7ab9 Fix issues from cargo deny (#1311)
d3d79d01e0 expose fee multiplier metrics in messages relay (#1312)
c8b3f0ea16 Endow relayer account at target chain in message benchmarks (#1310)
f51ecd92b6 fix benchmarks before using it in Polkadot/Kusama/Rococo runtimes (#1309)
6935c619ad increase relay balance guard limits for Polkadot<>Kusama bridge (#1308)
7e31834c66 Fix mandatory headers scanning in on-demand relay (#1306)
92ddc3ea7a Polkadot-staging update (#1305)
3787193a31 fix session length of Rococo and Wococo (#1304)
eb468d29c0 Revert nightly docker pin (#1301)
e2d4c073e1 Use raw balance value if tokenDecimals property is missing (#1299)
108f4b29d1 Fix ss58 prefixes of Polkadot, Kusama and Westend used by relay (#1298)
64fbd2705e bump chain spec versions (#1297)
5707777b86 Bump Substrate/Polkadot/Cumulus refs (#1295)
29eecdf1fa Merge pull request #1294 from paritytech/polkadot-staging-update
1f0c05368e Relay balance metrics (#1291)
6356bb90b3 when messages pallet is halted, relay shall not submit messages delivery/confirmation transactions (#1289)
800dc2df8d when GRANDPA pallet is halted, relay shall not submit finality transactions (#1288)
3dd8e4f936 disable BEEFY allerts for Rialto (#1285)
f58fed7380 support version mode cli options in send-message subcommand (#1284)
3aac448da3 reuse polkadot-service code (#1273)
2bdbb651e1 replace latest_confirmed_nonce runtime APIs with direct storage reads (#1282)
5f9c6d241f move "common" code of messages pallet benchmarks helpers to the common library (#1281)
173d2d8229 Merge pull request #1280 from paritytech/polkadot-staging-update
8b9c4ec16d do not start spec_version guard when version mode is set to auto (#1278)
e98d682de2 removed extra messages benchmarks (#1279)
c730e25b61 Move benchmarks from Rialto to Millau (#1277)
54146416e7 Merge pull request #1276 from paritytech/polkadot-staging-update
df70118174 Merge branch 'master' into polkadot-staging-update
ed7def64c4 Revert "override conversion rate in estimate-message-fee RPC (#1189)" (#1275)
38c6c3a49f Use "production" floating tag when uilding docker image from version git tags (#1272)
ded9ff6dbb Replace InboundLaneApi::latest_received_nonce with direct storage read (#1269)
f704a741ee Polkadot staging update (#1270)
8c65f0d7ab verify that GRANDPA pallet is not initialized before submitting initialization transaction (#1267)
e7e83d8944 remove OutboundLaneApi::latest_received_nonce (#1262)
9f4b34acf1 bump rococo version (#1263)
82c08c5a87 read latest_generated_nonce directly from storage (#1260)
50ffb5dd08 override conversion rate in estimate-message-fee RPC (#1189)
467ca5ef59 move storage keys computation to primitivs (#1254)
4f9884066b remporary use pinned bridges-ci image in Dockerfile (#1258)
edfcb74e00 Change submit transaction spec_version and transaction_version query from chain (#1248)
4009d970d0 pin bridges-ci image (#1256)
65e51b5e1c decrease startup sleep to 5s for relays and to 120s for generators + remove curl (#1251)
3bc74355d9 Add missing RPC APIs to rialto parachain node (#1250)
80c9429284 Bump relay version to 1.0.0 (#1249)
9ead06af2a runtimes: fix call_size() test (#1245)
4fc8a29357 Use same endowed accounts set on dev/local chains (#1244)
fed54371c2 Refactor message relay helpers (#1234)
a15b4faae7 post-merge build fix (#1243)
52232d8d54 Fix transactions mortality (#1196)
c07bba931f Expose prometheus BEEFY metrics and add them to grafana dashboard (#1242)
f927775bd5 Refactor finality relay helpers (#1220)
7bf76f14a8 Update Rococo/Wococo version + prepare relay for Rococo<>Wococo bridge (#1241)
e860fecd04 Enable offchain indexing for Rialto/Millau nodes (#1239)
04d4d1c6b4 Enable Beefy debug logs in test deployment (#1237)
cd771f1089 Fix storage parameter name computation (#1238)
816ddd2dd2 Integrate BEEFY with Rialto & Millau runtimes (#1227)
d94b62b1ac update dependencies (#1229)
98eb9ee13d Add mut support (#1232)
ffef6f89f9 fixed set_operational in GRANDPA pallet (#1226)
bd2f8bfbd7 Add CODEOWNERS file (#1219)
6b5cf2b591 Unify metric names (#1209)
d1541e797e remove abandoned exchange relay (#1217)
39140d0b34 Remove unused `relays/headers` (#1216)
9bc071d42b Remove unused PoA<>Substrate bridge (#1210)
877e8d01e3 Fix UI deployment. (#1211)
6cd5775ebe Add `AtLeast32BitUnsigned` for MessageLance::SourceChainBalance (#1207)

git-subtree-dir: bridges
git-subtree-split: f220d2fccabbf141101d19456ecb4e3576a1d797

* fix compilation warnings
This commit is contained in:
Svyatoslav Nikolsky
2022-03-21 13:19:29 +03:00
committed by GitHub
parent 20da356434
commit 8e01ba9c03
212 changed files with 9704 additions and 7984 deletions
@@ -2,25 +2,27 @@
name = "relay-substrate-client"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
edition = "2021"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
async-std = { version = "1.6.5", features = ["attributes"] }
async-trait = "0.1.40"
codec = { package = "parity-scale-codec", version = "2.2.0" }
jsonrpsee-proc-macros = "0.3.1"
jsonrpsee-ws-client = "0.3.1"
codec = { package = "parity-scale-codec", version = "3.0.0" }
jsonrpsee = { version = "0.8", features = ["macros", "ws-client"] }
log = "0.4.11"
num-traits = "0.2"
rand = "0.7"
tokio = "1.8"
serde = { version = "1.0" }
tokio = { version = "1.8", features = ["rt-multi-thread"] }
thiserror = "1.0.26"
# Bridge dependencies
bp-header-chain = { path = "../../primitives/header-chain" }
bp-messages = { path = "../../primitives/messages" }
bp-runtime = { path = "../../primitives/runtime" }
pallet-bridge-messages = { path = "../../modules/messages" }
finality-relay = { path = "../finality" }
relay-utils = { path = "../utils" }
@@ -31,9 +33,10 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "mast
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -14,10 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use bp_runtime::{Chain as ChainBase, HashOf, TransactionEraOf};
use bp_messages::MessageNonce;
use bp_runtime::{Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEraOf};
use codec::{Codec, Encode};
use frame_support::weights::WeightToFeePolynomial;
use jsonrpsee_ws_client::types::{DeserializeOwned, Serialize};
use frame_support::weights::{Weight, WeightToFeePolynomial};
use jsonrpsee::core::{DeserializeOwned, Serialize};
use num_traits::Zero;
use sc_transaction_pool_api::TransactionStatus;
use sp_core::{storage::StorageKey, Pair};
@@ -32,6 +33,18 @@ use std::{fmt::Debug, time::Duration};
pub trait Chain: ChainBase + Clone {
/// Chain name.
const NAME: &'static str;
/// Identifier of the basic token of the chain (if applicable).
///
/// This identifier is used to fetch token price. In case of testnets, you may either
/// set it to `None`, or associate testnet with one of the existing tokens.
const TOKEN_ID: Option<&'static str>;
/// Name of the runtime API method that is returning best known finalized header number
/// and hash (as tuple).
///
/// Keep in mind that this method is normally provided by the other chain, which is
/// bridged with this chain.
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str;
/// Average block interval.
///
/// How often blocks are produced on that chain. It's suggested to set this value
@@ -45,12 +58,54 @@ pub trait Chain: ChainBase + Clone {
/// Block type.
type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>;
/// The aggregated `Call` type.
type Call: Clone + Dispatchable + Debug;
type Call: Clone + Codec + Dispatchable + Debug + Send;
/// Type that is used by the chain, to convert from weight to fee.
type WeightToFee: WeightToFeePolynomial<Balance = Self::Balance>;
}
/// Substrate-based chain that is using direct GRANDPA finality from minimal relay-client point of
/// view.
///
/// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement
/// this trait.
pub trait ChainWithGrandpa: Chain {
/// Name of the bridge GRANDPA pallet (used in `construct_runtime` macro call) that is deployed
/// at some other chain to bridge with this `ChainWithGrandpa`.
///
/// We assume that all chains that are bridging with this `ChainWithGrandpa` are using
/// the same name.
const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str;
}
/// Substrate-based chain with messaging support from minimal relay-client point of view.
pub trait ChainWithMessages: Chain {
/// Name of the bridge messages pallet (used in `construct_runtime` macro call) that is deployed
/// at some other chain to bridge with this `ChainWithMessages`.
///
/// We assume that all chains that are bridging with this `ChainWithMessages` are using
/// the same name.
const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str;
/// Name of the `To<ChainWithMessages>OutboundLaneApi::message_details` runtime API method.
/// The method is provided by the runtime that is bridged with this `ChainWithMessages`.
const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str;
/// Additional weight of the dispatch fee payment if dispatch is paid at the target chain
/// and this `ChainWithMessages` is the target chain.
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight;
/// Maximal number of unrewarded relayers in a single confirmation transaction at this
/// `ChainWithMessages`.
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce;
/// Maximal number of unconfirmed messages in a single confirmation transaction at this
/// `ChainWithMessages`.
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce;
/// Weights of message pallet calls.
type WeightInfo: pallet_bridge_messages::WeightInfoExt;
}
/// Call type used by the chain.
pub type CallOf<C> = <C as Chain>::Call;
/// Weight-to-Fee type used by the chain.
@@ -58,7 +113,7 @@ pub type WeightToFeeOf<C> = <C as Chain>::WeightToFee;
/// Transaction status of the chain.
pub type TransactionStatusOf<C> = TransactionStatus<HashOf<C>, HashOf<C>>;
/// Substrate-based chain with `frame_system::Config::AccountData` set to
/// Substrate-based chain with `AccountData` generic argument of `frame_system::AccountInfo` set to
/// the `pallet_balances::AccountData<Balance>`.
pub trait ChainWithBalances: Chain {
/// Return runtime storage key for getting `frame_system::AccountInfo` of given account.
@@ -79,10 +134,10 @@ pub trait BlockWithJustification<Header> {
}
/// Transaction before it is signed.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct UnsignedTransaction<C: Chain> {
/// Runtime call of this transaction.
pub call: C::Call,
pub call: EncodedOrDecodedCall<C::Call>,
/// Transaction nonce.
pub nonce: C::Index,
/// Tip included into transaction.
@@ -91,7 +146,7 @@ pub struct UnsignedTransaction<C: Chain> {
impl<C: Chain> UnsignedTransaction<C> {
/// Create new unsigned transaction with given call, nonce and zero tip.
pub fn new(call: C::Call, nonce: C::Index) -> Self {
pub fn new(call: EncodedOrDecodedCall<C::Call>, nonce: C::Index) -> Self {
Self { call, nonce, tip: Zero::zero() }
}
@@ -102,6 +157,9 @@ impl<C: Chain> UnsignedTransaction<C> {
}
}
/// Account key pair used by transactions signing scheme.
pub type AccountKeyPairOf<S> = <S as TransactionSignScheme>::AccountKeyPair;
/// Substrate-based chain transactions signing scheme.
pub trait TransactionSignScheme {
/// Chain that this scheme is to be used.
@@ -112,12 +170,9 @@ pub trait TransactionSignScheme {
type SignedTransaction: Clone + Debug + Codec + Send + 'static;
/// Create transaction for given runtime call, signed by given account.
fn sign_transaction(
genesis_hash: <Self::Chain as ChainBase>::Hash,
signer: &Self::AccountKeyPair,
era: TransactionEraOf<Self::Chain>,
unsigned: UnsignedTransaction<Self::Chain>,
) -> Self::SignedTransaction;
fn sign_transaction(param: SignParam<Self>) -> Result<Self::SignedTransaction, crate::Error>
where
Self: Sized;
/// Returns true if transaction is signed.
fn is_signed(tx: &Self::SignedTransaction) -> bool;
@@ -131,6 +186,22 @@ pub trait TransactionSignScheme {
fn parse_transaction(tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self::Chain>>;
}
/// Sign transaction parameters
pub struct SignParam<T: TransactionSignScheme> {
/// Version of the runtime specification.
pub spec_version: u32,
/// Transaction version
pub transaction_version: u32,
/// Hash of the genesis block.
pub genesis_hash: <T::Chain as ChainBase>::Hash,
/// Signer account
pub signer: T::AccountKeyPair,
/// Transaction era used by the chain.
pub era: TransactionEraOf<T::Chain>,
/// Transaction before it is signed.
pub unsigned: UnsignedTransaction<T::Chain>,
}
impl<Block: BlockT> BlockWithJustification<Block::Header> for SignedBlock<Block> {
fn header(&self) -> Block::Header {
self.block.header().clone()
@@ -18,8 +18,9 @@
use crate::{
chain::{Chain, ChainWithBalances, TransactionStatusOf},
rpc::Substrate,
ConnectionParams, Error, HashOf, HeaderIdOf, Result,
rpc::SubstrateClient,
AccountIdOf, BlockNumberOf, ConnectionParams, Error, HashOf, HeaderIdOf, HeaderOf, IndexOf,
Result,
};
use async_std::sync::{Arc, Mutex};
@@ -27,14 +28,12 @@ use async_trait::async_trait;
use codec::{Decode, Encode};
use frame_system::AccountInfo;
use futures::{SinkExt, StreamExt};
use jsonrpsee_ws_client::{
types::{
self as jsonrpsee_types, traits::SubscriptionClient, v2::params::JsonRpcParams,
DeserializeOwned,
},
WsClient as RpcClient, WsClientBuilder as RpcClientBuilder,
use jsonrpsee::{
core::{client::SubscriptionClientT, DeserializeOwned},
types::params::ParamsSer,
ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder},
};
use num_traits::{Bounded, Zero};
use num_traits::{Bounded, CheckedSub, One, Zero};
use pallet_balances::AccountData;
use pallet_transaction_payment::InclusionFee;
use relay_utils::{relay_loop::RECONNECT_DELAY, HeaderId};
@@ -60,6 +59,17 @@ pub struct Subscription<T>(Mutex<futures::channel::mpsc::Receiver<Option<T>>>);
/// Opaque GRANDPA authorities set.
pub type OpaqueGrandpaAuthoritiesSet = Vec<u8>;
/// Chain runtime version in client
#[derive(Clone, Debug)]
pub enum ChainRuntimeVersion {
/// Auto query from chain.
Auto,
/// Custom runtime version, defined by user.
/// the first is `spec_version`
/// the second is `transaction_version`
Custom(u32, u32),
}
/// Substrate client type.
///
/// Cloning `Client` is a cheap operation.
@@ -77,6 +87,8 @@ pub struct Client<C: Chain> {
/// transactions will be rejected from the pool. This lock is here to prevent situations like
/// that.
submit_signed_extrinsic_lock: Arc<Mutex<()>>,
/// Saved chain runtime version
chain_runtime_version: ChainRuntimeVersion,
}
#[async_trait]
@@ -99,6 +111,7 @@ impl<C: Chain> Clone for Client<C> {
client: self.client.clone(),
genesis_hash: self.genesis_hash,
submit_signed_extrinsic_lock: self.submit_signed_extrinsic_lock.clone(),
chain_runtime_version: self.chain_runtime_version.clone(),
}
}
}
@@ -140,16 +153,26 @@ impl<C: Chain> Client<C> {
let genesis_hash_client = client.clone();
let genesis_hash = tokio
.spawn(async move {
Substrate::<C>::chain_get_block_hash(&*genesis_hash_client, number).await
SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::chain_get_block_hash(&*genesis_hash_client, Some(number))
.await
})
.await??;
let chain_runtime_version = params.chain_runtime_version.clone();
Ok(Self {
tokio,
params,
client,
genesis_hash,
submit_signed_extrinsic_lock: Arc::new(Mutex::new(())),
chain_runtime_version,
})
}
@@ -178,10 +201,31 @@ impl<C: Chain> Client<C> {
}
impl<C: Chain> Client<C> {
/// Return simple runtime version, only include `spec_version` and `transaction_version`.
pub async fn simple_runtime_version(&self) -> Result<(u32, u32)> {
let (spec_version, transaction_version) = match self.chain_runtime_version {
ChainRuntimeVersion::Auto => {
let runtime_version = self.runtime_version().await?;
(runtime_version.spec_version, runtime_version.transaction_version)
},
ChainRuntimeVersion::Custom(spec_version, transaction_version) =>
(spec_version, transaction_version),
};
Ok((spec_version, transaction_version))
}
/// Returns true if client is connected to at least one peer and is in synced state.
pub async fn ensure_synced(&self) -> Result<()> {
self.jsonrpsee_execute(|client| async move {
let health = Substrate::<C>::system_health(&*client).await?;
let health = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::system_health(&*client)
.await?;
let is_synced = !health.is_syncing && (!health.should_have_peers || health.peers > 0);
if is_synced {
Ok(())
@@ -200,7 +244,15 @@ impl<C: Chain> Client<C> {
/// Return hash of the best finalized block.
pub async fn best_finalized_header_hash(&self) -> Result<C::Hash> {
self.jsonrpsee_execute(|client| async move {
Ok(Substrate::<C>::chain_get_finalized_head(&*client).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::chain_get_finalized_head(&*client)
.await?)
})
.await
}
@@ -216,7 +268,15 @@ impl<C: Chain> Client<C> {
C::Header: DeserializeOwned,
{
self.jsonrpsee_execute(|client| async move {
Ok(Substrate::<C>::chain_get_header(&*client, None).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::chain_get_header(&*client, None)
.await?)
})
.await
}
@@ -224,7 +284,15 @@ impl<C: Chain> Client<C> {
/// Get a Substrate block from its hash.
pub async fn get_block(&self, block_hash: Option<C::Hash>) -> Result<C::SignedBlock> {
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::chain_get_block(&*client, block_hash).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::chain_get_block(&*client, block_hash)
.await?)
})
.await
}
@@ -235,7 +303,15 @@ impl<C: Chain> Client<C> {
C::Header: DeserializeOwned,
{
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::chain_get_header(&*client, block_hash).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::chain_get_header(&*client, Some(block_hash))
.await?)
})
.await
}
@@ -243,7 +319,15 @@ impl<C: Chain> Client<C> {
/// Get a Substrate block hash by its number.
pub async fn block_hash_by_number(&self, number: C::BlockNumber) -> Result<C::Hash> {
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::chain_get_block_hash(&*client, number).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::chain_get_block_hash(&*client, Some(number))
.await?)
})
.await
}
@@ -261,7 +345,15 @@ impl<C: Chain> Client<C> {
/// Return runtime version.
pub async fn runtime_version(&self) -> Result<RuntimeVersion> {
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::state_runtime_version(&*client).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_runtime_version(&*client)
.await?)
})
.await
}
@@ -287,7 +379,15 @@ impl<C: Chain> Client<C> {
block_hash: Option<C::Hash>,
) -> Result<Option<StorageData>> {
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::state_get_storage(&*client, storage_key, block_hash).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_get_storage(&*client, storage_key, block_hash)
.await?)
})
.await
}
@@ -299,10 +399,16 @@ impl<C: Chain> Client<C> {
{
self.jsonrpsee_execute(move |client| async move {
let storage_key = C::account_info_storage_key(&account);
let encoded_account_data =
Substrate::<C>::state_get_storage(&*client, storage_key, None)
.await?
.ok_or(Error::AccountDoesNotExist)?;
let encoded_account_data = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_get_storage(&*client, storage_key, None)
.await?
.ok_or(Error::AccountDoesNotExist)?;
let decoded_account_data = AccountInfo::<C::Index, AccountData<C::Balance>>::decode(
&mut &encoded_account_data.0[..],
)
@@ -317,7 +423,15 @@ impl<C: Chain> Client<C> {
/// Note: It's the caller's responsibility to make sure `account` is a valid SS58 address.
pub async fn next_account_index(&self, account: C::AccountId) -> Result<C::Index> {
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::system_account_next_index(&*client, account).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::system_account_next_index(&*client, account)
.await?)
})
.await
}
@@ -327,7 +441,15 @@ impl<C: Chain> Client<C> {
/// Note: The given transaction needs to be SCALE encoded beforehand.
pub async fn submit_unsigned_extrinsic(&self, transaction: Bytes) -> Result<C::Hash> {
self.jsonrpsee_execute(move |client| async move {
let tx_hash = Substrate::<C>::author_submit_extrinsic(&*client, transaction).await?;
let tx_hash = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::author_submit_extrinsic(&*client, transaction)
.await?;
log::trace!(target: "bridge", "Sent transaction to Substrate node: {:?}", tx_hash);
Ok(tx_hash)
})
@@ -344,15 +466,33 @@ impl<C: Chain> Client<C> {
pub async fn submit_signed_extrinsic(
&self,
extrinsic_signer: C::AccountId,
prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Bytes + Send + 'static,
prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Result<Bytes> + Send + 'static,
) -> Result<C::Hash> {
let _guard = self.submit_signed_extrinsic_lock.lock().await;
let transaction_nonce = self.next_account_index(extrinsic_signer).await?;
let best_header = self.best_header().await?;
let best_header_id = HeaderId(*best_header.number(), best_header.hash());
// By using parent of best block here, we are protecing again best-block reorganizations.
// E.g. transaction my have been submitted when the best block was `A[num=100]`. Then it has
// been changed to `B[num=100]`. Hash of `A` has been included into transaction signature
// payload. So when signature will be checked, the check will fail and transaction will be
// dropped from the pool.
let best_header_id = match best_header.number().checked_sub(&One::one()) {
Some(parent_block_number) => HeaderId(parent_block_number, *best_header.parent_hash()),
None => HeaderId(*best_header.number(), best_header.hash()),
};
self.jsonrpsee_execute(move |client| async move {
let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce);
let tx_hash = Substrate::<C>::author_submit_extrinsic(&*client, extrinsic).await?;
let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?;
let tx_hash = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::author_submit_extrinsic(&*client, extrinsic)
.await?;
log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash);
Ok(tx_hash)
})
@@ -364,7 +504,7 @@ impl<C: Chain> Client<C> {
pub async fn submit_and_watch_signed_extrinsic(
&self,
extrinsic_signer: C::AccountId,
prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Bytes + Send + 'static,
prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Result<Bytes> + Send + 'static,
) -> Result<Subscription<TransactionStatusOf<C>>> {
let _guard = self.submit_signed_extrinsic_lock.lock().await;
let transaction_nonce = self.next_account_index(extrinsic_signer).await?;
@@ -372,13 +512,13 @@ impl<C: Chain> Client<C> {
let best_header_id = HeaderId(*best_header.number(), best_header.hash());
let subscription = self
.jsonrpsee_execute(move |client| async move {
let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce);
let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?;
let tx_hash = C::Hasher::hash(&extrinsic.0);
let subscription = client
.subscribe(
"author_submitAndWatchExtrinsic",
JsonRpcParams::Array(vec![jsonrpsee_types::to_json_value(extrinsic)
.map_err(|e| Error::RpcError(e.into()))?]),
Some(ParamsSer::Array(vec![jsonrpsee::core::to_json_value(extrinsic)
.map_err(|e| Error::RpcError(e.into()))?])),
"author_unwatchExtrinsic",
)
.await?;
@@ -399,7 +539,15 @@ impl<C: Chain> Client<C> {
/// Returns pending extrinsics from transaction pool.
pub async fn pending_extrinsics(&self) -> Result<Vec<Bytes>> {
self.jsonrpsee_execute(move |client| async move {
Ok(Substrate::<C>::author_pending_extrinsics(&*client).await?)
Ok(SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::author_pending_extrinsics(&*client)
.await?)
})
.await
}
@@ -414,8 +562,15 @@ impl<C: Chain> Client<C> {
let call = SUB_API_TXPOOL_VALIDATE_TRANSACTION.to_string();
let data = Bytes((TransactionSource::External, transaction, at_block).encode());
let encoded_response =
Substrate::<C>::state_call(&*client, call, data, Some(at_block)).await?;
let encoded_response = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_call(&*client, call, data, Some(at_block))
.await?;
let validity = TransactionValidity::decode(&mut &encoded_response.0[..])
.map_err(Error::ResponseParseFailed)?;
@@ -430,8 +585,15 @@ impl<C: Chain> Client<C> {
transaction: Bytes,
) -> Result<InclusionFee<C::Balance>> {
self.jsonrpsee_execute(move |client| async move {
let fee_details =
Substrate::<C>::payment_query_fee_details(&*client, transaction, None).await?;
let fee_details = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::payment_query_fee_details(&*client, transaction, None)
.await?;
let inclusion_fee = fee_details
.inclusion_fee
.map(|inclusion_fee| InclusionFee {
@@ -463,8 +625,15 @@ impl<C: Chain> Client<C> {
let call = SUB_API_GRANDPA_AUTHORITIES.to_string();
let data = Bytes(Vec::new());
let encoded_response =
Substrate::<C>::state_call(&*client, call, data, Some(block)).await?;
let encoded_response = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_call(&*client, call, data, Some(block))
.await?;
let authority_list = encoded_response.0;
Ok(authority_list)
@@ -480,9 +649,16 @@ impl<C: Chain> Client<C> {
at_block: Option<C::Hash>,
) -> Result<Bytes> {
self.jsonrpsee_execute(move |client| async move {
Substrate::<C>::state_call(&*client, method, data, at_block)
.await
.map_err(Into::into)
SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_call(&*client, method, data, at_block)
.await
.map_err(Into::into)
})
.await
}
@@ -494,10 +670,36 @@ impl<C: Chain> Client<C> {
at_block: C::Hash,
) -> Result<StorageProof> {
self.jsonrpsee_execute(move |client| async move {
Substrate::<C>::state_prove_storage(&*client, keys, Some(at_block))
.await
.map(|proof| StorageProof::new(proof.proof.into_iter().map(|b| b.0)))
.map_err(Into::into)
SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::state_prove_storage(&*client, keys, Some(at_block))
.await
.map(|proof| {
StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect::<Vec<_>>())
})
.map_err(Into::into)
})
.await
}
/// Return `tokenDecimals` property from the set of chain properties.
pub async fn token_decimals(&self) -> Result<Option<u64>> {
self.jsonrpsee_execute(move |client| async move {
let system_properties = SubstrateClient::<
AccountIdOf<C>,
BlockNumberOf<C>,
HashOf<C>,
HeaderOf<C>,
IndexOf<C>,
C::SignedBlock,
>::system_properties(&*client)
.await?;
Ok(system_properties.get("tokenDecimals").and_then(|v| v.as_u64()))
})
.await
}
@@ -509,7 +711,7 @@ impl<C: Chain> Client<C> {
Ok(client
.subscribe(
"grandpa_subscribeJustifications",
JsonRpcParams::NoParams,
None,
"grandpa_unsubscribeJustifications",
)
.await?)
@@ -549,26 +751,16 @@ impl<T: DeserializeOwned> Subscription<T> {
async fn background_worker(
chain_name: String,
item_type: String,
mut subscription: jsonrpsee_types::Subscription<T>,
mut subscription: jsonrpsee::core::client::Subscription<T>,
mut sender: futures::channel::mpsc::Sender<Option<T>>,
) {
loop {
match subscription.next().await {
Ok(Some(item)) =>
Some(Ok(item)) =>
if sender.send(Some(item)).await.is_err() {
break
},
Ok(None) => {
log::trace!(
target: "bridge",
"{} {} subscription stream has returned None. Stream needs to be restarted.",
chain_name,
item_type,
);
let _ = sender.send(None).await;
break
},
Err(e) => {
Some(Err(e)) => {
log::trace!(
target: "bridge",
"{} {} subscription stream has returned '{:?}'. Stream needs to be restarted.",
@@ -579,6 +771,16 @@ impl<T: DeserializeOwned> Subscription<T> {
let _ = sender.send(None).await;
break
},
None => {
log::trace!(
target: "bridge",
"{} {} subscription stream has returned None. Stream needs to be restarted.",
chain_name,
item_type,
);
let _ = sender.send(None).await;
break
},
}
}
}
@@ -16,7 +16,7 @@
//! Substrate node RPC errors.
use jsonrpsee_ws_client::types::Error as RpcError;
use jsonrpsee::core::Error as RpcError;
use relay_utils::MaybeConnectionError;
use sc_rpc_api::system::Health;
use sp_runtime::transaction_validity::TransactionValidityError;
@@ -51,6 +51,9 @@ pub enum Error {
/// The client we're connected to is not synced, so we can't rely on its state.
#[error("Substrate client is not synced {0}.")]
ClientNotSynced(Health),
/// The bridge pallet is halted and all transactions will be rejected.
#[error("Bridge pallet is halted.")]
BridgePalletIsHalted,
/// An error has happened when we have tried to parse storage proof.
#[error("Error when parsing storage proof: {0:?}.")]
StorageProofError(bp_runtime::StorageProofError),
@@ -1,172 +0,0 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Default generic implementation of finality source for basic Substrate client.
use crate::{
chain::{BlockWithJustification, Chain},
client::Client,
error::Error,
sync_header::SyncHeader,
};
use async_std::sync::{Arc, Mutex};
use async_trait::async_trait;
use bp_header_chain::justification::GrandpaJustification;
use codec::Decode;
use finality_relay::{FinalitySyncPipeline, SourceClient, SourceHeader};
use futures::stream::{unfold, Stream, StreamExt};
use relay_utils::relay_loop::Client as RelayClient;
use sp_runtime::traits::Header as HeaderT;
use std::{marker::PhantomData, pin::Pin};
/// Shared updatable reference to the maximal header number that we want to sync from the source.
pub type RequiredHeaderNumberRef<C> = Arc<Mutex<<C as bp_runtime::Chain>::BlockNumber>>;
/// Substrate node as finality source.
pub struct FinalitySource<C: Chain, P> {
client: Client<C>,
maximal_header_number: Option<RequiredHeaderNumberRef<C>>,
_phantom: PhantomData<P>,
}
impl<C: Chain, P> FinalitySource<C, P> {
/// Create new headers source using given client.
pub fn new(
client: Client<C>,
maximal_header_number: Option<RequiredHeaderNumberRef<C>>,
) -> Self {
FinalitySource { client, maximal_header_number, _phantom: Default::default() }
}
/// Returns reference to the underlying RPC client.
pub fn client(&self) -> &Client<C> {
&self.client
}
/// Returns best finalized block number.
pub async fn on_chain_best_finalized_block_number(&self) -> Result<C::BlockNumber, Error> {
// we **CAN** continue to relay finality proofs if source node is out of sync, because
// target node may be missing proofs that are already available at the source
let finalized_header_hash = self.client.best_finalized_header_hash().await?;
let finalized_header = self.client.header_by_hash(finalized_header_hash).await?;
Ok(*finalized_header.number())
}
}
impl<C: Chain, P> Clone for FinalitySource<C, P> {
fn clone(&self) -> Self {
FinalitySource {
client: self.client.clone(),
maximal_header_number: self.maximal_header_number.clone(),
_phantom: Default::default(),
}
}
}
#[async_trait]
impl<C: Chain, P: FinalitySyncPipeline> RelayClient for FinalitySource<C, P> {
type Error = Error;
async fn reconnect(&mut self) -> Result<(), Error> {
self.client.reconnect().await
}
}
#[async_trait]
impl<C, P> SourceClient<P> for FinalitySource<C, P>
where
C: Chain,
C::BlockNumber: relay_utils::BlockNumberBase,
P: FinalitySyncPipeline<
Hash = C::Hash,
Number = C::BlockNumber,
Header = SyncHeader<C::Header>,
FinalityProof = GrandpaJustification<C::Header>,
>,
P::Header: SourceHeader<C::BlockNumber>,
{
type FinalityProofsStream = Pin<Box<dyn Stream<Item = GrandpaJustification<C::Header>> + Send>>;
async fn best_finalized_block_number(&self) -> Result<P::Number, Error> {
let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?;
// never return block number larger than requested. This way we'll never sync headers
// past `maximal_header_number`
if let Some(ref maximal_header_number) = self.maximal_header_number {
let maximal_header_number = *maximal_header_number.lock().await;
if finalized_header_number > maximal_header_number {
finalized_header_number = maximal_header_number;
}
}
Ok(finalized_header_number)
}
async fn header_and_finality_proof(
&self,
number: P::Number,
) -> Result<(P::Header, Option<P::FinalityProof>), Error> {
let header_hash = self.client.block_hash_by_number(number).await?;
let signed_block = self.client.get_block(Some(header_hash)).await?;
let justification = signed_block
.justification()
.map(|raw_justification| {
GrandpaJustification::<C::Header>::decode(&mut raw_justification.as_slice())
})
.transpose()
.map_err(Error::ResponseParseFailed)?;
Ok((signed_block.header().into(), justification))
}
async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
Ok(unfold(
self.client.clone().subscribe_justifications().await?,
move |subscription| async move {
loop {
let log_error = |err| {
log::error!(
target: "bridge",
"Failed to read justification target from the {} justifications stream: {:?}",
P::SOURCE_NAME,
err,
);
};
let next_justification = subscription
.next()
.await
.map_err(|err| log_error(err.to_string()))
.ok()??;
let decoded_justification =
GrandpaJustification::<C::Header>::decode(&mut &next_justification[..]);
let justification = match decoded_justification {
Ok(j) => j,
Err(err) => {
log_error(format!("decode failed with error {:?}", err));
continue
},
};
return Some((justification, subscription))
}
},
)
.boxed())
}
}
@@ -64,6 +64,13 @@ pub fn abort_on_spec_version_change<C: ChainWithBalances>(
expected_spec_version: u32,
) {
async_std::task::spawn(async move {
log::info!(
target: "bridge-guard",
"Starting spec_version guard for {}. Expected spec_version: {}",
C::NAME,
expected_spec_version,
);
loop {
let actual_spec_version = env.runtime_version().await;
match actual_spec_version {
@@ -103,6 +110,14 @@ pub fn abort_when_account_balance_decreased<C: ChainWithBalances>(
const DAY: Duration = Duration::from_secs(60 * 60 * 24);
async_std::task::spawn(async move {
log::info!(
target: "bridge-guard",
"Starting balance guard for {}/{:?}. Maximal decrease: {:?}",
C::NAME,
account_id,
maximal_decrease,
);
let mut balances = VecDeque::new();
loop {
@@ -181,7 +196,7 @@ impl<C: ChainWithBalances> Environment<C> for Client<C> {
#[cfg(test)]
mod tests {
use super::*;
use frame_support::weights::IdentityFee;
use frame_support::weights::{IdentityFee, Weight};
use futures::{
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
future::FutureExt,
@@ -202,10 +217,19 @@ mod tests {
type Balance = u32;
type Index = u32;
type Signature = sp_runtime::testing::TestSignature;
fn max_extrinsic_size() -> u32 {
unreachable!()
}
fn max_extrinsic_weight() -> Weight {
unreachable!()
}
}
impl Chain for TestChain {
const NAME: &'static str = "Test";
const TOKEN_ID: Option<&'static str> = None;
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "BestTestHeader";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1);
const STORAGE_PROOF_OVERHEAD: u32 = 0;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0;
@@ -24,7 +24,6 @@ mod error;
mod rpc;
mod sync_header;
pub mod finality_source;
pub mod guard;
pub mod metrics;
@@ -32,10 +31,11 @@ use std::time::Duration;
pub use crate::{
chain::{
BlockWithJustification, CallOf, Chain, ChainWithBalances, TransactionSignScheme,
TransactionStatusOf, UnsignedTransaction, WeightToFeeOf,
AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances,
ChainWithGrandpa, ChainWithMessages, SignParam, TransactionSignScheme, TransactionStatusOf,
UnsignedTransaction, WeightToFeeOf,
},
client::{Client, OpaqueGrandpaAuthoritiesSet, Subscription},
client::{ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, Subscription},
error::{Error, Result},
sync_header::SyncHeader,
};
@@ -56,11 +56,18 @@ pub struct ConnectionParams {
pub port: u16,
/// Use secure websocket connection.
pub secure: bool,
/// Defined chain runtime version
pub chain_runtime_version: ChainRuntimeVersion,
}
impl Default for ConnectionParams {
fn default() -> Self {
ConnectionParams { host: "localhost".into(), port: 9944, secure: false }
ConnectionParams {
host: "localhost".into(),
port: 9944,
secure: false,
chain_runtime_version: ChainRuntimeVersion::Auto,
}
}
}
@@ -14,48 +14,84 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::{chain::Chain, client::Client};
use crate::{chain::Chain, client::Client, Error as SubstrateError};
use async_std::sync::{Arc, RwLock};
use async_trait::async_trait;
use codec::Decode;
use num_traits::One;
use relay_utils::metrics::{
metric_name, register, F64SharedRef, Gauge, Metric, PrometheusError, Registry,
StandaloneMetric, F64,
};
use sp_core::storage::StorageKey;
use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber};
use std::time::Duration;
use sp_core::storage::{StorageData, StorageKey};
use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber, FixedU128};
use std::{marker::PhantomData, time::Duration};
/// Storage value update interval (in blocks).
const UPDATE_INTERVAL_IN_BLOCKS: u32 = 5;
/// Metric that represents fixed-point runtime storage value as float gauge.
#[derive(Clone, Debug)]
pub struct FloatStorageValueMetric<C: Chain, T: Clone> {
client: Client<C>,
storage_key: StorageKey,
maybe_default_value: Option<T>,
metric: Gauge<F64>,
shared_value_ref: F64SharedRef,
/// Fied-point storage value and the way it is decoded from the raw storage value.
pub trait FloatStorageValue: 'static + Clone + Send + Sync {
/// Type of the value.
type Value: FixedPointNumber;
/// Try to decode value from the raw storage value.
fn decode(
&self,
maybe_raw_value: Option<StorageData>,
) -> Result<Option<Self::Value>, SubstrateError>;
}
impl<C: Chain, T: Decode + FixedPointNumber> FloatStorageValueMetric<C, T> {
/// Implementation of `FloatStorageValue` that expects encoded `FixedU128` value and returns `1` if
/// value is missing from the storage.
#[derive(Clone, Debug, Default)]
pub struct FixedU128OrOne;
impl FloatStorageValue for FixedU128OrOne {
type Value = FixedU128;
fn decode(
&self,
maybe_raw_value: Option<StorageData>,
) -> Result<Option<Self::Value>, SubstrateError> {
maybe_raw_value
.map(|raw_value| {
FixedU128::decode(&mut &raw_value.0[..])
.map_err(SubstrateError::ResponseParseFailed)
.map(Some)
})
.unwrap_or_else(|| Ok(Some(FixedU128::one())))
}
}
/// Metric that represents fixed-point runtime storage value as float gauge.
#[derive(Clone, Debug)]
pub struct FloatStorageValueMetric<C: Chain, V: FloatStorageValue> {
value_converter: V,
client: Client<C>,
storage_key: StorageKey,
metric: Gauge<F64>,
shared_value_ref: F64SharedRef,
_phantom: PhantomData<V>,
}
impl<C: Chain, V: FloatStorageValue> FloatStorageValueMetric<C, V> {
/// Create new metric.
pub fn new(
value_converter: V,
client: Client<C>,
storage_key: StorageKey,
maybe_default_value: Option<T>,
name: String,
help: String,
) -> Result<Self, PrometheusError> {
let shared_value_ref = Arc::new(RwLock::new(None));
Ok(FloatStorageValueMetric {
value_converter,
client,
storage_key,
maybe_default_value,
metric: Gauge::new(metric_name(None, &name), help)?,
shared_value_ref,
_phantom: Default::default(),
})
}
@@ -65,20 +101,14 @@ impl<C: Chain, T: Decode + FixedPointNumber> FloatStorageValueMetric<C, T> {
}
}
impl<C: Chain, T> Metric for FloatStorageValueMetric<C, T>
where
T: 'static + Decode + Send + Sync + FixedPointNumber,
{
impl<C: Chain, V: FloatStorageValue> Metric for FloatStorageValueMetric<C, V> {
fn register(&self, registry: &Registry) -> Result<(), PrometheusError> {
register(self.metric.clone(), registry).map(drop)
}
}
#[async_trait]
impl<C: Chain, T> StandaloneMetric for FloatStorageValueMetric<C, T>
where
T: 'static + Decode + Send + Sync + FixedPointNumber,
{
impl<C: Chain, V: FloatStorageValue> StandaloneMetric for FloatStorageValueMetric<C, V> {
fn update_interval(&self) -> Duration {
C::AVERAGE_BLOCK_INTERVAL * UPDATE_INTERVAL_IN_BLOCKS
}
@@ -86,16 +116,18 @@ where
async fn update(&self) {
let value = self
.client
.storage_value::<T>(self.storage_key.clone(), None)
.raw_storage_value(self.storage_key.clone(), None)
.await
.map(|maybe_storage_value| {
maybe_storage_value.or(self.maybe_default_value).map(|storage_value| {
storage_value.into_inner().unique_saturated_into() as f64 /
T::DIV.unique_saturated_into() as f64
.and_then(|maybe_storage_value| {
self.value_converter.decode(maybe_storage_value).map(|maybe_fixed_point_value| {
maybe_fixed_point_value.map(|fixed_point_value| {
fixed_point_value.into_inner().unique_saturated_into() as f64 /
V::Value::DIV.unique_saturated_into() as f64
})
})
})
.map_err(drop);
relay_utils::metrics::set_gauge_value(&self.metric, value);
.map_err(|e| e.to_string());
relay_utils::metrics::set_gauge_value(&self.metric, value.clone());
*self.shared_value_ref.write().await = value.ok().and_then(|x| x);
}
}
@@ -16,7 +16,7 @@
//! Contains several Substrate-specific metrics that may be exposed by relay.
pub use float_storage_value::FloatStorageValueMetric;
pub use float_storage_value::{FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric};
pub use storage_proof_overhead::StorageProofOverheadMetric;
mod float_storage_value;
@@ -16,8 +16,7 @@
//! The most generic Substrate node RPC interface.
use crate::chain::Chain;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use pallet_transaction_payment_rpc_runtime_api::FeeDetails;
use sc_rpc_api::{state::ReadProof, system::Health};
use sp_core::{
@@ -27,33 +26,51 @@ use sp_core::{
use sp_rpc::number::NumberOrHex;
use sp_version::RuntimeVersion;
jsonrpsee_proc_macros::rpc_client_api! {
pub(crate) Substrate<C: Chain> {
#[rpc(method = "system_health", positional_params)]
fn system_health() -> Health;
#[rpc(method = "chain_getHeader", positional_params)]
fn chain_get_header(block_hash: Option<C::Hash>) -> C::Header;
#[rpc(method = "chain_getFinalizedHead", positional_params)]
fn chain_get_finalized_head() -> C::Hash;
#[rpc(method = "chain_getBlock", positional_params)]
fn chain_get_block(block_hash: Option<C::Hash>) -> C::SignedBlock;
#[rpc(method = "chain_getBlockHash", positional_params)]
fn chain_get_block_hash(block_number: Option<C::BlockNumber>) -> C::Hash;
#[rpc(method = "system_accountNextIndex", positional_params)]
fn system_account_next_index(account_id: C::AccountId) -> C::Index;
#[rpc(method = "author_submitExtrinsic", positional_params)]
fn author_submit_extrinsic(extrinsic: Bytes) -> C::Hash;
#[rpc(method = "author_pendingExtrinsics", positional_params)]
fn author_pending_extrinsics() -> Vec<Bytes>;
#[rpc(method = "state_call", positional_params)]
fn state_call(method: String, data: Bytes, at_block: Option<C::Hash>) -> Bytes;
#[rpc(method = "state_getStorage", positional_params)]
fn state_get_storage(key: StorageKey, at_block: Option<C::Hash>) -> Option<StorageData>;
#[rpc(method = "state_getReadProof", positional_params)]
fn state_prove_storage(keys: Vec<StorageKey>, hash: Option<C::Hash>) -> ReadProof<C::Hash>;
#[rpc(method = "state_getRuntimeVersion", positional_params)]
fn state_runtime_version() -> RuntimeVersion;
#[rpc(method = "payment_queryFeeDetails", positional_params)]
fn payment_query_fee_details(extrinsic: Bytes, at_block: Option<C::Hash>) -> FeeDetails<NumberOrHex>;
}
#[rpc(client)]
pub(crate) trait Substrate<AccountId, BlockNumber, Hash, Header, Index, SignedBlock> {
#[method(name = "system_health", param_kind = array)]
async fn system_health(&self) -> RpcResult<Health>;
#[method(name = "system_properties", param_kind = array)]
async fn system_properties(&self) -> RpcResult<sc_chain_spec::Properties>;
#[method(name = "chain_getHeader", param_kind = array)]
async fn chain_get_header(&self, block_hash: Option<Hash>) -> RpcResult<Header>;
#[method(name = "chain_getFinalizedHead", param_kind = array)]
async fn chain_get_finalized_head(&self) -> RpcResult<Hash>;
#[method(name = "chain_getBlock", param_kind = array)]
async fn chain_get_block(&self, block_hash: Option<Hash>) -> RpcResult<SignedBlock>;
#[method(name = "chain_getBlockHash", param_kind = array)]
async fn chain_get_block_hash(&self, block_number: Option<BlockNumber>) -> RpcResult<Hash>;
#[method(name = "system_accountNextIndex", param_kind = array)]
async fn system_account_next_index(&self, account_id: AccountId) -> RpcResult<Index>;
#[method(name = "author_submitExtrinsic", param_kind = array)]
async fn author_submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult<Hash>;
#[method(name = "author_pendingExtrinsics", param_kind = array)]
async fn author_pending_extrinsics(&self) -> RpcResult<Vec<Bytes>>;
#[method(name = "state_call", param_kind = array)]
async fn state_call(
&self,
method: String,
data: Bytes,
at_block: Option<Hash>,
) -> RpcResult<Bytes>;
#[method(name = "state_getStorage", param_kind = array)]
async fn state_get_storage(
&self,
key: StorageKey,
at_block: Option<Hash>,
) -> RpcResult<Option<StorageData>>;
#[method(name = "state_getReadProof", param_kind = array)]
async fn state_prove_storage(
&self,
keys: Vec<StorageKey>,
hash: Option<Hash>,
) -> RpcResult<ReadProof<Hash>>;
#[method(name = "state_getRuntimeVersion", param_kind = array)]
async fn state_runtime_version(&self) -> RpcResult<RuntimeVersion>;
#[method(name = "payment_queryFeeDetails", param_kind = array)]
async fn payment_query_fee_details(
&self,
extrinsic: Bytes,
at_block: Option<Hash>,
) -> RpcResult<FeeDetails<NumberOrHex>>;
}
@@ -44,7 +44,11 @@ impl<Header> From<Header> for SyncHeader<Header> {
}
}
impl<Header: HeaderT> FinalitySourceHeader<Header::Number> for SyncHeader<Header> {
impl<Header: HeaderT> FinalitySourceHeader<Header::Hash, Header::Number> for SyncHeader<Header> {
fn hash(&self) -> Header::Hash {
self.0.hash()
}
fn number(&self) -> Header::Number {
*self.0.number()
}