Remove unused PoA<>Substrate bridge (#1210)

* Decouple the PoA bridge code from Rialto
* Remove Rialto PoA bridge code
* Remove relays/bin-ethereum code
* Remove relays/client-ethereum code
* Remove modules/ethereum code
* Remove modules/ethereum-contract-builtin code
* Remove PoA bridge documentation
* Remove primitives/ethereum-poa code
* Decouple Rialto from currency-exchange
* Fix building with runtime-benchmarks
* Fix should_encode_bridge_send_message_call test
    Because we removed some runtime modules/pallets, the
    substrate2substrate bridge pallet has a different index within
    the runtime so its calls have a different encoding.
    Update the test to use the new encoding.
* Update readme - no more PoA bridge
* Remove deployments/bridges/poa-rialto
    Also removes:
    - deployments/networks/eth-poa.yml
    - deployments/networks/OpenEthereum.Dockerfile
* Remove deployments/dev/poa-config
* Update deployments readme - no more PoA bridge
* Remove eth-related scripts
    Deletes:
    - deployments/networks/eth-poa.yml
    - scripts/run-openethereum-node.sh
* Remove poa-relay from gitlab-ci
* Dockerfiles to use substrate-relay as default
* Remove modules/currency-exchange code
* Remove primitives/currency-exchange code

Signed-off-by: acatangiu <adrian@parity.io>
This commit is contained in:
Adrian Catangiu
2021-11-15 16:14:08 +02:00
committed by Bastian Köcher
parent 2d05583b15
commit 57f3f36cb1
54 changed files with 7 additions and 12181 deletions
+3 -21
View File
@@ -17,9 +17,9 @@
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, BridgeMillauMessagesConfig, ConfigurationConfig,
GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig,
WASM_BINARY,
};
use serde_json::json;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
@@ -216,8 +216,6 @@ 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(),
grandpa: GrandpaConfig { authorities: Vec::new() },
sudo: SudoConfig { key: root_key },
session: SessionConfig {
@@ -291,22 +289,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");
-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,9 +24,7 @@ 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 }
@@ -80,8 +76,6 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
[features]
default = ["std"]
std = [
"bp-currency-exchange/std",
"bp-eth-poa/std",
"bp-header-chain/std",
"bp-message-dispatch/std",
"bp-messages/std",
@@ -99,9 +93,7 @@ std = [
"pallet-authority-discovery/std",
"pallet-babe/std",
"pallet-balances/std",
"pallet-bridge-currency-exchange/std",
"pallet-bridge-dispatch/std",
"pallet-bridge-eth-poa/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-grandpa/std",
@@ -137,8 +129,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",
]
-38
View File
@@ -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()])),
])
}
-259
View File
@@ -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_value()) + sp_core::U256::from(1);
})
.0
),
Err(ExchangeError::InvalidAmount),
);
}
}
-201
View File
@@ -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_value(),
strict_empty_steps_transition: 0,
validate_step_transition: 0x16e360,
validate_score_transition: 0x41a3c4,
two_thirds_majority_transition: u64::max_value(),
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::max_value(),
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",
);
}
}
-308
View File
@@ -30,14 +30,8 @@
#[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};
@@ -72,8 +66,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;
@@ -253,48 +245,6 @@ 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_bridge_dispatch::Config for Runtime {
type Event = Event;
type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
@@ -307,68 +257,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;
@@ -578,12 +466,6 @@ 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},
// Millau bridge modules.
BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
@@ -693,46 +575,6 @@ 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 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)
}
fn finalized_block() -> (u64, bp_eth_poa::H256) {
let finalized_block = BridgeKovan::finalized_block();
(finalized_block.number, finalized_block.hash)
}
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)
}
}
impl bp_millau::MillauFinalityApi<Block> for Runtime {
fn best_finalized() -> (bp_millau::BlockNumber, bp_millau::Hash) {
let header = BridgeMillauGrandpa::best_finalized();
@@ -744,18 +586,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,
@@ -1028,17 +858,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);
@@ -1068,46 +891,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;
@@ -1274,13 +1057,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,
@@ -1322,48 +1098,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>;
@@ -1405,50 +1141,6 @@ 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
@@ -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_value(),
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::max_value(),
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",
);
}
}