Newer
Older
// 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/>.
pub mod millau_headers_to_rialto;
pub mod millau_messages_to_rialto;
pub mod rialto_headers_to_millau;
pub mod rialto_messages_to_millau;
pub mod rococo_headers_to_wococo;
pub mod rococo_messages_to_wococo;
pub mod wococo_headers_to_rococo;
pub mod wococo_messages_to_rococo;
mod millau;
mod rialto;
mod rococo;
mod westend;
// Millau/Rialto tokens have no any real value, so the conversion rate we use is always 1:1. But we want to
// test our code that is intended to work with real-value chains. So to keep it close to 1:1, we'll be treating
// Rialto as BTC and Millau as wBTC (only in relayer).
/// The identifier of token, which value is associated with Rialto token value by relayer.
pub(crate) const RIALTO_ASSOCIATED_TOKEN_ID: &str = "polkadot";
/// The identifier of token, which value is associated with Millau token value by relayer.
pub(crate) const MILLAU_ASSOCIATED_TOKEN_ID: &str = "kusama";
use relay_utils::metrics::MetricsParams;
pub(crate) fn add_polkadot_kusama_price_metrics<T: finality_relay::FinalitySyncPipeline>(
params: MetricsParams,
) -> anyhow::Result<MetricsParams> {
// Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama
// relays, but we want to test metrics/dashboards in advance
Ok(relay_utils::relay_metrics(prefix, params)
.standalone_metric(|registry, prefix| {
substrate_relay_helper::helpers::token_price_metric(registry, prefix, "polkadot")
})?
.standalone_metric(|registry, prefix| {
substrate_relay_helper::helpers::token_price_metric(registry, prefix, "kusama")
})?
.into_params())
}
#[cfg(test)]
mod tests {
use crate::cli::{encode_call, send_message};
use bp_messages::source_chain::TargetHeaderChain;
use frame_support::dispatch::GetDispatchInfo;
use relay_millau_client::Millau;
use relay_rialto_client::Rialto;
use relay_substrate_client::{TransactionSignScheme, UnsignedTransaction};
use sp_core::Pair;
use sp_runtime::traits::{IdentifyAccount, Verify};
#[test]
fn millau_signature_is_valid_on_rialto() {
let millau_sign = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
let call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(vec![]));
let millau_public: bp_millau::AccountSigner = millau_sign.public().into();
let millau_account_id: bp_millau::AccountId = millau_public.into_account();
let digest = millau_runtime::millau_to_rialto_account_ownership_digest(
&call,
millau_account_id,
rialto_runtime::VERSION.spec_version,
);
let rialto_signer = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
let signature = rialto_signer.sign(&digest);
assert!(signature.verify(&digest[..], &rialto_signer.public()));
}
#[test]
fn rialto_signature_is_valid_on_millau() {
let rialto_sign = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
let call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![]));
let rialto_public: bp_rialto::AccountSigner = rialto_sign.public().into();
let rialto_account_id: bp_rialto::AccountId = rialto_public.into_account();
let digest = rialto_runtime::rialto_to_millau_account_ownership_digest(
&call,
rialto_account_id,
millau_runtime::VERSION.spec_version,
);
let millau_signer = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
let signature = millau_signer.sign(&digest);
assert!(signature.verify(&digest[..], &millau_signer.public()));
}
#[test]
fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() {
use rialto_runtime::millau_messages::Millau;
let maximal_remark_size = encode_call::compute_maximal_message_arguments_size(
bp_rialto::max_extrinsic_size(),
bp_millau::max_extrinsic_size(),
);
let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into();
Default::default(),
call.get_dispatch_info().weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert_eq!(Millau::verify_message(&payload), Ok(()));
let call: millau_runtime::Call =
millau_runtime::SystemCall::remark(vec![42; (maximal_remark_size + 1) as _]).into();
Default::default(),
call.get_dispatch_info().weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert!(Millau::verify_message(&payload).is_err());
}
#[test]
fn maximal_size_remark_to_rialto_is_generated_correctly() {
assert!(
bridge_runtime_common::messages::target::maximal_incoming_message_size(
bp_rialto::max_extrinsic_size()
) > bp_millau::max_extrinsic_size(),
"We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large",
)
}
#[test]
fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() {
use rialto_runtime::millau_messages::Millau;
let maximal_dispatch_weight =
send_message::compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight());
let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into();
Default::default(),
maximal_dispatch_weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert_eq!(Millau::verify_message(&payload), Ok(()));
Default::default(),
maximal_dispatch_weight + 1,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert!(Millau::verify_message(&payload).is_err());
}
#[test]
fn maximal_weight_fill_block_to_rialto_is_generated_correctly() {
use millau_runtime::rialto_messages::Rialto;
let maximal_dispatch_weight =
send_message::compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight());
let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into();
Default::default(),
maximal_dispatch_weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert_eq!(Rialto::verify_message(&payload), Ok(()));
Default::default(),
maximal_dispatch_weight + 1,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert!(Rialto::verify_message(&payload).is_err());
}
#[test]
fn rialto_tx_extra_bytes_constant_is_correct() {
let rialto_call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(vec![]));
let rialto_tx = Rialto::sign_transaction(
Default::default(),
&sp_keyring::AccountKeyring::Alice.pair(),
relay_substrate_client::TransactionEra::immortal(),
UnsignedTransaction::new(rialto_call.clone(), 0),
);
let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len();
assert!(
bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction,
"Hardcoded number of extra bytes in Rialto transaction {} is lower than actual value: {}",
bp_rialto::TX_EXTRA_BYTES,
extra_bytes_in_transaction,
);
}
#[test]
fn millau_tx_extra_bytes_constant_is_correct() {
let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![]));
let millau_tx = Millau::sign_transaction(
Default::default(),
&sp_keyring::AccountKeyring::Alice.pair(),
relay_substrate_client::TransactionEra::immortal(),
UnsignedTransaction::new(millau_call.clone(), 0),
);
let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len();
assert!(
bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction,
"Hardcoded number of extra bytes in Millau transaction {} is lower than actual value: {}",
bp_millau::TX_EXTRA_BYTES,
extra_bytes_in_transaction,
);
}
}
#[cfg(test)]
mod rococo_tests {
use bp_header_chain::justification::GrandpaJustification;
use codec::Encode;
#[test]
fn scale_compatibility_of_bridges_call() {
// given
let header = sp_runtime::generic::Header {
parent_hash: Default::default(),
number: Default::default(),
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: sp_runtime::generic::Digest { logs: vec![] },
};
let justification = GrandpaJustification {
round: 0,
commit: finality_grandpa::Commit {
target_hash: Default::default(),
target_number: Default::default(),
precommits: vec![],
},
votes_ancestries: vec![],
};
let actual = relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof(
header.clone(),
justification.clone(),
);
let expected = millau_runtime::BridgeGrandpaRialtoCall::<millau_runtime::Runtime>::submit_finality_proof(
header,
justification,
);
// when
let actual_encoded = actual.encode();
let expected_encoded = expected.encode();
// then
assert_eq!(
actual_encoded, expected_encoded,
"\n\nEncoding difference.\nGot {:#?} \nExpected: {:#?}",
actual, expected
);
}
}
#[cfg(test)]
mod westend_tests {
use bp_header_chain::justification::GrandpaJustification;
use codec::Encode;
#[test]
fn scale_compatibility_of_bridges_call() {
// given
let header = sp_runtime::generic::Header {
parent_hash: Default::default(),
number: Default::default(),
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: sp_runtime::generic::Digest { logs: vec![] },
};
let justification = GrandpaJustification {
round: 0,
commit: finality_grandpa::Commit {
target_hash: Default::default(),
target_number: Default::default(),
precommits: vec![],
},
votes_ancestries: vec![],
};
let actual = bp_westend::BridgeGrandpaRococoCall::submit_finality_proof(header.clone(), justification.clone());
let expected = millau_runtime::BridgeGrandpaRialtoCall::<millau_runtime::Runtime>::submit_finality_proof(
header,
justification,
);
// when
let actual_encoded = actual.encode();
let expected_encoded = expected.encode();
// then
assert_eq!(
actual_encoded, expected_encoded,
"\n\nEncoding difference.\nGot {:#?} \nExpected: {:#?}",
actual, expected
);
}
}