referrerpolicy=no-referrer-when-downgrade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
// 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/>.

use crate::calls::UtilityCall;

use crate::SimpleRuntimeVersion;
use bp_header_chain::ChainWithGrandpa as ChainWithGrandpaBase;
use bp_messages::ChainWithMessages as ChainWithMessagesBase;
use bp_runtime::{
	Chain as ChainBase, EncodedOrDecodedCall, HashOf, Parachain as ParachainBase, TransactionEra,
	TransactionEraOf, UnderlyingChainProvider,
};
use codec::{Codec, Decode, Encode};
use jsonrpsee::core::{DeserializeOwned, Serialize};
use num_traits::Zero;
use sc_transaction_pool_api::TransactionStatus;
use scale_info::TypeInfo;
use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{
	generic::SignedBlock,
	traits::{Block as BlockT, Member},
	ConsensusEngineId, EncodedJustification,
};
use std::{fmt::Debug, time::Duration};

/// Signed block type of given chain.
pub type SignedBlockOf<C> = <C as Chain>::SignedBlock;

/// Substrate-based chain from minimal relay-client point of view.
pub trait Chain: ChainBase + Clone {
	/// Chain name.
	const NAME: &'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;
	/// Name of the runtime API method that is returning interval between source chain
	/// headers that may be submitted for free to the target chain.
	///
	/// Keep in mind that this method is normally provided by the other chain, which is
	/// bridged with this chain.
	const FREE_HEADERS_INTERVAL_METHOD: &'static str;

	/// Average block interval.
	///
	/// How often blocks are produced on that chain. It's suggested to set this value
	/// to match the block time of the chain.
	const AVERAGE_BLOCK_INTERVAL: Duration;

	/// Block type.
	type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>;
	/// The aggregated `Call` type.
	type Call: Clone + Codec + Debug + Send + Sync;
}

/// Bridge-supported network definition.
///
/// Used to abstract away CLI commands.
pub trait ChainWithRuntimeVersion: Chain {
	/// Current version of the chain runtime, known to relay.
	///
	/// can be `None` if relay is not going to submit transactions to that chain.
	const RUNTIME_VERSION: Option<SimpleRuntimeVersion>;
}

/// Substrate-based relay chain that supports parachains.
///
/// We assume that the parachains are supported using `runtime_parachains::paras` pallet.
pub trait RelayChain: Chain {
	/// Name of the `runtime_parachains::paras` pallet in the runtime of this chain.
	const PARAS_PALLET_NAME: &'static str;
	/// Name of the `pallet-bridge-parachains`, deployed at the **bridged** chain to sync
	/// parachains of **this** chain.
	const WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME: &'static str;
}

/// 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 + ChainWithGrandpaBase {
	/// Name of the runtime API method that is returning the GRANDPA info associated with the
	/// headers accepted by the `submit_finality_proofs` extrinsic in the queried block.
	///
	/// Keep in mind that this method is normally provided by the other chain, which is
	/// bridged with this chain.
	const SYNCED_HEADERS_GRANDPA_INFO_METHOD: &'static str;

	/// The type of the key owner proof used by the grandpa engine.
	type KeyOwnerProof: Decode + TypeInfo + Send;
}

/// Substrate-based parachain from minimal relay-client point of view.
pub trait Parachain: Chain + ParachainBase {}

impl<T> Parachain for T where T: UnderlyingChainProvider + Chain + ParachainBase {}

/// Substrate-based chain with messaging support from minimal relay-client point of view.
pub trait ChainWithMessages: Chain + ChainWithMessagesBase {
	/// Name of the bridge relayers 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_RELAYERS_PALLET_NAME: Option<&'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;

	/// Name of the `From<ChainWithMessages>InboundLaneApi::message_details` runtime API method.
	/// The method is provided by the runtime that is bridged with this `ChainWithMessages`.
	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str;
}

/// Call type used by the chain.
pub type CallOf<C> = <C as Chain>::Call;
/// Transaction status of the chain.
pub type TransactionStatusOf<C> = TransactionStatus<HashOf<C>, HashOf<C>>;

/// 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.
	fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey;
}

/// SCALE-encoded extrinsic.
pub type EncodedExtrinsic = Vec<u8>;

