1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
// Copyright (C) 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/>.
//! Bridge relayers registration and slashing scheme.
//!
//! There is an option to add a refund-relayer signed extension that will compensate
//! relayer costs of the message delivery and confirmation transactions (as well as
//! required finality proofs). This extension boosts priority of message delivery
//! transactions, based on the number of bundled messages. So transaction with more
//! messages has larger priority than the transaction with less messages.
//! See `bridge_runtime_common::extensions::priority_calculator` for details;
//!
//! This encourages relayers to include more messages to their delivery transactions.
//! At the same time, we are not verifying storage proofs before boosting
//! priority. Instead, we simply trust relayer, when it says that transaction delivers
//! `N` messages.
//!
//! This allows relayers to submit transactions which declare large number of bundled
//! transactions to receive priority boost for free, potentially pushing actual delivery
//! transactions from the block (or even transaction queue). Such transactions are
//! not free, but their cost is relatively small.
//!
//! To alleviate that, we only boost transactions of relayers that have some stake
//! that guarantees that their transactions are valid. Such relayers get priority
//! for free, but they risk to lose their stake.
use crate::RewardsAccountParams;
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{Get, Zero},
DispatchError, DispatchResult,
};
/// Either explicit account reference or `RewardsAccountParams`.
#[derive(Clone, Debug)]
pub enum ExplicitOrAccountParams<AccountId, LaneId: Decode + Encode> {
/// Explicit account reference.
Explicit(AccountId),
/// Account, referenced using `RewardsAccountParams`.
Params(RewardsAccountParams<LaneId>),
}
impl<AccountId, LaneId: Decode + Encode> From<RewardsAccountParams<LaneId>>
for ExplicitOrAccountParams<AccountId, LaneId>
{
fn from(params: RewardsAccountParams<LaneId>) -> Self {
ExplicitOrAccountParams::Params(params)
}
}
/// Relayer registration.
#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)]
pub struct Registration<BlockNumber, Balance> {
/// The last block number, where this registration is considered active.
///
/// Relayer has an option to renew his registration (this may be done before it
/// is spoiled as well). Starting from block `valid_till + 1`, relayer may `deregister`
/// himself and get his stake back.
///
/// Please keep in mind that priority boost stops working some blocks before the
/// registration ends (see [`StakeAndSlash::RequiredRegistrationLease`]).
pub valid_till: BlockNumber,
/// Active relayer stake, which is mapped to the relayer reserved balance.
///
/// If `stake` is less than the [`StakeAndSlash::RequiredStake`], the registration
/// is considered inactive even if `valid_till + 1` is not yet reached.
pub stake: Balance,
}
/// Relayer stake-and-slash mechanism.
pub trait StakeAndSlash<AccountId, BlockNumber, Balance> {
/// The stake that the relayer must have to have its transactions boosted.
type RequiredStake: Get<Balance>;
/// Required **remaining** registration lease to be able to get transaction priority boost.
///
/// If the difference between registration's `valid_till` and the current block number
/// is less than the `RequiredRegistrationLease`, it becomes inactive and relayer transaction
/// won't get priority boost. This period exists, because priority is calculated when
/// transaction is placed to the queue (and it is reevaluated periodically) and then some time
/// may pass before transaction will be included into the block.
type RequiredRegistrationLease: Get<BlockNumber>;
/// Reserve the given amount at relayer account.
fn reserve(relayer: &AccountId, amount: Balance) -> DispatchResult;
/// `Unreserve` the given amount from relayer account.
///
/// Returns amount that we have failed to `unreserve`.
fn unreserve(relayer: &AccountId, amount: Balance) -> Balance;
/// Slash up to `amount` from reserved balance of account `relayer` and send funds to given
/// `beneficiary`.
///
/// Returns `Ok(_)` with non-zero balance if we have failed to repatriate some portion of stake.
fn repatriate_reserved<LaneId: Decode + Encode>(
relayer: &AccountId,
beneficiary: ExplicitOrAccountParams<AccountId, LaneId>,
amount: Balance,
) -> Result<Balance, DispatchError>;
}
impl<AccountId, BlockNumber, Balance> StakeAndSlash<AccountId, BlockNumber, Balance> for ()
where
Balance: Default + Zero,
BlockNumber: Default,
{
type RequiredStake = ();
type RequiredRegistrationLease = ();
fn reserve(_relayer: &AccountId, _amount: Balance) -> DispatchResult {
Ok(())
}
fn unreserve(_relayer: &AccountId, _amount: Balance) -> Balance {
Zero::zero()
}
fn repatriate_reserved<LaneId: Decode + Encode>(
_relayer: &AccountId,
_beneficiary: ExplicitOrAccountParams<AccountId, LaneId>,
_amount: Balance,
) -> Result<Balance, DispatchError> {
Ok(Zero::zero())
}
}