Merge commit '114f487fd9daef4b4cd791446372a9a690c137ac' into update-bridges-subtree-r/w

This commit is contained in:
antonio-dropulic
2021-12-01 16:34:30 +01:00
183 changed files with 1017 additions and 21238 deletions
+9 -1
View File
@@ -28,10 +28,15 @@ rialto-runtime = { path = "../runtime" }
# Substrate Dependencies
beefy-gadget = { git = "https://github.com/paritytech/substrate", branch = "master" }
beefy-gadget-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -70,6 +75,10 @@ sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "mast
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
# Polkadot Dependencies
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
# Polkadot (parachain) Dependencies
polkadot-approval-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
@@ -88,7 +97,6 @@ polkadot-node-core-bitfield-signing = { git = "https://github.com/paritytech/pol
polkadot-node-core-candidate-validation = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-chain-api = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-chain-selection = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-dispute-participation = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-parachains-inherent = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-provisioner = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master" }
@@ -14,12 +14,13 @@
// 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 beefy_primitives::crypto::AuthorityId as BeefyId;
use bp_rialto::derive_account_from_millau_id;
use polkadot_primitives::v1::{AssignmentId, ValidatorId};
use rialto_runtime::{
AccountId, BabeConfig, BalancesConfig, BridgeKovanConfig, BridgeMillauMessagesConfig,
BridgeRialtoPoaConfig, ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig,
SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
AccountId, BabeConfig, BalancesConfig, BeefyConfig, BridgeMillauMessagesConfig,
ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature,
SudoConfig, SystemConfig, WASM_BINARY,
};
use serde_json::json;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
@@ -62,10 +63,11 @@ where
/// Helper function to generate authority keys.
pub fn get_authority_keys_from_seed(
s: &str,
) -> (AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) {
) -> (AccountId, BabeId, BeefyId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) {
(
get_account_id_from_seed::<sr25519::Public>(s),
get_from_seed::<BabeId>(s),
get_from_seed::<BeefyId>(s),
get_from_seed::<GrandpaId>(s),
get_from_seed::<ValidatorId>(s),
get_from_seed::<AssignmentId>(s),
@@ -183,18 +185,20 @@ impl Alternative {
fn session_keys(
babe: BabeId,
beefy: BeefyId,
grandpa: GrandpaId,
para_validator: ValidatorId,
para_assignment: AssignmentId,
authority_discovery: AuthorityDiscoveryId,
) -> SessionKeys {
SessionKeys { babe, grandpa, para_validator, para_assignment, authority_discovery }
SessionKeys { babe, beefy, grandpa, para_validator, para_assignment, authority_discovery }
}
fn testnet_genesis(
initial_authorities: Vec<(
AccountId,
BabeId,
BeefyId,
GrandpaId,
ValidatorId,
AssignmentId,
@@ -207,7 +211,6 @@ fn testnet_genesis(
GenesisConfig {
system: SystemConfig {
code: WASM_BINARY.expect("Rialto development WASM not available").to_vec(),
changes_trie_config: Default::default(),
},
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(),
@@ -216,8 +219,7 @@ fn testnet_genesis(
authorities: Vec::new(),
epoch_config: Some(rialto_runtime::BABE_GENESIS_EPOCH_CONFIG),
},
bridge_rialto_poa: load_rialto_poa_bridge_config(),
bridge_kovan: load_kovan_bridge_config(),
beefy: BeefyConfig { authorities: Vec::new() },
grandpa: GrandpaConfig { authorities: Vec::new() },
sudo: SudoConfig { key: root_key },
session: SessionConfig {
@@ -233,6 +235,7 @@ fn testnet_genesis(
x.3.clone(),
x.4.clone(),
x.5.clone(),
x.6.clone(),
),
)
})
@@ -291,22 +294,6 @@ fn testnet_genesis(
}
}
fn load_rialto_poa_bridge_config() -> BridgeRialtoPoaConfig {
BridgeRialtoPoaConfig {
initial_header: rialto_runtime::rialto_poa::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: rialto_runtime::rialto_poa::genesis_validators(),
}
}
fn load_kovan_bridge_config() -> BridgeKovanConfig {
BridgeKovanConfig {
initial_header: rialto_runtime::kovan::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: rialto_runtime::kovan::genesis_validators(),
}
}
#[test]
fn derived_dave_account_is_as_expected() {
let dave = get_account_id_from_seed::<sr25519::Public>("Dave");
@@ -70,7 +70,7 @@ impl SubstrateCli for Cli {
/// Parse and run command line arguments
pub fn run() -> sc_cli::Result<()> {
let cli = Cli::from_args();
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::Custom(
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom(
rialto_runtime::SS58Prefix::get() as u16,
));
@@ -63,8 +63,7 @@ pub use polkadot_node_core_candidate_validation::CandidateValidationSubsystem;
pub use polkadot_node_core_chain_api::ChainApiSubsystem;
pub use polkadot_node_core_chain_selection::ChainSelectionSubsystem;
pub use polkadot_node_core_dispute_coordinator::DisputeCoordinatorSubsystem;
pub use polkadot_node_core_dispute_participation::DisputeParticipationSubsystem;
pub use polkadot_node_core_provisioner::ProvisioningSubsystem as ProvisionerSubsystem;
pub use polkadot_node_core_provisioner::ProvisionerSubsystem;
pub use polkadot_node_core_runtime_api::RuntimeApiSubsystem;
pub use polkadot_statement_distribution::StatementDistribution as StatementDistributionSubsystem;
@@ -160,7 +159,6 @@ pub fn prepared_overseer_builder<Spawner, RuntimeClient>(
ApprovalVotingSubsystem,
GossipSupportSubsystem<AuthorityDiscoveryService>,
DisputeCoordinatorSubsystem,
DisputeParticipationSubsystem,
DisputeDistributionSubsystem<AuthorityDiscoveryService>,
ChainSelectionSubsystem,
>,
@@ -249,7 +247,6 @@ where
keystore.clone(),
Metrics::register(registry)?,
))
.dispute_participation(DisputeParticipationSubsystem::new())
.dispute_distribution(DisputeDistributionSubsystem::new(
keystore,
dispute_req_receiver,
+56 -68
View File
@@ -17,16 +17,11 @@
//! Rialto chain node service.
//!
//! The code is mostly copy of `service/src/lib.rs` file from Polkadot repository
//! without optional functions.
// this warning comes from Error enum (sc_cli::Error in particular) && it isn't easy to use box
// there
#![allow(clippy::large_enum_variant)]
// this warning comes from `sc_service::PartialComponents` type
#![allow(clippy::type_complexity)]
//! without optional functions, and with BEEFY added on top.
use crate::overseer::{OverseerGen, OverseerGenArgs};
use polkadot_client::RuntimeApiCollection;
use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig;
use polkadot_node_core_av_store::Config as AvailabilityConfig;
use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
@@ -43,7 +38,7 @@ use sc_service::{config::PrometheusConfig, Configuration, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker};
use sp_api::{ConstructRuntimeApi, HeaderT};
use sp_consensus::SelectChain;
use sp_runtime::traits::{BlakeTwo256, Block as BlockT};
use sp_runtime::traits::Block as BlockT;
use std::{sync::Arc, time::Duration};
use substrate_prometheus_endpoint::Registry;
@@ -115,52 +110,6 @@ type FullBabeBlockImport =
type FullBabeLink = sc_consensus_babe::BabeLink<Block>;
type FullGrandpaLink = sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>;
/// A set of APIs that polkadot-like runtimes must implement.
///
/// This is the copy of `polkadot_service::RuntimeApiCollection` with some APIs removed
/// (right now - MMR and BEEFY).
pub trait RequiredApiCollection:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block>
+ sp_consensus_babe::BabeApi<Block>
+ sp_finality_grandpa::GrandpaApi<Block>
+ polkadot_primitives::v1::ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block>
+ frame_system_rpc_runtime_api::AccountNonceApi<
Block,
bp_rialto::AccountId,
rialto_runtime::Index,
> + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ sp_authority_discovery::AuthorityDiscoveryApi<Block>
where
<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{
}
impl<Api> RequiredApiCollection for Api
where
Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block>
+ sp_consensus_babe::BabeApi<Block>
+ sp_finality_grandpa::GrandpaApi<Block>
+ polkadot_primitives::v1::ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block>
+ frame_system_rpc_runtime_api::AccountNonceApi<
Block,
bp_rialto::AccountId,
rialto_runtime::Index,
> + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ sp_authority_discovery::AuthorityDiscoveryApi<Block>,
<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{
}
// If we're using prometheus, use a registry with a prefix of `polkadot`.
fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> {
if let Some(PrometheusConfig { registry, .. }) = config.prometheus_config.as_mut() {
@@ -170,6 +119,8 @@ fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> {
Ok(())
}
// Needed here for complex return type while `impl Trait` in type aliases is unstable.
#[allow(clippy::type_complexity)]
pub fn new_partial(
config: &mut Configuration,
) -> Result<
@@ -184,7 +135,12 @@ pub fn new_partial(
sc_rpc::DenyUnsafe,
sc_rpc::SubscriptionTaskExecutor,
) -> Result<jsonrpc_core::IoHandler<sc_service::RpcMetadata>, sc_service::Error>,
(FullBabeBlockImport, FullGrandpaLink, FullBabeLink),
(
FullBabeBlockImport,
FullGrandpaLink,
FullBabeLink,
beefy_gadget::notification::BeefySignedCommitmentSender<Block>,
),
sc_finality_grandpa::SharedVoterState,
std::time::Duration,
Option<Telemetry>,
@@ -195,7 +151,7 @@ pub fn new_partial(
where
RuntimeApi: ConstructRuntimeApi<Block, FullClient> + Send + Sync + 'static,
<RuntimeApi as ConstructRuntimeApi<Block, FullClient>>::RuntimeApi:
RequiredApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
set_prometheus_registry(config)?;
@@ -226,7 +182,7 @@ where
let client = Arc::new(client);
let telemetry = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", worker.run());
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
telemetry
});
@@ -282,7 +238,10 @@ where
let shared_authority_set = grandpa_link.shared_authority_set().clone();
let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty();
let import_setup = (block_import, grandpa_link, babe_link);
let (signed_commitment_sender, signed_commitment_stream) =
beefy_gadget::notification::BeefySignedCommitmentStream::channel();
let import_setup = (block_import, grandpa_link, babe_link, signed_commitment_sender);
let rpc_setup = shared_voter_state.clone();
let slot_duration = babe_config.slot_duration();
@@ -316,14 +275,23 @@ where
pool,
deny_unsafe,
)));
io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client)));
io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(
client.clone(),
)));
io.extend_with(GrandpaApi::to_delegate(GrandpaRpcHandler::new(
shared_authority_set.clone(),
shared_voter_state,
justification_stream.clone(),
subscription_executor,
subscription_executor.clone(),
finality_proof_provider,
)));
io.extend_with(beefy_gadget_rpc::BeefyApi::to_delegate(
beefy_gadget_rpc::BeefyRpcHandler::new(
signed_commitment_stream.clone(),
subscription_executor,
),
));
io.extend_with(pallet_mmr_rpc::MmrApi::to_delegate(pallet_mmr_rpc::Mmr::new(client)));
Ok(io)
}
@@ -361,7 +329,7 @@ async fn active_leaves(
where
RuntimeApi: ConstructRuntimeApi<Block, FullClient> + Send + Sync + 'static,
<RuntimeApi as ConstructRuntimeApi<Block, FullClient>>::RuntimeApi:
RequiredApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
let best_block = select_chain.best_chain().await?;
@@ -406,7 +374,7 @@ pub fn new_full(
where
RuntimeApi: ConstructRuntimeApi<Block, FullClient> + Send + Sync + 'static,
<RuntimeApi as ConstructRuntimeApi<Block, FullClient>>::RuntimeApi:
RequiredApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
let is_collator = false;
@@ -442,6 +410,8 @@ where
// Substrate nodes.
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
config.network.extra_sets.push(beefy_gadget::beefy_peers_set_config());
{
use polkadot_network_bridge::{peer_sets_info, IsAuthority};
let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No };
@@ -474,7 +444,6 @@ where
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: None,
block_announce_validator_builder: None,
warp_sync: Some(warp_sync),
})?;
@@ -533,13 +502,11 @@ where
rpc_extensions_builder: Box::new(rpc_extensions_builder),
transaction_pool: transaction_pool.clone(),
task_manager: &mut task_manager,
on_demand: None,
remote_blockchain: None,
system_rpc_tx,
telemetry: telemetry.as_mut(),
})?;
let (block_import, link_half, babe_link) = import_setup;
let (block_import, link_half, babe_link, signed_commitment_sender) = import_setup;
let overseer_client = client.clone();
let spawner = task_manager.spawn_handle();
@@ -574,7 +541,9 @@ where
prometheus_registry.clone(),
);
task_manager.spawn_handle().spawn("authority-discovery-worker", worker.run());
task_manager
.spawn_handle()
.spawn("authority-discovery-worker", None, worker.run());
Some(service)
} else {
None
@@ -619,6 +588,7 @@ where
let handle = handle.clone();
task_manager.spawn_essential_handle().spawn_blocking(
"overseer",
None,
Box::pin(async move {
use futures::{pin_mut, select, FutureExt};
@@ -705,7 +675,7 @@ where
};
let babe = sc_consensus_babe::start_babe(babe_config)?;
task_manager.spawn_essential_handle().spawn_blocking("babe", babe);
task_manager.spawn_essential_handle().spawn_blocking("babe", None, babe);
}
// if the node isn't actively participating in consensus then it doesn't
@@ -713,6 +683,23 @@ where
let keystore_opt =
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
let beefy_params = beefy_gadget::BeefyParams {
client: client.clone(),
backend: backend.clone(),
key_store: keystore_opt.clone(),
network: network.clone(),
signed_commitment_sender,
min_block_delta: 2,
prometheus_registry: prometheus_registry.clone(),
};
// Start the BEEFY bridge gadget.
task_manager.spawn_essential_handle().spawn_blocking(
"beefy-gadget",
None,
beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params),
);
let config = sc_finality_grandpa::Config {
// FIXME substrate#1578 make this available through chainspec
gossip_duration: Duration::from_millis(1000),
@@ -751,6 +738,7 @@ where
task_manager.spawn_essential_handle().spawn_blocking(
"grandpa-voter",
None,
sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
);
}
+10 -10
View File
@@ -17,8 +17,6 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
# Bridge dependencies
bp-currency-exchange = { path = "../../../primitives/currency-exchange", default-features = false }
bp-eth-poa = { path = "../../../primitives/ethereum-poa", default-features = false }
bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false }
bp-messages = { path = "../../../primitives/messages", default-features = false }
@@ -26,15 +24,14 @@ bp-millau = { path = "../../../primitives/chain-millau", default-features = fals
bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false }
bp-runtime = { path = "../../../primitives/runtime", default-features = false }
bridge-runtime-common = { path = "../../runtime-common", default-features = false }
pallet-bridge-currency-exchange = { path = "../../../modules/currency-exchange", default-features = false }
pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false }
pallet-bridge-eth-poa = { path = "../../../modules/ethereum", default-features = false }
pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
# Substrate Dependencies
beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -43,7 +40,11 @@ frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate"
pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -80,8 +81,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
[features]
default = ["std"]
std = [
"bp-currency-exchange/std",
"bp-eth-poa/std",
"beefy-primitives/std",
"bp-header-chain/std",
"bp-message-dispatch/std",
"bp-messages/std",
@@ -99,12 +99,14 @@ std = [
"pallet-authority-discovery/std",
"pallet-babe/std",
"pallet-balances/std",
"pallet-bridge-currency-exchange/std",
"pallet-beefy/std",
"pallet-beefy-mmr/std",
"pallet-bridge-dispatch/std",
"pallet-bridge-eth-poa/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-grandpa/std",
"pallet-mmr/std",
"pallet-mmr-primitives/std",
"pallet-shift-session-manager/std",
"pallet-sudo/std",
"pallet-timestamp/std",
@@ -137,8 +139,6 @@ runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"libsecp256k1",
"pallet-bridge-currency-exchange/runtime-benchmarks",
"pallet-bridge-eth-poa/runtime-benchmarks",
"pallet-bridge-messages/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
@@ -1,38 +0,0 @@
// Copyright 2020-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/>.
//! We want to use a different validator configuration for benchmarking than what's used in Kovan
//! or in our Rialto test network. However, we can't configure a new validator set on the fly which
//! means we need to wire the runtime together like this
use pallet_bridge_eth_poa::{ValidatorsConfiguration, ValidatorsSource};
use sp_std::vec;
pub use crate::kovan::{
genesis_header, genesis_validators, BridgeAuraConfiguration, FinalityVotesCachingInterval,
PruningStrategy,
};
frame_support::parameter_types! {
pub BridgeValidatorsConfiguration: pallet_bridge_eth_poa::ValidatorsConfiguration = bench_validator_config();
}
fn bench_validator_config() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(vec![[1; 20].into()])),
(1, ValidatorsSource::Contract([3; 20].into(), vec![[1; 20].into()])),
])
}
@@ -1,259 +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/>.
//! Support for PoA -> Substrate native tokens exchange.
//!
//! If you want to exchange native PoA tokens for native Substrate
//! chain tokens, you need to:
//! 1) send some PoA tokens to `LOCK_FUNDS_ADDRESS` address on PoA chain. Data field of
//! the transaction must be SCALE-encoded id of Substrate account that will receive
//! funds on Substrate chain;
//! 2) wait until the 'lock funds' transaction is mined on PoA chain;
//! 3) wait until the block containing the 'lock funds' transaction is finalized on PoA chain;
//! 4) wait until the required PoA header and its finality are provided
//! to the PoA -> Substrate bridge module (it can be provided by you);
//! 5) receive tokens by providing proof-of-inclusion of PoA transaction.
use bp_currency_exchange::{
Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction,
Result as ExchangeResult,
};
use bp_eth_poa::{transaction_decode_rlp, RawTransaction, RawTransactionReceipt};
use codec::{Decode, Encode};
use frame_support::RuntimeDebug;
use hex_literal::hex;
use scale_info::TypeInfo;
use sp_std::vec::Vec;
/// Ethereum address where locked PoA funds must be sent to.
pub const LOCK_FUNDS_ADDRESS: [u8; 20] = hex!("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF");
/// Ethereum transaction inclusion proof.
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub struct EthereumTransactionInclusionProof {
/// Hash of the block with transaction.
pub block: sp_core::H256,
/// Index of the transaction within the block.
pub index: u64,
/// The proof itself (right now it is all RLP-encoded transactions of the block +
/// RLP-encoded receipts of all transactions of the block).
pub proof: Vec<(RawTransaction, RawTransactionReceipt)>,
}
/// We uniquely identify transfer by the pair (sender, nonce).
///
/// The assumption is that this pair will never appear more than once in
/// transactions included into finalized blocks. This is obviously true
/// for any existing eth-like chain (that keep current TX format), because
/// otherwise transaction can be replayed over and over.
#[derive(Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
pub struct EthereumTransactionTag {
/// Account that has locked funds.
pub account: [u8; 20],
/// Lock transaction nonce.
pub nonce: sp_core::U256,
}
/// Ethereum transaction from runtime perspective.
pub struct EthTransaction;
impl MaybeLockFundsTransaction for EthTransaction {
type Transaction = RawTransaction;
type Id = EthereumTransactionTag;
type Recipient = crate::AccountId;
type Amount = crate::Balance;
fn parse(
raw_tx: &Self::Transaction,
) -> ExchangeResult<LockFundsTransaction<Self::Id, Self::Recipient, Self::Amount>> {
let tx = transaction_decode_rlp(raw_tx).map_err(|_| ExchangeError::InvalidTransaction)?;
// we only accept transactions sending funds directly to the pre-configured address
if tx.unsigned.to != Some(LOCK_FUNDS_ADDRESS.into()) {
log::trace!(
target: "runtime",
"Failed to parse fund locks transaction. Invalid peer recipient: {:?}",
tx.unsigned.to,
);
return Err(ExchangeError::InvalidTransaction)
}
let mut recipient_raw = sp_core::H256::default();
match tx.unsigned.payload.len() {
32 => recipient_raw.as_fixed_bytes_mut().copy_from_slice(&tx.unsigned.payload),
len => {
log::trace!(
target: "runtime",
"Failed to parse fund locks transaction. Invalid recipient length: {}",
len,
);
return Err(ExchangeError::InvalidRecipient)
},
}
let amount = tx.unsigned.value.low_u128();
if tx.unsigned.value != amount.into() {
log::trace!(
target: "runtime",
"Failed to parse fund locks transaction. Invalid amount: {}",
tx.unsigned.value,
);
return Err(ExchangeError::InvalidAmount)
}
Ok(LockFundsTransaction {
id: EthereumTransactionTag {
account: *tx.sender.as_fixed_bytes(),
nonce: tx.unsigned.nonce,
},
recipient: crate::AccountId::from(*recipient_raw.as_fixed_bytes()),
amount,
})
}
}
/// Prepares everything required to bench claim of funds locked by given transaction.
#[cfg(feature = "runtime-benchmarks")]
pub(crate) fn prepare_environment_for_claim<T: pallet_bridge_eth_poa::Config<I>, I: 'static>(
transactions: &[(RawTransaction, RawTransactionReceipt)],
) -> bp_eth_poa::H256 {
use bp_eth_poa::compute_merkle_root;
use pallet_bridge_eth_poa::{
test_utils::{insert_dummy_header, validator_utils::validator, HeaderBuilder},
BridgeStorage, Storage,
};
let mut storage = BridgeStorage::<T, I>::new();
let header = HeaderBuilder::with_parent_number_on_runtime::<T, I>(0)
.transactions_root(compute_merkle_root(transactions.iter().map(|(tx, _)| tx)))
.receipts_root(compute_merkle_root(transactions.iter().map(|(_, receipt)| receipt)))
.sign_by(&validator(0));
let header_id = header.compute_id();
insert_dummy_header(&mut storage, header);
storage.finalize_and_prune_headers(Some(header_id), 0);
header_id.hash
}
/// Prepare signed ethereum lock-funds transaction.
#[cfg(any(feature = "runtime-benchmarks", test))]
pub(crate) fn prepare_ethereum_transaction(
recipient: &crate::AccountId,
editor: impl Fn(&mut bp_eth_poa::UnsignedTransaction),
) -> (RawTransaction, RawTransactionReceipt) {
use bp_eth_poa::{signatures::SignTransaction, Receipt, TransactionOutcome};
// prepare tx for OpenEthereum private dev chain:
// chain id is 0x11
// sender secret is 0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7
let chain_id = 0x11;
let signer = libsecp256k1::SecretKey::parse(&hex!(
"4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7"
))
.unwrap();
let recipient_raw: &[u8; 32] = recipient.as_ref();
let mut eth_tx = bp_eth_poa::UnsignedTransaction {
nonce: 0.into(),
to: Some(LOCK_FUNDS_ADDRESS.into()),
value: 100.into(),
gas: 100_000.into(),
gas_price: 100_000.into(),
payload: recipient_raw.to_vec(),
};
editor(&mut eth_tx);
(
eth_tx.sign_by(&signer, Some(chain_id)),
Receipt {
outcome: TransactionOutcome::StatusCode(1),
gas_used: Default::default(),
log_bloom: Default::default(),
logs: Vec::new(),
}
.rlp(),
)
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
fn ferdie() -> crate::AccountId {
hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c").into()
}
#[test]
fn valid_transaction_accepted() {
assert_eq!(
EthTransaction::parse(&prepare_ethereum_transaction(&ferdie(), |_| {}).0),
Ok(LockFundsTransaction {
id: EthereumTransactionTag {
account: hex!("00a329c0648769a73afac7f9381e08fb43dbea72"),
nonce: 0.into(),
},
recipient: ferdie(),
amount: 100,
}),
);
}
#[test]
fn invalid_transaction_rejected() {
assert_eq!(EthTransaction::parse(&Vec::new()), Err(ExchangeError::InvalidTransaction),);
}
#[test]
fn transaction_with_invalid_peer_recipient_rejected() {
assert_eq!(
EthTransaction::parse(
&prepare_ethereum_transaction(&ferdie(), |tx| {
tx.to = None;
})
.0
),
Err(ExchangeError::InvalidTransaction),
);
}
#[test]
fn transaction_with_invalid_recipient_rejected() {
assert_eq!(
EthTransaction::parse(
&prepare_ethereum_transaction(&ferdie(), |tx| {
tx.payload.clear();
})
.0
),
Err(ExchangeError::InvalidRecipient),
);
}
#[test]
fn transaction_with_invalid_amount_rejected() {
assert_eq!(
EthTransaction::parse(
&prepare_ethereum_transaction(&ferdie(), |tx| {
tx.value = sp_core::U256::from(u128::MAX) + sp_core::U256::from(1);
})
.0
),
Err(ExchangeError::InvalidAmount),
);
}
}
@@ -1,201 +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/>.
use crate::exchange::EthereumTransactionInclusionProof;
use bp_eth_poa::{Address, AuraHeader, RawTransaction, U256};
use bp_header_chain::InclusionProofVerifier;
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as BridgePruningStrategy,
ValidatorsConfiguration, ValidatorsSource,
};
use sp_std::prelude::*;
frame_support::parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(16);
pub BridgeAuraConfiguration: AuraConfiguration =
kovan_aura_configuration();
pub BridgeValidatorsConfiguration: ValidatorsConfiguration =
kovan_validators_configuration();
}
/// Max number of finalized headers to keep. It is equivalent of around 24 hours of
/// finalized blocks on current Kovan chain.
const FINALIZED_HEADERS_TO_KEEP: u64 = 20_000;
/// Aura engine configuration for Kovan chain.
pub fn kovan_aura_configuration() -> AuraConfiguration {
AuraConfiguration {
empty_steps_transition: u64::MAX,
strict_empty_steps_transition: 0,
validate_step_transition: 0x16e360,
validate_score_transition: 0x41a3c4,
two_thirds_majority_transition: u64::MAX,
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::MAX,
maximum_extra_data_size: 0x20,
}
}
/// Validators configuration for Kovan chain.
pub fn kovan_validators_configuration() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(genesis_validators())),
(
10960440,
ValidatorsSource::List(vec![
hex!("00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED").into(),
hex!("0010f94b296a852aaac52ea6c5ac72e03afd032d").into(),
hex!("00a0a24b9f0e5ec7aa4c7389b8302fd0123194de").into(),
]),
),
(
10960500,
ValidatorsSource::Contract(
hex!("aE71807C1B0a093cB1547b682DC78316D945c9B8").into(),
vec![
hex!("d05f7478c6aa10781258c5cc8b4f385fc8fa989c").into(),
hex!("03801efb0efe2a25ede5dd3a003ae880c0292e4d").into(),
hex!("a4df255ecf08bbf2c28055c65225c9a9847abd94").into(),
hex!("596e8221a30bfe6e7eff67fee664a01c73ba3c56").into(),
hex!("faadface3fbd81ce37b0e19c0b65ff4234148132").into(),
],
),
),
])
}
/// Genesis validators set of Kovan chain.
pub fn genesis_validators() -> Vec<Address> {
vec![
hex!("00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED").into(),
hex!("00427feae2419c15b89d1c21af10d1b6650a4d3d").into(),
hex!("4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c").into(),
hex!("0020ee4Be0e2027d76603cB751eE069519bA81A1").into(),
hex!("0010f94b296a852aaac52ea6c5ac72e03afd032d").into(),
hex!("007733a1FE69CF3f2CF989F81C7b4cAc1693387A").into(),
hex!("00E6d2b931F55a3f1701c7389d592a7778897879").into(),
hex!("00e4a10650e5a6D6001C38ff8E64F97016a1645c").into(),
hex!("00a0a24b9f0e5ec7aa4c7389b8302fd0123194de").into(),
]
}
/// Genesis header of the Kovan chain.
pub fn genesis_header() -> AuraHeader {
AuraHeader {
parent_hash: Default::default(),
timestamp: 0,
number: 0,
author: Default::default(),
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
.into(),
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
.into(),
extra_data: vec![],
state_root: hex!("2480155b48a1cea17d67dbfdfaafe821c1d19cdd478c5358e8ec56dec24502b2").into(),
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
.into(),
log_bloom: Default::default(),
gas_used: Default::default(),
gas_limit: 6000000.into(),
difficulty: 131072.into(),
seal: vec![
vec![128],
vec![
184, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
],
}
}
/// Kovan headers pruning strategy.
///
/// We do not prune unfinalized headers because exchange module only accepts
/// claims from finalized headers. And if we're pruning unfinalized headers, then
/// some claims may never be accepted.
#[derive(Default, RuntimeDebug)]
pub struct PruningStrategy;
impl BridgePruningStrategy for PruningStrategy {
fn pruning_upper_bound(&mut self, _best_number: u64, best_finalized_number: u64) -> u64 {
best_finalized_number.saturating_sub(FINALIZED_HEADERS_TO_KEEP)
}
}
/// PoA Header timestamp verification against `Timestamp` pallet.
#[derive(Default, RuntimeDebug)]
pub struct ChainTime;
impl TChainTime for ChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = super::Timestamp::now();
timestamp > now
}
}
/// The Kovan Blockchain as seen by the runtime.
pub struct KovanBlockchain;
impl InclusionProofVerifier for KovanBlockchain {
type Transaction = RawTransaction;
type TransactionInclusionProof = EthereumTransactionInclusionProof;
fn verify_transaction_inclusion_proof(
proof: &Self::TransactionInclusionProof,
) -> Option<Self::Transaction> {
let is_transaction_finalized = crate::BridgeKovan::verify_transaction_finalized(
proof.block,
proof.index,
&proof.proof,
);
if !is_transaction_finalized {
return None
}
proof.proof.get(proof.index as usize).map(|(tx, _)| tx.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pruning_strategy_keeps_enough_headers() {
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 10_000),
0,
"10_000 <= 20_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 20_000),
0,
"20_000 <= 20_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 30_000),
10_000,
"20_000 <= 30_000 => we're ready to prune first 10_000 headers",
);
}
}
+85 -301
View File
@@ -30,30 +30,28 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
pub mod exchange;
#[cfg(feature = "runtime-benchmarks")]
pub mod benches;
pub mod kovan;
pub mod millau_messages;
pub mod parachains;
pub mod rialto_poa;
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
use bridge_runtime_common::messages::{
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
};
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
};
use pallet_mmr_primitives::{
DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof,
};
use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
use sp_api::impl_runtime_apis;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, Block as BlockT, NumberFor, OpaqueKeys},
traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
};
@@ -72,8 +70,6 @@ pub use frame_support::{
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_bridge_currency_exchange::Call as BridgeCurrencyExchangeCall;
pub use pallet_bridge_eth_poa::Call as BridgeEthPoACall;
pub use pallet_bridge_grandpa::Call as BridgeGrandpaMillauCall;
pub use pallet_bridge_messages::Call as MessagesCall;
pub use pallet_sudo::Call as SudoCall;
@@ -109,9 +105,6 @@ pub type Hash = bp_rialto::Hash;
/// Hashing algorithm used by the chain.
pub type Hashing = bp_rialto::Hasher;
/// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>;
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
@@ -133,6 +126,7 @@ impl_opaque_keys! {
pub struct SessionKeys {
pub babe: Babe,
pub grandpa: Grandpa,
pub beefy: Beefy,
pub para_validator: Initializer,
pub para_assignment: SessionInfo,
pub authority_discovery: AuthorityDiscovery,
@@ -253,46 +247,8 @@ impl pallet_babe::Config for Runtime {
type WeightInfo = ();
}
type RialtoPoA = pallet_bridge_eth_poa::Instance1;
impl pallet_bridge_eth_poa::Config<RialtoPoA> for Runtime {
type AuraConfiguration = rialto_poa::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = rialto_poa::FinalityVotesCachingInterval;
type ValidatorsConfiguration = rialto_poa::BridgeValidatorsConfiguration;
type PruningStrategy = rialto_poa::PruningStrategy;
type ChainTime = rialto_poa::ChainTime;
type OnHeadersSubmitted = ();
}
type Kovan = pallet_bridge_eth_poa::Instance2;
impl pallet_bridge_eth_poa::Config<Kovan> for Runtime {
type AuraConfiguration = kovan::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = kovan::FinalityVotesCachingInterval;
type ValidatorsConfiguration = kovan::BridgeValidatorsConfiguration;
type PruningStrategy = kovan::PruningStrategy;
type ChainTime = kovan::ChainTime;
type OnHeadersSubmitted = ();
}
type RialtoCurrencyExchange = pallet_bridge_currency_exchange::Instance1;
impl pallet_bridge_currency_exchange::Config<RialtoCurrencyExchange> for Runtime {
type OnTransactionSubmitted = ();
type PeerBlockchain = rialto_poa::RialtoBlockchain;
type PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = bp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance;
type CurrencyConverter = bp_currency_exchange::IdentityCurrencyConverter<Balance>;
type DepositInto = DepositInto;
}
type KovanCurrencyExchange = pallet_bridge_currency_exchange::Instance2;
impl pallet_bridge_currency_exchange::Config<KovanCurrencyExchange> for Runtime {
type OnTransactionSubmitted = ();
type PeerBlockchain = kovan::KovanBlockchain;
type PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = bp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance;
type CurrencyConverter = bp_currency_exchange::IdentityCurrencyConverter<Balance>;
type DepositInto = DepositInto;
impl pallet_beefy::Config for Runtime {
type BeefyId = BeefyId;
}
impl pallet_bridge_dispatch::Config for Runtime {
@@ -307,68 +263,6 @@ impl pallet_bridge_dispatch::Config for Runtime {
type AccountIdConverter = bp_rialto::AccountIdConverter;
}
pub struct DepositInto;
impl bp_currency_exchange::DepositInto for DepositInto {
type Recipient = AccountId;
type Amount = Balance;
fn deposit_into(
recipient: Self::Recipient,
amount: Self::Amount,
) -> bp_currency_exchange::Result<()> {
// let balances module make all checks for us (it won't allow depositing lower than
// existential deposit, balance overflow, ...)
let deposited = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
&recipient, amount,
);
// I'm dropping deposited here explicitly to illustrate the fact that it'll update
// `TotalIssuance` on drop
let deposited_amount = deposited.peek();
drop(deposited);
// we have 3 cases here:
// - deposited == amount: success
// - deposited == 0: deposit has failed and no changes to storage were made
// - deposited != 0: (should never happen in practice) deposit has been partially completed
match deposited_amount {
_ if deposited_amount == amount => {
log::trace!(
target: "runtime",
"Deposited {} to {:?}",
amount,
recipient,
);
Ok(())
},
_ if deposited_amount == 0 => {
log::error!(
target: "runtime",
"Deposit of {} to {:?} has failed",
amount,
recipient,
);
Err(bp_currency_exchange::Error::DepositFailed)
},
_ => {
log::error!(
target: "runtime",
"Deposit of {} to {:?} has partially competed. {} has been deposited",
amount,
recipient,
deposited_amount,
);
// we can't return DepositFailed error here, because storage changes were made
Err(bp_currency_exchange::Error::DepositPartiallyFailed)
},
}
}
}
impl pallet_grandpa::Config for Runtime {
type Event = Event;
type Call = Call;
@@ -386,6 +280,38 @@ impl pallet_grandpa::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
}
impl pallet_mmr::Config for Runtime {
const INDEXING_PREFIX: &'static [u8] = b"mmr";
type Hashing = Keccak256;
type Hash = <Keccak256 as sp_runtime::traits::Hash>::Output;
type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
type WeightInfo = ();
type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
}
parameter_types! {
/// Version of the produced MMR leaf.
///
/// The version consists of two parts;
/// - `major` (3 bits)
/// - `minor` (5 bits)
///
/// `major` should be updated only if decoding the previous MMR Leaf format from the payload
/// is not possible (i.e. backward incompatible change).
/// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE
/// encoding does not prevent old leafs from being decoded.
///
/// Hence we expect `major` to be changed really rarely (think never).
/// See [`MmrLeafVersion`] type documentation for more details.
pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0);
}
impl pallet_beefy_mmr::Config for Runtime {
type LeafVersion = LeafVersion;
type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum;
type ParachainHeads = ();
}
parameter_types! {
pub const MinimumPeriod: u64 = bp_rialto::SLOT_DURATION / 2;
}
@@ -579,11 +505,10 @@ construct_runtime!(
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
ShiftSessionManager: pallet_shift_session_manager::{Pallet},
// Eth-PoA chains bridge modules.
BridgeRialtoPoa: pallet_bridge_eth_poa::<Instance1>::{Pallet, Call, Config, Storage, ValidateUnsigned},
BridgeKovan: pallet_bridge_eth_poa::<Instance2>::{Pallet, Call, Config, Storage, ValidateUnsigned},
BridgeRialtoCurrencyExchange: pallet_bridge_currency_exchange::<Instance1>::{Pallet, Call},
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Pallet, Call},
// BEEFY Bridges support.
Beefy: pallet_beefy::{Pallet, Storage, Config<T>},
Mmr: pallet_mmr::{Pallet, Storage},
MmrLeaf: pallet_beefy_mmr::{Pallet, Storage},
// Millau bridge modules.
BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
@@ -694,43 +619,42 @@ impl_runtime_apis! {
}
}
impl bp_eth_poa::RialtoPoAHeaderApi<Block> for Runtime {
fn best_block() -> (u64, bp_eth_poa::H256) {
let best_block = BridgeRialtoPoa::best_block();
(best_block.number, best_block.hash)
}
fn finalized_block() -> (u64, bp_eth_poa::H256) {
let finalized_block = BridgeRialtoPoa::finalized_block();
(finalized_block.number, finalized_block.hash)
}
fn is_import_requires_receipts(header: bp_eth_poa::AuraHeader) -> bool {
BridgeRialtoPoa::is_import_requires_receipts(header)
}
fn is_known_block(hash: bp_eth_poa::H256) -> bool {
BridgeRialtoPoa::is_known_block(hash)
impl beefy_primitives::BeefyApi<Block> for Runtime {
fn validator_set() -> ValidatorSet<BeefyId> {
Beefy::validator_set()
}
}
impl bp_eth_poa::KovanHeaderApi<Block> for Runtime {
fn best_block() -> (u64, bp_eth_poa::H256) {
let best_block = BridgeKovan::best_block();
(best_block.number, best_block.hash)
impl pallet_mmr_primitives::MmrApi<Block, Hash> for Runtime {
fn generate_proof(leaf_index: u64)
-> Result<(EncodableOpaqueLeaf, MmrProof<Hash>), MmrError>
{
Mmr::generate_proof(leaf_index)
.map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof))
}
fn finalized_block() -> (u64, bp_eth_poa::H256) {
let finalized_block = BridgeKovan::finalized_block();
(finalized_block.number, finalized_block.hash)
fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof<Hash>)
-> Result<(), MmrError>
{
pub type Leaf = <
<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider
>::LeafData;
let leaf: Leaf = leaf
.into_opaque_leaf()
.try_decode()
.ok_or(MmrError::Verify)?;
Mmr::verify_leaf(leaf, proof)
}
fn is_import_requires_receipts(header: bp_eth_poa::AuraHeader) -> bool {
BridgeKovan::is_import_requires_receipts(header)
}
fn is_known_block(hash: bp_eth_poa::H256) -> bool {
BridgeKovan::is_known_block(hash)
fn verify_proof_stateless(
root: Hash,
leaf: EncodableOpaqueLeaf,
proof: MmrProof<Hash>
) -> Result<(), MmrError> {
type MmrHashing = <Runtime as pallet_mmr::Config>::Hashing;
let node = DataOrHash::Data(leaf.into_opaque_leaf());
pallet_mmr::verify_leaf_proof::<MmrHashing, _>(root, node, proof)
}
}
@@ -745,18 +669,6 @@ impl_runtime_apis! {
}
}
impl bp_currency_exchange::RialtoCurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeRialtoCurrencyExchange::filter_transaction_proof(&proof)
}
}
impl bp_currency_exchange::KovanCurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeKovanCurrencyExchange::filter_transaction_proof(&proof)
}
}
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
@@ -846,6 +758,13 @@ impl_runtime_apis! {
polkadot_runtime_parachains::runtime_api_impl::v1::persisted_validation_data::<Runtime>(para_id, assumption)
}
fn assumed_validation_data(
para_id: polkadot_primitives::v1::Id,
expected_persisted_validation_data_hash: Hash,
) -> Option<(polkadot_primitives::v1::PersistedValidationData<Hash, BlockNumber>, polkadot_primitives::v1::ValidationCodeHash)> {
polkadot_runtime_parachains::runtime_api_impl::v1::assumed_validation_data::<Runtime>(para_id, expected_persisted_validation_data_hash)
}
fn check_validation_outputs(
para_id: polkadot_primitives::v1::Id,
outputs: polkadot_primitives::v1::CandidateCommitments,
@@ -1029,17 +948,10 @@ impl_runtime_apis! {
use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
use frame_support::traits::StorageInfoTrait;
use pallet_bridge_currency_exchange::benchmarking::Pallet as BridgeCurrencyExchangeBench;
use pallet_bridge_messages::benchmarking::Pallet as MessagesBench;
let mut list = Vec::<BenchmarkList>::new();
list_benchmark!(list, extra, pallet_bridge_eth_poa, BridgeRialtoPoa);
list_benchmark!(
list,
extra,
pallet_bridge_currency_exchange, BridgeCurrencyExchangeBench::<Runtime, KovanCurrencyExchange>
);
list_benchmark!(list, extra, pallet_bridge_messages, MessagesBench::<Runtime, WithMillauMessagesInstance>);
list_benchmark!(list, extra, pallet_bridge_grandpa, BridgeMillauGrandpa);
@@ -1073,46 +985,6 @@ impl_runtime_apis! {
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
use pallet_bridge_currency_exchange::benchmarking::{
Pallet as BridgeCurrencyExchangeBench,
Config as BridgeCurrencyExchangeConfig,
ProofParams as BridgeCurrencyExchangeProofParams,
};
impl BridgeCurrencyExchangeConfig<KovanCurrencyExchange> for Runtime {
fn make_proof(
proof_params: BridgeCurrencyExchangeProofParams<AccountId>,
) -> crate::exchange::EthereumTransactionInclusionProof {
use bp_currency_exchange::DepositInto;
if proof_params.recipient_exists {
<Runtime as pallet_bridge_currency_exchange::Config<KovanCurrencyExchange>>::DepositInto::deposit_into(
proof_params.recipient.clone(),
ExistentialDeposit::get(),
).unwrap();
}
let (transaction, receipt) = crate::exchange::prepare_ethereum_transaction(
&proof_params.recipient,
|tx| {
// our runtime only supports transactions where data is exactly 32 bytes long
// (receiver key)
// => we are ignoring `transaction_size_factor` here
tx.value = (ExistentialDeposit::get() * 10).into();
},
);
let transactions = sp_std::iter::repeat((transaction, receipt))
.take(1 + proof_params.proof_size_factor as usize)
.collect::<Vec<_>>();
let block_hash = crate::exchange::prepare_environment_for_claim::<Runtime, Kovan>(&transactions);
crate::exchange::EthereumTransactionInclusionProof {
block: block_hash,
index: 0,
proof: transactions,
}
}
}
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
use bp_runtime::messages::DispatchFeePayment;
use bridge_runtime_common::messages;
@@ -1279,13 +1151,6 @@ impl_runtime_apis! {
}
}
add_benchmark!(params, batches, pallet_bridge_eth_poa, BridgeRialtoPoa);
add_benchmark!(
params,
batches,
pallet_bridge_currency_exchange,
BridgeCurrencyExchangeBench::<Runtime, KovanCurrencyExchange>
);
add_benchmark!(
params,
batches,
@@ -1327,48 +1192,8 @@ where
#[cfg(test)]
mod tests {
use super::*;
use bp_currency_exchange::DepositInto;
use bridge_runtime_common::messages;
fn run_deposit_into_test(test: impl Fn(AccountId) -> Balance) {
let mut ext: sp_io::TestExternalities =
SystemConfig::default().build_storage::<Runtime>().unwrap().into();
ext.execute_with(|| {
// initially issuance is zero
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::total_issuance(),
0,
);
// create account
let account: AccountId = [1u8; 32].into();
let initial_amount = ExistentialDeposit::get();
let deposited =
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
&account,
initial_amount,
);
drop(deposited);
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::total_issuance(),
initial_amount,
);
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&account),
initial_amount,
);
// run test
let total_issuance_change = test(account);
// check that total issuance has changed by `run_deposit_into_test`
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::total_issuance(),
initial_amount + total_issuance_change,
);
});
}
#[test]
fn ensure_rialto_message_lane_weights_are_correct() {
type Weights = pallet_bridge_messages::weights::RialtoWeight<Runtime>;
@@ -1410,53 +1235,12 @@ mod tests {
);
}
#[test]
fn deposit_into_existing_account_works() {
run_deposit_into_test(|existing_account| {
let initial_amount =
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&existing_account,
);
let additional_amount = 10_000;
<Runtime as pallet_bridge_currency_exchange::Config<KovanCurrencyExchange>>::DepositInto::deposit_into(
existing_account.clone(),
additional_amount,
)
.unwrap();
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&existing_account
),
initial_amount + additional_amount,
);
additional_amount
});
}
#[test]
fn deposit_into_new_account_works() {
run_deposit_into_test(|_| {
let initial_amount = 0;
let additional_amount = ExistentialDeposit::get() + 10_000;
let new_account: AccountId = [42u8; 32].into();
<Runtime as pallet_bridge_currency_exchange::Config<KovanCurrencyExchange>>::DepositInto::deposit_into(
new_account.clone(),
additional_amount,
)
.unwrap();
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&new_account
),
initial_amount + additional_amount,
);
additional_amount
});
}
#[test]
fn call_size() {
const MAX_CALL_SIZE: usize = 230; // value from polkadot-runtime tests
assert!(core::mem::size_of::<Call>() <= MAX_CALL_SIZE);
const DOT_MAX_CALL_SZ: usize = 230;
assert!(core::mem::size_of::<pallet_bridge_grandpa::Call<Runtime>>() <= DOT_MAX_CALL_SZ);
// FIXME: get this down to 230. https://github.com/paritytech/grandpa-bridge-gadget/issues/359
const BEEFY_MAX_CALL_SZ: usize = 232;
assert!(core::mem::size_of::<pallet_bridge_messages::Call<Runtime>>() <= BEEFY_MAX_CALL_SZ);
}
}
@@ -71,7 +71,9 @@ impl parachains_paras::Config for Runtime {
type WeightInfo = parachains_paras::TestWeightInfo;
}
impl parachains_paras_inherent::Config for Runtime {}
impl parachains_paras_inherent::Config for Runtime {
type WeightInfo = parachains_paras_inherent::TestWeightInfo;
}
impl parachains_scheduler::Config for Runtime {}
@@ -1,183 +0,0 @@
// Copyright 2020-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/>.
//! Configuration parameters for the Rialto PoA chain.
use crate::exchange::EthereumTransactionInclusionProof;
use bp_eth_poa::{Address, AuraHeader, RawTransaction, U256};
use bp_header_chain::InclusionProofVerifier;
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as TPruningStrategy,
ValidatorsConfiguration, ValidatorsSource,
};
use sp_std::prelude::*;
frame_support::parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(8);
pub BridgeAuraConfiguration: AuraConfiguration =
aura_configuration();
pub BridgeValidatorsConfiguration: ValidatorsConfiguration =
validators_configuration();
}
/// Max number of finalized headers to keep.
const FINALIZED_HEADERS_TO_KEEP: u64 = 5_000;
/// Aura engine configuration for Rialto chain.
pub fn aura_configuration() -> AuraConfiguration {
AuraConfiguration {
empty_steps_transition: 0xfffffffff,
strict_empty_steps_transition: 0,
validate_step_transition: 0,
validate_score_transition: 0,
two_thirds_majority_transition: u64::MAX,
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::MAX,
maximum_extra_data_size: 0x20,
}
}
/// Validators configuration for Rialto PoA chain.
pub fn validators_configuration() -> ValidatorsConfiguration {
ValidatorsConfiguration::Single(ValidatorsSource::List(genesis_validators()))
}
/// Genesis validators set of Rialto PoA chain.
pub fn genesis_validators() -> Vec<Address> {
vec![
hex!("005e714f896a8b7cede9d38688c1a81de72a58e4").into(),
hex!("007594304039c2937a12220338aab821d819f5a4").into(),
hex!("004e7a39907f090e19b0b80a277e77b72b22e269").into(),
]
}
/// Genesis header of the Rialto PoA chain.
///
/// To obtain genesis header from a running node, invoke:
/// ```bash
/// $ http localhost:8545 jsonrpc=2.0 id=1 method=eth_getBlockByNumber params:='["earliest", false]' -v
/// ```
pub fn genesis_header() -> AuraHeader {
AuraHeader {
parent_hash: Default::default(),
timestamp: 0,
number: 0,
author: Default::default(),
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
.into(),
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
.into(),
extra_data: vec![],
state_root: hex!("a992d04c791620ed7ed96555a80cf0568355bb4bee2656f46899a4372f25f248").into(),
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
.into(),
log_bloom: Default::default(),
gas_used: Default::default(),
gas_limit: 0x222222.into(),
difficulty: 0x20000.into(),
seal: vec![vec![0x80], {
let mut vec = vec![0xb8, 0x41];
vec.resize(67, 0);
vec
}],
}
}
/// Rialto PoA headers pruning strategy.
///
/// We do not prune unfinalized headers because exchange module only accepts
/// claims from finalized headers. And if we're pruning unfinalized headers, then
/// some claims may never be accepted.
#[derive(Default, RuntimeDebug)]
pub struct PruningStrategy;
impl TPruningStrategy for PruningStrategy {
fn pruning_upper_bound(&mut self, _best_number: u64, best_finalized_number: u64) -> u64 {
best_finalized_number.saturating_sub(FINALIZED_HEADERS_TO_KEEP)
}
}
/// `ChainTime` provider
#[derive(Default)]
pub struct ChainTime;
impl TChainTime for ChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = super::Timestamp::now();
timestamp > now
}
}
/// The Rialto PoA Blockchain as seen by the runtime.
pub struct RialtoBlockchain;
impl InclusionProofVerifier for RialtoBlockchain {
type Transaction = RawTransaction;
type TransactionInclusionProof = EthereumTransactionInclusionProof;
fn verify_transaction_inclusion_proof(
proof: &Self::TransactionInclusionProof,
) -> Option<Self::Transaction> {
let is_transaction_finalized = crate::BridgeRialtoPoa::verify_transaction_finalized(
proof.block,
proof.index,
&proof.proof,
);
if !is_transaction_finalized {
return None
}
proof.proof.get(proof.index as usize).map(|(tx, _)| tx.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn genesis_hash_matches() {
assert_eq!(
genesis_header().compute_hash(),
hex!("1468e1a0fa20d30025a5a0f87e1cced4fdc393b84b7d2850b11ca5863db482cb").into(),
);
}
#[test]
fn pruning_strategy_keeps_enough_headers() {
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 1_000),
0,
"1_000 <= 5_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 5_000),
0,
"5_000 <= 5_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 10_000),
5_000,
"5_000 <= 10_000 => we're ready to prune first 5_000 headers",
);
}
}