/// Block with justification.
pub trait BlockWithJustification<Header> {
	/// Return block header.
	fn header(&self) -> Header;
	/// Return encoded block extrinsics.
	fn extrinsics(&self) -> Vec<EncodedExtrinsic>;
	/// Return block justification, if known.
	fn justification(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification>;
}

/// Transaction before it is signed.
#[derive(Clone, Debug, PartialEq)]
pub struct UnsignedTransaction<C: Chain> {
	/// Runtime call of this transaction.
	pub call: EncodedOrDecodedCall<C::Call>,
	/// Transaction nonce.
	pub nonce: C::Nonce,
	/// Tip included into transaction.
	pub tip: C::Balance,
	/// Transaction era used by the chain.
	pub era: TransactionEraOf<C>,
}

impl<C: Chain> UnsignedTransaction<C> {
	/// Create new unsigned transaction with given call, nonce, era and zero tip.
	pub fn new(call: EncodedOrDecodedCall<C::Call>, nonce: C::Nonce) -> Self {
		Self { call, nonce, era: TransactionEra::Immortal, tip: Zero::zero() }
	}

	/// Convert to the transaction of the other compatible chain.
	pub fn switch_chain<Other>(self) -> UnsignedTransaction<Other>
	where
		Other: Chain<
			Nonce = C::Nonce,
			Balance = C::Balance,
			BlockNumber = C::BlockNumber,
			Hash = C::Hash,
		>,
	{
		UnsignedTransaction {
			call: EncodedOrDecodedCall::Encoded(self.call.into_encoded()),
			nonce: self.nonce,
			tip: self.tip,
			era: self.era,
		}
	}

	/// Set transaction tip.
	#[must_use]
	pub fn tip(mut self, tip: C::Balance) -> Self {
		self.tip = tip;
		self
	}

	/// Set transaction era.
	#[must_use]
	pub fn era(mut self, era: TransactionEraOf<C>) -> Self {
		self.era = era;
		self
	}
}

/// Account key pair used by transactions signing scheme.
pub type AccountKeyPairOf<S> = <S as ChainWithTransactions>::AccountKeyPair;

/// Substrate-based chain transactions signing scheme.
pub trait ChainWithTransactions: Chain {
	/// Type of key pairs used to sign transactions.
	type AccountKeyPair: Pair + Clone + Send + Sync;
	/// Signed transaction.
	type SignedTransaction: Clone + Debug + Codec + Send + 'static;

	/// Create transaction for given runtime call, signed by given account.
	fn sign_transaction(
		param: SignParam<Self>,
		unsigned: UnsignedTransaction<Self>,
	) -> Result<Self::SignedTransaction, crate::Error>
	where
		Self: Sized;
}

/// Sign transaction parameters
pub struct SignParam<C: ChainWithTransactions> {
	/// Version of the runtime specification.
	pub spec_version: u32,
	/// Transaction version
	pub transaction_version: u32,
	/// Hash of the genesis block.
	pub genesis_hash: HashOf<C>,
	/// Signer account
	pub signer: AccountKeyPairOf<C>,
}

impl<Block: BlockT> BlockWithJustification<Block::Header> for SignedBlock<Block> {
	fn header(&self) -> Block::Header {
		self.block.header().clone()
	}

	fn extrinsics(&self) -> Vec<EncodedExtrinsic> {
		self.block.extrinsics().iter().map(Encode::encode).collect()
	}

	fn justification(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification> {
		self.justifications.as_ref().and_then(|j| j.get(engine_id))
	}
}

/// Trait that provides functionality defined inside `pallet-utility`
pub trait UtilityPallet<C: Chain> {
	/// Create batch call from given calls vector.
	fn build_batch_call(calls: Vec<C::Call>) -> C::Call;
}

/// Structure that implements `UtilityPalletProvider` based on a full runtime.
pub struct FullRuntimeUtilityPallet<R> {
	_phantom: std::marker::PhantomData<R>,
}

impl<C, R> UtilityPallet<C> for FullRuntimeUtilityPallet<R>
where
	C: Chain,
	R: pallet_utility::Config<RuntimeCall = C::Call>,
	<R as pallet_utility::Config>::RuntimeCall: From<pallet_utility::Call<R>>,
{
	fn build_batch_call(calls: Vec<C::Call>) -> C::Call {
		pallet_utility::Call::batch_all { calls }.into()
	}
}

/// Structure that implements `UtilityPalletProvider` based on a call conversion.
pub struct MockedRuntimeUtilityPallet<Call> {
	_phantom: std::marker::PhantomData<Call>,
}

impl<C, Call> UtilityPallet<C> for MockedRuntimeUtilityPallet<Call>
where
	C: Chain,
	C::Call: From<UtilityCall<C::Call>>,
{
	fn build_batch_call(calls: Vec<C::Call>) -> C::Call {
		UtilityCall::batch_all(calls).into()
	}
}

/// Substrate-based chain that uses `pallet-utility`.
pub trait ChainWithUtilityPallet: Chain {
	/// The utility pallet provider.
	type UtilityPallet: UtilityPallet<Self>;
}