Downward & Upward messages (#1266)

* Downward messages, the front-end.

* Move types around to make them accessible from Parachains

* Fix compilation

* Fix branch

* Make it compile for Cumulus

* Update the branch names

* Add default generic parameter

* Implement `Partialeq`

* Move upward messages into the `ValidationResult`

* Support disabling of the runtime api

* Update branch

* Adds support for handling downward messages

* Implement sending XCMP messages as up/downward messages

* service: update to latest ServiceBuilder changes

* Make it compile

* Initial commit

Forked at: ef2aa428d7
Parent branch: origin/master

* Update substrate branch to cecton-update-polkadot-substrate

* Update substrate & polkadot to cumulus-branch

* Reset branch

* Update primitives/src/parachain.rs

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>

* Update runtime/common/src/parachains.rs

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>

* Update runtime/common/src/parachains.rs

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>

* Minor fixes

* Fix wasm build

Co-authored-by: Gav Wood <gavin@parity.io>
Co-authored-by: André Silva <andre.beat@gmail.com>
Co-authored-by: Cecile Tonglet <cecile.tonglet@cecton.com>
Co-authored-by: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
Bastian Köcher
2020-07-01 16:20:38 +02:00
committed by GitHub
parent 3b357fadd5
commit 934f27d92b
37 changed files with 460 additions and 377 deletions
+137 -12
View File
@@ -34,7 +34,7 @@ use sp_staking::{
};
use frame_support::{
traits::KeyOwnerProofSystem,
dispatch::{IsSubType},
dispatch::IsSubType,
weights::{DispatchClass, Weight},
};
use primitives::{
@@ -47,14 +47,13 @@ use primitives::{
LocalValidationData, Scheduling, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
ValidatorSignature, SigningContext, HeadData, ValidationCode,
},
Remark, DownwardMessage
};
use frame_support::{
Parameter, dispatch::DispatchResult, decl_storage, decl_module, decl_error, ensure,
traits::{Currency, Get, WithdrawReason, ExistenceRequirement, Randomness},
};
use sp_runtime::{
transaction_validity::InvalidTransaction,
};
use sp_runtime::transaction_validity::InvalidTransaction;
use inherents::{ProvideInherent, InherentData, MakeFatalError, InherentIdentifier};
@@ -91,6 +90,18 @@ impl<N: Saturating + One + PartialOrd + PartialEq + Clone> Iterator for BlockNum
pub trait ParachainCurrency<AccountId> {
fn free_balance(para_id: ParaId) -> Balance;
fn deduct(para_id: ParaId, amount: Balance) -> DispatchResult;
fn transfer_in(
source: &AccountId,
dest: ParaId,
amount: Balance,
existence_requirement: ExistenceRequirement,
) -> DispatchResult;
fn transfer_out(
source: ParaId,
dest: &AccountId,
amount: Balance,
existence_requirement: ExistenceRequirement,
) -> DispatchResult;
}
impl<AccountId, T: Currency<AccountId>> ParachainCurrency<AccountId> for T where
@@ -102,6 +113,8 @@ impl<AccountId, T: Currency<AccountId>> ParachainCurrency<AccountId> for T where
T::free_balance(&para_account).into()
}
// TODO: this should really be the same API as `withdraw`, having NegativeImbalance as an
// associated type.
fn deduct(para_id: ParaId, amount: Balance) -> DispatchResult {
let para_account = para_id.into_account();
@@ -115,6 +128,24 @@ impl<AccountId, T: Currency<AccountId>> ParachainCurrency<AccountId> for T where
Ok(())
}
fn transfer_in(
source: &AccountId,
dest: ParaId,
amount: Balance,
existence_requirement: ExistenceRequirement,
) -> DispatchResult {
T::transfer(source, &dest.into_account(), amount.into(), existence_requirement)
}
fn transfer_out(
source: ParaId,
dest: &AccountId,
amount: Balance,
existence_requirement: ExistenceRequirement,
) -> DispatchResult {
T::transfer(&source.into_account(), dest, amount.into(), existence_requirement)
}
}
/// Interface to the persistent (stash) identities of the current validators.
@@ -226,12 +257,14 @@ pub trait Trait: CreateSignedTransaction<Call<Self>> + attestations::Trait + ses
type AuthorityId: system::offchain::AppCrypto<Self::Public, Self::Signature>;
/// The outer origin type.
type Origin: From<Origin> + From<system::RawOrigin<Self::AccountId>>;
type Origin: From<Origin>
+ From<<Self as system::Trait>::Origin>
+ Into<result::Result<Origin, <Self as Trait>::Origin>>;
/// The outer call dispatch type.
type Call: Parameter + Dispatchable<Origin=<Self as Trait>::Origin> + From<Call<Self>>;
/// Some way of interacting with balances for fees.
/// Some way of interacting with balances for fees and transfers.
type ParachainCurrency: ParachainCurrency<Self::AccountId>;
/// Polkadot in practice will always use the `BlockNumber` type.
@@ -345,6 +378,8 @@ impl<Offender: Clone> Offence<Offender> for DoubleVoteOffence<Offender> {
}
}
/// Total number of individual messages allowed in the relay-chain -> parachain message queue.
const MAX_DOWNWARD_QUEUE_COUNT: usize = 10;
/// Total number of individual messages allowed in the parachain -> relay-chain message queue.
const MAX_QUEUE_COUNT: usize = 100;
/// Total size of messages allowed in the parachain -> relay-chain message queue before which no
@@ -445,8 +480,7 @@ impl<N: Ord + Copy> ParaPastCodeMeta<N> {
}
decl_storage! {
trait Store for Module<T: Trait> as Parachains
{
trait Store for Module<T: Trait> as Parachains {
/// All authorities' keys at the moment.
pub Authorities get(fn authorities): Vec<ValidatorId>;
/// The active code of a currently-registered parachain.
@@ -484,6 +518,9 @@ decl_storage! {
///
/// `None` if not yet updated.
pub DidUpdate: Option<Vec<ParaId>>;
/// Messages waiting to be delivered from the Relay chain into the parachain.
pub DownwardMessageQueue: map hasher(twox_64_concat) ParaId => Vec<DownwardMessage<T::AccountId>>;
}
add_extra_genesis {
config(authorities): Vec<ValidatorId>;
@@ -531,6 +568,8 @@ decl_error! {
CannotPayFees,
/// Unexpected relay-parent for a candidate receipt.
UnexpectedRelayParent,
/// Downward message queue is full for the Parachain.
DownwardMessageQueueFull,
}
}
@@ -596,6 +635,11 @@ decl_module! {
WATERMARK_QUEUE_SIZE,
)?;
Self::remove_processed_downward_messages(
id,
head.candidate.commitments.processed_downward_messages as usize,
);
let id = head.parachain_index();
proceeded.push(id);
last_id = Some(id);
@@ -668,6 +712,36 @@ decl_module! {
Ok(())
}
/// Transfer some tokens into a parachain and leave a message in the downward queue for it.
#[weight = 100_000]
pub fn transfer_to_parachain(
origin,
to: ParaId,
amount: Balance,
remark: Remark,
) {
let who = ensure_signed(origin)?;
let downward_queue_count = DownwardMessageQueue::<T>::decode_len(to).unwrap_or(0);
ensure!(downward_queue_count < MAX_DOWNWARD_QUEUE_COUNT, Error::<T>::DownwardMessageQueueFull);
T::ParachainCurrency::transfer_in(&who, to, amount, ExistenceRequirement::AllowDeath)?;
DownwardMessageQueue::<T>::append(to, DownwardMessage::TransferInto(who, amount, remark));
}
/// Send a XCMP message to the given parachain.
///
/// The origin must be another parachain.
#[weight = 100_000]
pub fn send_xcmp_message(
origin,
to: ParaId,
msg: Vec<u8>,
) {
ensure_parachain(<T as Trait>::Origin::from(origin))?;
let downward_queue_count = DownwardMessageQueue::<T>::decode_len(to).unwrap_or(0);
ensure!(downward_queue_count < MAX_DOWNWARD_QUEUE_COUNT, Error::<T>::DownwardMessageQueueFull);
DownwardMessageQueue::<T>::append(to, DownwardMessage::XCMPMessage(msg));
}
}
}
@@ -814,11 +888,11 @@ impl<T: Trait> Module<T> {
if let Ok(message_call) = <T as Trait>::Call::decode(&mut &data[..]) {
let origin: <T as Trait>::Origin = match origin {
ParachainDispatchOrigin::Signed =>
system::RawOrigin::Signed(id.into_account()).into(),
<T as Trait>::Origin::from(<T as system::Trait>::Origin::from(system::RawOrigin::Signed(id.into_account()))),
ParachainDispatchOrigin::Parachain =>
Origin::Parachain(id).into(),
ParachainDispatchOrigin::Root =>
system::RawOrigin::Root.into(),
<T as Trait>::Origin::from(<T as system::Trait>::Origin::from(system::RawOrigin::Root)),
};
let _ok = message_call.dispatch(origin).is_ok();
// Not much to do with the result as it is. It's up to the parachain to ensure that the
@@ -862,6 +936,17 @@ impl<T: Trait> Module<T> {
Ok(())
}
/// Remove processed downward messages from the `DownwardMessageQueue`.
fn remove_processed_downward_messages(id: ParaId, processed: usize) {
DownwardMessageQueue::<T>::mutate(id, |v| {
if processed > v.len() {
v.clear();
} else {
*v = v.split_off(processed);
}
});
}
/// Update routing information from the parachain heads. This queues upwards
/// messages to the relay chain as well.
fn update_routing(
@@ -1079,6 +1164,11 @@ impl<T: Trait> Module<T> {
})
}
/// Returns the `DownwardMessage`'s for the given parachain.
pub fn downward_messages(id: ParaId) -> Vec<DownwardMessage<T::AccountId>> {
DownwardMessageQueue::<T>::get(id)
}
/// Get the local validation data for a particular parent w.r.t. the current
/// block height.
pub fn current_local_validation_data(id: &ParaId) -> Option<LocalValidationData> {
@@ -1113,8 +1203,7 @@ impl<T: Trait> Module<T> {
schedule: &GlobalValidationSchedule,
attested_candidates: &[AttestedCandidate],
active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
) -> sp_std::result::Result<IncludedBlocks<T>, sp_runtime::DispatchError>
{
) -> sp_std::result::Result<IncludedBlocks<T>, sp_runtime::DispatchError> {
// returns groups of slices that have the same chain ID.
// assumes the inner slice is sorted by id.
struct GroupedDutyIter<'a> {
@@ -3511,4 +3600,40 @@ mod tests {
}
});
}
#[test]
fn downward_message_removal_works() {
let id = ParaId::from(0);
// That the list of egress queue roots is in ascending order by `ParaId`.
let parachains = vec![
(id, vec![].into(), vec![].into()),
];
new_test_ext(parachains).execute_with(|| {
run_to_block(2);
DownwardMessageQueue::<Test>::insert(
&id,
vec![
DownwardMessage::Opaque(vec![1]),
DownwardMessage::Opaque(vec![2]),
DownwardMessage::Opaque(vec![3])
]
);
let mut raw_candidate = raw_candidate(id);
raw_candidate.commitments.processed_downward_messages = 2;
let candidate = make_blank_attested(raw_candidate);
let mut candidates = vec![candidate];
candidates.iter_mut().for_each(make_attestations);
assert_ok!(Parachains::set_heads(Origin::none(), candidates));
assert_eq!(
vec![DownwardMessage::Opaque(vec![3])],
DownwardMessageQueue::<Test>::get(&id),
);
});
}
}
+1
View File
@@ -1074,6 +1074,7 @@ mod tests {
upward_messages: vec![],
erasure_root: [1; 32].into(),
new_validation_code: None,
processed_downward_messages: 0,
},
};
let (candidate, _) = candidate.abridge();