mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 11:01:01 +00:00
Remove message fee + message send calls (#1642)
* remove message fee * it is compiling! * fixes + fmt * more cleanup * more cleanup * restore MessageDeliveryAndDispatchPayment since we'll need relayer rewards * started rational relayer removal * more removal * removed estimate fee subcommand * remove DispatchFeePayment * more removals * removed conversion rates && some metrics * - unneeded associated type * - OutboundMessageFee * fix benchmarks compilation * fmt * test + fix benchmarks * fix send message * clippy
This commit is contained in:
committed by
Bastian Köcher
parent
1217b2cf80
commit
8c845602cf
@@ -29,9 +29,9 @@ mod metrics;
|
||||
|
||||
pub mod message_lane;
|
||||
pub mod message_lane_loop;
|
||||
pub mod relay_strategy;
|
||||
|
||||
mod message_race_delivery;
|
||||
mod message_race_limits;
|
||||
mod message_race_loop;
|
||||
mod message_race_receiving;
|
||||
mod message_race_strategy;
|
||||
|
||||
@@ -30,7 +30,6 @@ use async_trait::async_trait;
|
||||
use futures::{channel::mpsc::unbounded, future::FutureExt, stream::StreamExt};
|
||||
|
||||
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight};
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
use relay_utils::{
|
||||
interval, metrics::MetricsParams, process_future_result, relay_loop::Client as RelayClient,
|
||||
retry_backoff, FailedClient, TransactionTracker,
|
||||
@@ -41,12 +40,11 @@ use crate::{
|
||||
message_race_delivery::run as run_message_delivery_race,
|
||||
message_race_receiving::run as run_message_receiving_race,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
relay_strategy::RelayStrategy,
|
||||
};
|
||||
|
||||
/// Message lane loop configuration params.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Params<Strategy: RelayStrategy> {
|
||||
pub struct Params {
|
||||
/// Id of lane this loop is servicing.
|
||||
pub lane: LaneId,
|
||||
/// Interval at which we ask target node about its updates.
|
||||
@@ -56,22 +54,12 @@ pub struct Params<Strategy: RelayStrategy> {
|
||||
/// Delay between moments when connection error happens and our reconnect attempt.
|
||||
pub reconnect_delay: Duration,
|
||||
/// Message delivery race parameters.
|
||||
pub delivery_params: MessageDeliveryParams<Strategy>,
|
||||
}
|
||||
|
||||
/// Relayer operating mode.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RelayerMode {
|
||||
/// The relayer doesn't care about rewards.
|
||||
Altruistic,
|
||||
/// The relayer will deliver all messages and confirmations as long as he's not losing any
|
||||
/// funds.
|
||||
Rational,
|
||||
pub delivery_params: MessageDeliveryParams,
|
||||
}
|
||||
|
||||
/// Message delivery race parameters.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MessageDeliveryParams<Strategy: RelayStrategy> {
|
||||
pub struct MessageDeliveryParams {
|
||||
/// Maximal number of unconfirmed relayer entries at the inbound lane. If there's that number
|
||||
/// of entries in the `InboundLaneData::relayers` set, all new messages will be rejected until
|
||||
/// reward payment will be proved (by including outbound lane state to the message delivery
|
||||
@@ -87,8 +75,6 @@ pub struct MessageDeliveryParams<Strategy: RelayStrategy> {
|
||||
pub max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal cumulative size of relayed messages in single delivery transaction.
|
||||
pub max_messages_size_in_single_batch: u32,
|
||||
/// Relay strategy
|
||||
pub relay_strategy: Strategy,
|
||||
}
|
||||
|
||||
/// Message details.
|
||||
@@ -100,8 +86,6 @@ pub struct MessageDetails<SourceChainBalance> {
|
||||
pub size: u32,
|
||||
/// The relayer reward paid in the source chain tokens.
|
||||
pub reward: SourceChainBalance,
|
||||
/// Where the fee for dispatching message is paid?
|
||||
pub dispatch_fee_payment: DispatchFeePayment,
|
||||
}
|
||||
|
||||
/// Messages details map.
|
||||
@@ -173,9 +157,6 @@ pub trait SourceClient<P: MessageLane>: RelayClient {
|
||||
|
||||
/// We need given finalized target header on source to continue synchronization.
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<P>);
|
||||
|
||||
/// Estimate cost of single message confirmation transaction in source chain tokens.
|
||||
async fn estimate_confirmation_transaction(&self) -> P::SourceChainBalance;
|
||||
}
|
||||
|
||||
/// Target client trait.
|
||||
@@ -221,18 +202,6 @@ pub trait TargetClient<P: MessageLane>: RelayClient {
|
||||
|
||||
/// We need given finalized source header on target to continue synchronization.
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<P>);
|
||||
|
||||
/// Estimate cost of messages delivery transaction in source chain tokens.
|
||||
///
|
||||
/// Please keep in mind that the returned cost must be converted to the source chain
|
||||
/// tokens, even though the transaction fee will be paid in the target chain tokens.
|
||||
async fn estimate_delivery_transaction_in_source_tokens(
|
||||
&self,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
total_prepaid_nonces: MessageNonce,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> Result<P::SourceChainBalance, Self::Error>;
|
||||
}
|
||||
|
||||
/// State of the client.
|
||||
@@ -272,8 +241,8 @@ pub fn metrics_prefix<P: MessageLane>(lane: &LaneId) -> String {
|
||||
}
|
||||
|
||||
/// Run message lane service loop.
|
||||
pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
params: Params<Strategy>,
|
||||
pub async fn run<P: MessageLane>(
|
||||
params: Params,
|
||||
source_client: impl SourceClient<P>,
|
||||
target_client: impl TargetClient<P>,
|
||||
metrics_params: MetricsParams,
|
||||
@@ -283,11 +252,7 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
relay_utils::relay_loop(source_client, target_client)
|
||||
.reconnect_delay(params.reconnect_delay)
|
||||
.with_metrics(metrics_params)
|
||||
.loop_metric(MessageLaneLoopMetrics::new(
|
||||
Some(&metrics_prefix::<P>(¶ms.lane)),
|
||||
P::SOURCE_NAME,
|
||||
P::TARGET_NAME,
|
||||
)?)?
|
||||
.loop_metric(MessageLaneLoopMetrics::new(Some(&metrics_prefix::<P>(¶ms.lane)))?)?
|
||||
.expose()
|
||||
.await?
|
||||
.run(metrics_prefix::<P>(¶ms.lane), move |source_client, target_client, metrics| {
|
||||
@@ -304,13 +269,8 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
|
||||
/// Run one-way message delivery loop until connection with target or source node is lost, or exit
|
||||
/// signal is received.
|
||||
async fn run_until_connection_lost<
|
||||
P: MessageLane,
|
||||
Strategy: RelayStrategy,
|
||||
SC: SourceClient<P>,
|
||||
TC: TargetClient<P>,
|
||||
>(
|
||||
params: Params<Strategy>,
|
||||
async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: TargetClient<P>>(
|
||||
params: Params,
|
||||
source_client: SC,
|
||||
target_client: TC,
|
||||
metrics_msg: Option<MessageLaneLoopMetrics>,
|
||||
@@ -477,17 +437,12 @@ pub(crate) mod tests {
|
||||
|
||||
use relay_utils::{HeaderId, MaybeConnectionError, TrackedTransactionStatus};
|
||||
|
||||
use crate::relay_strategy::AltruisticStrategy;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn header_id(number: TestSourceHeaderNumber) -> TestSourceHeaderId {
|
||||
HeaderId(number, number)
|
||||
}
|
||||
|
||||
pub const CONFIRMATION_TRANSACTION_COST: TestSourceChainBalance = 1;
|
||||
pub const BASE_MESSAGE_DELIVERY_TRANSACTION_COST: TestSourceChainBalance = 1;
|
||||
|
||||
pub type TestSourceChainBalance = u64;
|
||||
pub type TestSourceHeaderId = HeaderId<TestSourceHeaderNumber, TestSourceHeaderHash>;
|
||||
pub type TestTargetHeaderId = HeaderId<TestTargetHeaderNumber, TestTargetHeaderHash>;
|
||||
@@ -681,7 +636,6 @@ pub(crate) mod tests {
|
||||
dispatch_weight: Weight::from_ref_time(1),
|
||||
size: 1,
|
||||
reward: 1,
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -737,10 +691,6 @@ pub(crate) mod tests {
|
||||
(self.tick)(&mut data);
|
||||
(self.post_tick)(&mut data);
|
||||
}
|
||||
|
||||
async fn estimate_confirmation_transaction(&self) -> TestSourceChainBalance {
|
||||
CONFIRMATION_TRANSACTION_COST
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -871,20 +821,6 @@ pub(crate) mod tests {
|
||||
(self.tick)(&mut data);
|
||||
(self.post_tick)(&mut data);
|
||||
}
|
||||
|
||||
async fn estimate_delivery_transaction_in_source_tokens(
|
||||
&self,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
_total_prepaid_nonces: MessageNonce,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> Result<TestSourceChainBalance, TestError> {
|
||||
Ok((Weight::from_ref_time(BASE_MESSAGE_DELIVERY_TRANSACTION_COST) *
|
||||
(nonces.end() - nonces.start() + 1) +
|
||||
total_dispatch_weight +
|
||||
Weight::from_ref_time(total_size as u64))
|
||||
.ref_time())
|
||||
}
|
||||
}
|
||||
|
||||
fn run_loop_test(
|
||||
@@ -920,7 +856,6 @@ pub(crate) mod tests {
|
||||
max_messages_in_single_batch: 4,
|
||||
max_messages_weight_in_single_batch: Weight::from_ref_time(4),
|
||||
max_messages_size_in_single_batch: 4,
|
||||
relay_strategy: AltruisticStrategy,
|
||||
},
|
||||
},
|
||||
source_client,
|
||||
|
||||
@@ -28,23 +28,23 @@ use crate::{
|
||||
SourceClient as MessageLaneSourceClient, SourceClientState,
|
||||
TargetClient as MessageLaneTargetClient, TargetClientState,
|
||||
},
|
||||
message_race_limits::{MessageRaceLimits, RelayMessagesBatchReference},
|
||||
message_race_loop::{
|
||||
MessageRace, NoncesRange, RaceState, RaceStrategy, SourceClient, SourceClientNonces,
|
||||
TargetClient, TargetClientNonces,
|
||||
},
|
||||
message_race_strategy::BasicStrategy,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
relay_strategy::{EnforcementStrategy, RelayMessagesBatchReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// Run message delivery race.
|
||||
pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
pub async fn run<P: MessageLane>(
|
||||
source_client: impl MessageLaneSourceClient<P>,
|
||||
source_state_updates: impl FusedStream<Item = SourceClientState<P>>,
|
||||
target_client: impl MessageLaneTargetClient<P>,
|
||||
target_state_updates: impl FusedStream<Item = TargetClientState<P>>,
|
||||
metrics_msg: Option<MessageLaneLoopMetrics>,
|
||||
params: MessageDeliveryParams<Strategy>,
|
||||
params: MessageDeliveryParams,
|
||||
) -> Result<(), FailedClient> {
|
||||
crate::message_race_loop::run(
|
||||
MessageDeliveryRaceSource {
|
||||
@@ -59,7 +59,7 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
_phantom: Default::default(),
|
||||
},
|
||||
target_state_updates,
|
||||
MessageDeliveryStrategy::<P, Strategy, _, _> {
|
||||
MessageDeliveryStrategy::<P, _, _> {
|
||||
lane_source_client: source_client,
|
||||
lane_target_client: target_client,
|
||||
max_unrewarded_relayer_entries_at_target: params
|
||||
@@ -68,7 +68,6 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
max_messages_in_single_batch: params.max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch: params.max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch: params.max_messages_size_in_single_batch,
|
||||
relay_strategy: params.relay_strategy,
|
||||
latest_confirmed_nonces_at_source: VecDeque::new(),
|
||||
target_nonces: None,
|
||||
strategy: BasicStrategy::new(),
|
||||
@@ -231,7 +230,7 @@ struct DeliveryRaceTargetNoncesData {
|
||||
}
|
||||
|
||||
/// Messages delivery strategy.
|
||||
struct MessageDeliveryStrategy<P: MessageLane, Strategy: RelayStrategy, SC, TC> {
|
||||
struct MessageDeliveryStrategy<P: MessageLane, SC, TC> {
|
||||
/// The client that is connected to the message lane source node.
|
||||
lane_source_client: SC,
|
||||
/// The client that is connected to the message lane target node.
|
||||
@@ -246,8 +245,6 @@ struct MessageDeliveryStrategy<P: MessageLane, Strategy: RelayStrategy, SC, TC>
|
||||
max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal messages size in the single delivery transaction.
|
||||
max_messages_size_in_single_batch: u32,
|
||||
/// Relayer operating mode.
|
||||
relay_strategy: Strategy,
|
||||
/// Latest confirmed nonces at the source client + the header id where we have first met this
|
||||
/// nonce.
|
||||
latest_confirmed_nonces_at_source: VecDeque<(SourceHeaderIdOf<P>, MessageNonce)>,
|
||||
@@ -268,9 +265,7 @@ type MessageDeliveryStrategyBase<P> = BasicStrategy<
|
||||
<P as MessageLane>::MessagesProof,
|
||||
>;
|
||||
|
||||
impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> std::fmt::Debug
|
||||
for MessageDeliveryStrategy<P, Strategy, SC, TC>
|
||||
{
|
||||
impl<P: MessageLane, SC, TC> std::fmt::Debug for MessageDeliveryStrategy<P, SC, TC> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fmt.debug_struct("MessageDeliveryStrategy")
|
||||
.field(
|
||||
@@ -288,7 +283,7 @@ impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> std::fmt::Debug
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> MessageDeliveryStrategy<P, Strategy, SC, TC> {
|
||||
impl<P: MessageLane, SC, TC> MessageDeliveryStrategy<P, SC, TC> {
|
||||
/// Returns total weight of all undelivered messages.
|
||||
fn total_queued_dispatch_weight(&self) -> Weight {
|
||||
self.strategy
|
||||
@@ -300,9 +295,8 @@ impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> MessageDeliveryStrategy<P,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<P, Strategy: RelayStrategy, SC, TC>
|
||||
RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessagesProof>
|
||||
for MessageDeliveryStrategy<P, Strategy, SC, TC>
|
||||
impl<P, SC, TC> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessagesProof>
|
||||
for MessageDeliveryStrategy<P, SC, TC>
|
||||
where
|
||||
P: MessageLane,
|
||||
SC: MessageLaneSourceClient<P>,
|
||||
@@ -524,8 +518,7 @@ where
|
||||
metrics: self.metrics_msg.clone(),
|
||||
};
|
||||
|
||||
let mut strategy = EnforcementStrategy::new(self.relay_strategy.clone());
|
||||
let range_end = strategy.decide(reference).await?;
|
||||
let range_end = MessageRaceLimits::decide(reference).await?;
|
||||
|
||||
let range_begin = source_queue[0].1.begin();
|
||||
let selected_nonces = range_begin..=range_end;
|
||||
@@ -562,38 +555,27 @@ impl<SourceChainBalance: std::fmt::Debug> NoncesRange for MessageDetailsMap<Sour
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
|
||||
use crate::{
|
||||
message_lane_loop::{
|
||||
tests::{
|
||||
header_id, TestMessageLane, TestMessagesProof, TestSourceChainBalance,
|
||||
TestSourceClient, TestSourceHeaderId, TestTargetClient, TestTargetHeaderId,
|
||||
BASE_MESSAGE_DELIVERY_TRANSACTION_COST, CONFIRMATION_TRANSACTION_COST,
|
||||
},
|
||||
MessageDetails, RelayerMode,
|
||||
use crate::message_lane_loop::{
|
||||
tests::{
|
||||
header_id, TestMessageLane, TestMessagesProof, TestSourceChainBalance,
|
||||
TestSourceClient, TestSourceHeaderId, TestTargetClient, TestTargetHeaderId,
|
||||
},
|
||||
relay_strategy::MixStrategy,
|
||||
MessageDetails,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
const DEFAULT_DISPATCH_WEIGHT: Weight = Weight::from_ref_time(1);
|
||||
const DEFAULT_SIZE: u32 = 1;
|
||||
const DEFAULT_REWARD: TestSourceChainBalance = CONFIRMATION_TRANSACTION_COST +
|
||||
BASE_MESSAGE_DELIVERY_TRANSACTION_COST +
|
||||
DEFAULT_DISPATCH_WEIGHT.ref_time() +
|
||||
(DEFAULT_SIZE as TestSourceChainBalance);
|
||||
|
||||
type TestRaceState = RaceState<TestSourceHeaderId, TestTargetHeaderId, TestMessagesProof>;
|
||||
type TestStrategy =
|
||||
MessageDeliveryStrategy<TestMessageLane, MixStrategy, TestSourceClient, TestTargetClient>;
|
||||
MessageDeliveryStrategy<TestMessageLane, TestSourceClient, TestTargetClient>;
|
||||
|
||||
fn source_nonces(
|
||||
new_nonces: RangeInclusive<MessageNonce>,
|
||||
confirmed_nonce: MessageNonce,
|
||||
reward: TestSourceChainBalance,
|
||||
dispatch_fee_payment: DispatchFeePayment,
|
||||
) -> SourceClientNonces<MessageDetailsMap<TestSourceChainBalance>> {
|
||||
SourceClientNonces {
|
||||
new_nonces: new_nonces
|
||||
@@ -605,7 +587,6 @@ mod tests {
|
||||
dispatch_weight: DEFAULT_DISPATCH_WEIGHT,
|
||||
size: DEFAULT_SIZE,
|
||||
reward,
|
||||
dispatch_fee_payment,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -648,13 +629,11 @@ mod tests {
|
||||
},
|
||||
}),
|
||||
strategy: BasicStrategy::new(),
|
||||
relay_strategy: MixStrategy::new(RelayerMode::Altruistic),
|
||||
};
|
||||
|
||||
race_strategy.strategy.source_nonces_updated(
|
||||
header_id(1),
|
||||
source_nonces(20..=23, 19, DEFAULT_REWARD, DispatchFeePayment::AtSourceChain),
|
||||
);
|
||||
race_strategy
|
||||
.strategy
|
||||
.source_nonces_updated(header_id(1), source_nonces(20..=23, 19, 0));
|
||||
|
||||
let target_nonces = TargetClientNonces { latest_nonce: 19, nonces_data: () };
|
||||
race_strategy
|
||||
@@ -687,7 +666,6 @@ mod tests {
|
||||
dispatch_weight: Weight::from_ref_time(idx),
|
||||
size: idx as _,
|
||||
reward: idx as _,
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -978,83 +956,6 @@ mod tests {
|
||||
assert_eq!(strategy.required_source_header_at_target(&header_id(1)), Some(header_id(2)));
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn rational_relayer_is_delivering_messages_if_cost_is_equal_to_reward() {
|
||||
let (state, mut strategy) = prepare_strategy();
|
||||
strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
|
||||
|
||||
// so now we have:
|
||||
// - 20..=23 with reward = cost
|
||||
// => strategy shall select all 20..=23
|
||||
assert_eq!(
|
||||
strategy.select_nonces_to_deliver(state).await,
|
||||
Some(((20..=23), proof_parameters(false, 4)))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn rational_relayer_is_not_delivering_messages_if_cost_is_larger_than_reward() {
|
||||
let (mut state, mut strategy) = prepare_strategy();
|
||||
let nonces = source_nonces(
|
||||
24..=25,
|
||||
19,
|
||||
DEFAULT_REWARD - BASE_MESSAGE_DELIVERY_TRANSACTION_COST,
|
||||
DispatchFeePayment::AtSourceChain,
|
||||
);
|
||||
strategy.strategy.source_nonces_updated(header_id(2), nonces);
|
||||
state.best_finalized_source_header_id_at_best_target = Some(header_id(2));
|
||||
strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
|
||||
|
||||
// so now we have:
|
||||
// - 20..=23 with reward = cost
|
||||
// - 24..=25 with reward less than cost
|
||||
// => strategy shall only select 20..=23
|
||||
assert_eq!(
|
||||
strategy.select_nonces_to_deliver(state).await,
|
||||
Some(((20..=23), proof_parameters(false, 4)))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn rational_relayer_is_delivering_unpaid_messages() {
|
||||
async fn test_with_dispatch_fee_payment(
|
||||
dispatch_fee_payment: DispatchFeePayment,
|
||||
) -> Option<(RangeInclusive<MessageNonce>, MessageProofParameters)> {
|
||||
let (mut state, mut strategy) = prepare_strategy();
|
||||
let nonces = source_nonces(
|
||||
24..=24,
|
||||
19,
|
||||
DEFAULT_REWARD - DEFAULT_DISPATCH_WEIGHT.ref_time(),
|
||||
dispatch_fee_payment,
|
||||
);
|
||||
strategy.strategy.source_nonces_updated(header_id(2), nonces);
|
||||
state.best_finalized_source_header_id_at_best_target = Some(header_id(2));
|
||||
strategy.max_unrewarded_relayer_entries_at_target = 100;
|
||||
strategy.max_unconfirmed_nonces_at_target = 100;
|
||||
strategy.max_messages_in_single_batch = 100;
|
||||
strategy.max_messages_weight_in_single_batch = Weight::from_ref_time(100);
|
||||
strategy.max_messages_size_in_single_batch = 100;
|
||||
strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
|
||||
|
||||
// so now we have:
|
||||
// - 20..=23 with reward = cost
|
||||
// - 24..=24 with reward less than cost, but we're deducting `DEFAULT_DISPATCH_WEIGHT`
|
||||
// from the cost, so it should be fine;
|
||||
// => when MSG#24 fee is paid at the target chain, strategy shall select all 20..=24
|
||||
// => when MSG#25 fee is paid at the source chain, strategy shall only select 20..=23
|
||||
strategy.select_nonces_to_deliver(state).await
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
test_with_dispatch_fee_payment(DispatchFeePayment::AtTargetChain).await,
|
||||
Some(((20..=24), proof_parameters(false, 5)))
|
||||
);
|
||||
assert_eq!(
|
||||
test_with_dispatch_fee_payment(DispatchFeePayment::AtSourceChain).await,
|
||||
Some(((20..=23), proof_parameters(false, 4)))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn relayer_uses_flattened_view_of_the_source_queue_to_select_nonces() {
|
||||
// Real scenario that has happened on test deployments:
|
||||
@@ -1066,7 +967,7 @@ mod tests {
|
||||
// This was happening because selector (`select_nonces_for_delivery_transaction`) has been
|
||||
// called for every `source_queue` entry separately without preserving any context.
|
||||
let (mut state, mut strategy) = prepare_strategy();
|
||||
let nonces = source_nonces(24..=25, 19, DEFAULT_REWARD, DispatchFeePayment::AtSourceChain);
|
||||
let nonces = source_nonces(24..=25, 19, 0);
|
||||
strategy.strategy.source_nonces_updated(header_id(2), nonces);
|
||||
strategy.max_unrewarded_relayer_entries_at_target = 100;
|
||||
strategy.max_unconfirmed_nonces_at_target = 100;
|
||||
|
||||
+61
-85
@@ -17,43 +17,88 @@
|
||||
//! enforcement strategy
|
||||
|
||||
use num_traits::Zero;
|
||||
use std::ops::Range;
|
||||
|
||||
use bp_messages::{MessageNonce, Weight};
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
MessageDetails, SourceClient as MessageLaneSourceClient,
|
||||
MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient,
|
||||
TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
message_race_loop::NoncesRange,
|
||||
relay_strategy::{RelayMessagesBatchReference, RelayReference, RelayStrategy},
|
||||
message_race_strategy::SourceRangesQueue,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
};
|
||||
|
||||
/// Do hard check and run soft check strategy
|
||||
/// Reference data for participating in relay
|
||||
pub struct RelayReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Messages size summary
|
||||
pub selected_size: u32,
|
||||
|
||||
/// Hard check begin nonce
|
||||
pub hard_selected_begin_nonce: MessageNonce,
|
||||
|
||||
/// Index by all ready nonces
|
||||
pub index: usize,
|
||||
/// Current nonce
|
||||
pub nonce: MessageNonce,
|
||||
/// Current nonce details
|
||||
pub details: MessageDetails<P::SourceChainBalance>,
|
||||
}
|
||||
|
||||
/// Relay reference data
|
||||
pub struct RelayMessagesBatchReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// Maximal number of relayed messages in single delivery transaction.
|
||||
pub max_messages_in_this_batch: MessageNonce,
|
||||
/// Maximal cumulative dispatch weight of relayed messages in single delivery transaction.
|
||||
pub max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal cumulative size of relayed messages in single delivery transaction.
|
||||
pub max_messages_size_in_single_batch: u32,
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Source queue.
|
||||
pub nonces_queue: SourceRangesQueue<
|
||||
P::SourceHeaderHash,
|
||||
P::SourceHeaderNumber,
|
||||
MessageDetailsMap<P::SourceChainBalance>,
|
||||
>,
|
||||
/// Source queue range
|
||||
pub nonces_queue_range: Range<usize>,
|
||||
}
|
||||
|
||||
/// Limits of the message race transactions.
|
||||
#[derive(Clone)]
|
||||
pub struct EnforcementStrategy<Strategy: RelayStrategy> {
|
||||
strategy: Strategy,
|
||||
}
|
||||
pub struct MessageRaceLimits;
|
||||
|
||||
impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
pub fn new(strategy: Strategy) -> Self {
|
||||
Self { strategy }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
impl MessageRaceLimits {
|
||||
pub async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: RelayMessagesBatchReference<P, SourceClient, TargetClient>,
|
||||
) -> Option<MessageNonce> {
|
||||
let mut hard_selected_count = 0;
|
||||
let mut soft_selected_count = 0;
|
||||
|
||||
let mut selected_weight = Weight::zero();
|
||||
let mut selected_count: MessageNonce = 0;
|
||||
@@ -67,17 +112,9 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
lane_target_client: reference.lane_target_client.clone(),
|
||||
metrics: reference.metrics.clone(),
|
||||
|
||||
selected_reward: P::SourceChainBalance::zero(),
|
||||
selected_cost: P::SourceChainBalance::zero(),
|
||||
selected_size: 0,
|
||||
|
||||
total_reward: P::SourceChainBalance::zero(),
|
||||
total_confirmations_cost: P::SourceChainBalance::zero(),
|
||||
total_cost: P::SourceChainBalance::zero(),
|
||||
|
||||
hard_selected_begin_nonce,
|
||||
selected_prepaid_nonces: 0,
|
||||
selected_unpaid_weight: Weight::zero(),
|
||||
|
||||
index: 0,
|
||||
nonce: 0,
|
||||
@@ -85,7 +122,6 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
dispatch_weight: Weight::zero(),
|
||||
size: 0,
|
||||
reward: P::SourceChainBalance::zero(),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -148,74 +184,14 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
}
|
||||
relay_reference.selected_size = new_selected_size;
|
||||
|
||||
// If dispatch fee has been paid at the source chain, it means that it is **relayer**
|
||||
// who's paying for dispatch at the target chain AND reward must cover this dispatch
|
||||
// fee.
|
||||
//
|
||||
// If dispatch fee is paid at the target chain, it means that it'll be withdrawn from
|
||||
// the dispatch origin account AND reward is not covering this fee.
|
||||
//
|
||||
// So in the latter case we're not adding the dispatch weight to the delivery
|
||||
// transaction weight.
|
||||
let mut new_selected_prepaid_nonces = relay_reference.selected_prepaid_nonces;
|
||||
let new_selected_unpaid_weight = match details.dispatch_fee_payment {
|
||||
DispatchFeePayment::AtSourceChain => {
|
||||
new_selected_prepaid_nonces += 1;
|
||||
relay_reference.selected_unpaid_weight.saturating_add(details.dispatch_weight)
|
||||
},
|
||||
DispatchFeePayment::AtTargetChain => relay_reference.selected_unpaid_weight,
|
||||
};
|
||||
relay_reference.selected_prepaid_nonces = new_selected_prepaid_nonces;
|
||||
relay_reference.selected_unpaid_weight = new_selected_unpaid_weight;
|
||||
|
||||
// now the message has passed all 'strong' checks, and we CAN deliver it. But do we WANT
|
||||
// to deliver it? It depends on the relayer strategy.
|
||||
if self.strategy.decide(&mut relay_reference).await {
|
||||
soft_selected_count = index + 1;
|
||||
}
|
||||
|
||||
hard_selected_count = index + 1;
|
||||
selected_weight = new_selected_weight;
|
||||
selected_count = new_selected_count;
|
||||
}
|
||||
|
||||
if hard_selected_count != soft_selected_count {
|
||||
let hard_selected_end_nonce =
|
||||
hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
|
||||
let soft_selected_begin_nonce = hard_selected_begin_nonce;
|
||||
let soft_selected_end_nonce =
|
||||
soft_selected_begin_nonce + soft_selected_count as MessageNonce - 1;
|
||||
log::warn!(
|
||||
target: "bridge",
|
||||
"Relayer may deliver nonces [{:?}; {:?}], but because of its strategy it has selected \
|
||||
nonces [{:?}; {:?}].",
|
||||
hard_selected_begin_nonce,
|
||||
hard_selected_end_nonce,
|
||||
soft_selected_begin_nonce,
|
||||
soft_selected_end_nonce,
|
||||
);
|
||||
|
||||
hard_selected_count = soft_selected_count;
|
||||
}
|
||||
|
||||
if hard_selected_count != 0 {
|
||||
if relay_reference.selected_reward != P::SourceChainBalance::zero() &&
|
||||
relay_reference.selected_cost != P::SourceChainBalance::zero()
|
||||
{
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Expected reward from delivering nonces [{:?}; {:?}] is: {:?} - {:?} = {:?}",
|
||||
hard_selected_begin_nonce,
|
||||
hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1,
|
||||
&relay_reference.selected_reward,
|
||||
&relay_reference.selected_cost,
|
||||
relay_reference.selected_reward - relay_reference.selected_cost,
|
||||
);
|
||||
}
|
||||
|
||||
let selected_max_nonce =
|
||||
hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
|
||||
self.strategy.on_final_decision(&relay_reference);
|
||||
Some(selected_max_nonce)
|
||||
} else {
|
||||
None
|
||||
@@ -24,7 +24,7 @@ use crate::{
|
||||
use bp_messages::MessageNonce;
|
||||
use finality_relay::SyncLoopMetrics;
|
||||
use relay_utils::metrics::{
|
||||
metric_name, register, Counter, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
|
||||
metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
|
||||
};
|
||||
|
||||
/// Message lane relay metrics.
|
||||
@@ -39,17 +39,11 @@ pub struct MessageLaneLoopMetrics {
|
||||
/// Lane state nonces: "source_latest_generated", "source_latest_confirmed",
|
||||
/// "target_latest_received", "target_latest_confirmed".
|
||||
lane_state_nonces: GaugeVec<U64>,
|
||||
/// Count of unprofitable message delivery transactions that we have submitted so far.
|
||||
unprofitable_delivery_transactions: Counter<U64>,
|
||||
}
|
||||
|
||||
impl MessageLaneLoopMetrics {
|
||||
/// Create and register messages loop metrics.
|
||||
pub fn new(
|
||||
prefix: Option<&str>,
|
||||
source_name: &str,
|
||||
target_name: &str,
|
||||
) -> Result<Self, PrometheusError> {
|
||||
pub fn new(prefix: Option<&str>) -> Result<Self, PrometheusError> {
|
||||
Ok(MessageLaneLoopMetrics {
|
||||
source_to_target_finality_metrics: SyncLoopMetrics::new(
|
||||
prefix,
|
||||
@@ -65,13 +59,6 @@ impl MessageLaneLoopMetrics {
|
||||
Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"),
|
||||
&["type"],
|
||||
)?,
|
||||
unprofitable_delivery_transactions: Counter::new(
|
||||
metric_name(prefix, "unprofitable_delivery_transactions"),
|
||||
format!(
|
||||
"Count of unprofitable message delivery transactions from {} to {}",
|
||||
source_name, target_name
|
||||
),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -140,11 +127,6 @@ impl MessageLaneLoopMetrics {
|
||||
.with_label_values(&["target_latest_confirmed"])
|
||||
.set(target_latest_confirmed_nonce);
|
||||
}
|
||||
|
||||
/// Note unprofitable delivery transaction.
|
||||
pub fn note_unprofitable_delivery_transactions(&self) {
|
||||
self.unprofitable_delivery_transactions.inc()
|
||||
}
|
||||
}
|
||||
|
||||
impl Metric for MessageLaneLoopMetrics {
|
||||
@@ -152,7 +134,6 @@ impl Metric for MessageLaneLoopMetrics {
|
||||
self.source_to_target_finality_metrics.register(registry)?;
|
||||
self.target_to_source_finality_metrics.register(registry)?;
|
||||
register(self.lane_state_nonces.clone(), registry)?;
|
||||
register(self.unprofitable_delivery_transactions.clone(), registry)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +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/>.
|
||||
|
||||
//! Altruistic relay strategy
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
SourceClient as MessageLaneSourceClient, TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
relay_strategy::{RelayReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// The relayer doesn't care about rewards.
|
||||
#[derive(Clone)]
|
||||
pub struct AltruisticStrategy;
|
||||
|
||||
#[async_trait]
|
||||
impl RelayStrategy for AltruisticStrategy {
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool {
|
||||
// We don't care about costs and rewards, but we want to report unprofitable transactions.
|
||||
if let Err(e) = reference.update_cost_and_reward().await {
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Failed to update transaction cost and reward: {:?}. \
|
||||
The `unprofitable_delivery_transactions` metric will be inaccurate",
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
) {
|
||||
if let Some(ref metrics) = reference.metrics {
|
||||
if !reference.is_profitable() {
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"The relayer has submitted unprofitable {} -> {} message delivery transaction \
|
||||
with {} messages: total cost = {:?}, total reward = {:?}",
|
||||
P::SOURCE_NAME,
|
||||
P::TARGET_NAME,
|
||||
reference.index + 1,
|
||||
reference.total_cost,
|
||||
reference.total_reward,
|
||||
);
|
||||
|
||||
metrics.note_unprofitable_delivery_transactions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +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/>.
|
||||
|
||||
//! Adapter for using `enum RelayerMode` in a context which requires `RelayStrategy`.
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
RelayerMode, SourceClient as MessageLaneSourceClient,
|
||||
TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
relay_strategy::{AltruisticStrategy, RationalStrategy, RelayReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// `RelayerMode` adapter.
|
||||
#[derive(Clone)]
|
||||
pub struct MixStrategy {
|
||||
relayer_mode: RelayerMode,
|
||||
}
|
||||
|
||||
impl MixStrategy {
|
||||
/// Create mix strategy instance
|
||||
pub fn new(relayer_mode: RelayerMode) -> Self {
|
||||
Self { relayer_mode }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RelayStrategy for MixStrategy {
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool {
|
||||
match self.relayer_mode {
|
||||
RelayerMode::Altruistic => AltruisticStrategy.decide(reference).await,
|
||||
RelayerMode::Rational => RationalStrategy.decide(reference).await,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
) {
|
||||
match self.relayer_mode {
|
||||
RelayerMode::Altruistic => AltruisticStrategy.on_final_decision(reference),
|
||||
RelayerMode::Rational => RationalStrategy.on_final_decision(reference),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,224 +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/>.
|
||||
|
||||
//! Relayer strategy
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{MessageNonce, Weight};
|
||||
use sp_arithmetic::traits::Saturating;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient,
|
||||
TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
message_race_strategy::SourceRangesQueue,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
};
|
||||
|
||||
pub(crate) use self::enforcement_strategy::*;
|
||||
pub use self::{altruistic_strategy::*, mix_strategy::*, rational_strategy::*};
|
||||
|
||||
mod altruistic_strategy;
|
||||
mod enforcement_strategy;
|
||||
mod mix_strategy;
|
||||
mod rational_strategy;
|
||||
|
||||
/// Relayer strategy trait
|
||||
#[async_trait]
|
||||
pub trait RelayStrategy: 'static + Clone + Send + Sync {
|
||||
/// The relayer decide how to process nonce by reference.
|
||||
/// From given set of source nonces, that are ready to be delivered, select nonces
|
||||
/// to fit into single delivery transaction.
|
||||
///
|
||||
/// The function returns last nonce that must be delivered to the target chain.
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool;
|
||||
|
||||
/// Notification that the following maximal nonce has been selected for the delivery.
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
);
|
||||
}
|
||||
|
||||
/// Total cost of mesage delivery and confirmation.
|
||||
struct MessagesDeliveryCost<SourceChainBalance> {
|
||||
/// Cost of message delivery transaction.
|
||||
pub delivery_transaction_cost: SourceChainBalance,
|
||||
/// Cost of confirmation delivery transaction.
|
||||
pub confirmation_transaction_cost: SourceChainBalance,
|
||||
}
|
||||
|
||||
/// Reference data for participating in relay
|
||||
pub struct RelayReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Current block reward summary
|
||||
pub selected_reward: P::SourceChainBalance,
|
||||
/// Current block cost summary
|
||||
pub selected_cost: P::SourceChainBalance,
|
||||
/// Messages size summary
|
||||
pub selected_size: u32,
|
||||
|
||||
/// Current block reward summary
|
||||
pub total_reward: P::SourceChainBalance,
|
||||
/// All confirmations cost
|
||||
pub total_confirmations_cost: P::SourceChainBalance,
|
||||
/// Current block cost summary
|
||||
pub total_cost: P::SourceChainBalance,
|
||||
|
||||
/// Hard check begin nonce
|
||||
pub hard_selected_begin_nonce: MessageNonce,
|
||||
/// Count prepaid nonces
|
||||
pub selected_prepaid_nonces: MessageNonce,
|
||||
/// Unpaid nonces weight summary
|
||||
pub selected_unpaid_weight: Weight,
|
||||
|
||||
/// Index by all ready nonces
|
||||
pub index: usize,
|
||||
/// Current nonce
|
||||
pub nonce: MessageNonce,
|
||||
/// Current nonce details
|
||||
pub details: MessageDetails<P::SourceChainBalance>,
|
||||
}
|
||||
|
||||
impl<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> RelayReference<P, SourceClient, TargetClient>
|
||||
{
|
||||
/// Returns whether the current `RelayReference` is profitable.
|
||||
pub fn is_profitable(&self) -> bool {
|
||||
self.total_reward >= self.total_cost
|
||||
}
|
||||
|
||||
async fn estimate_messages_delivery_cost(
|
||||
&self,
|
||||
) -> Result<MessagesDeliveryCost<P::SourceChainBalance>, TargetClient::Error> {
|
||||
// technically, multiple confirmations will be delivered in a single transaction,
|
||||
// meaning less loses for relayer. But here we don't know the final relayer yet, so
|
||||
// we're adding a separate transaction for every message. Normally, this cost is covered
|
||||
// by the message sender. Probably reconsider this?
|
||||
let confirmation_transaction_cost =
|
||||
self.lane_source_client.estimate_confirmation_transaction().await;
|
||||
|
||||
let delivery_transaction_cost = self
|
||||
.lane_target_client
|
||||
.estimate_delivery_transaction_in_source_tokens(
|
||||
self.hard_selected_begin_nonce..=
|
||||
(self.hard_selected_begin_nonce + self.index as MessageNonce),
|
||||
self.selected_prepaid_nonces,
|
||||
self.selected_unpaid_weight,
|
||||
self.selected_size,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost })
|
||||
}
|
||||
|
||||
async fn update_cost_and_reward(&mut self) -> Result<(), TargetClient::Error> {
|
||||
let prev_is_profitable = self.is_profitable();
|
||||
let prev_total_cost = self.total_cost;
|
||||
let prev_total_reward = self.total_reward;
|
||||
|
||||
let MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost } =
|
||||
self.estimate_messages_delivery_cost().await?;
|
||||
self.total_confirmations_cost =
|
||||
self.total_confirmations_cost.saturating_add(confirmation_transaction_cost);
|
||||
self.total_reward = self.total_reward.saturating_add(self.details.reward);
|
||||
self.total_cost = self.total_confirmations_cost.saturating_add(delivery_transaction_cost);
|
||||
|
||||
if prev_is_profitable && !self.is_profitable() {
|
||||
// if it is the first message that makes reward less than cost, let's log it
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it larger than \
|
||||
total reward {:?}->{:?}",
|
||||
self.nonce,
|
||||
self.details.reward,
|
||||
prev_total_cost,
|
||||
self.total_cost,
|
||||
prev_total_reward,
|
||||
self.total_reward,
|
||||
);
|
||||
} else if !prev_is_profitable && self.is_profitable() {
|
||||
// if this message makes batch profitable again, let's log it
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it less than or \
|
||||
equal to the total reward {:?}->{:?} (again)",
|
||||
self.nonce,
|
||||
self.details.reward,
|
||||
prev_total_cost,
|
||||
self.total_cost,
|
||||
prev_total_reward,
|
||||
self.total_reward,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Relay reference data
|
||||
pub struct RelayMessagesBatchReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// Maximal number of relayed messages in single delivery transaction.
|
||||
pub max_messages_in_this_batch: MessageNonce,
|
||||
/// Maximal cumulative dispatch weight of relayed messages in single delivery transaction.
|
||||
pub max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal cumulative size of relayed messages in single delivery transaction.
|
||||
pub max_messages_size_in_single_batch: u32,
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Source queue.
|
||||
pub nonces_queue: SourceRangesQueue<
|
||||
P::SourceHeaderHash,
|
||||
P::SourceHeaderNumber,
|
||||
MessageDetailsMap<P::SourceChainBalance>,
|
||||
>,
|
||||
/// Source queue range
|
||||
pub nonces_queue_range: Range<usize>,
|
||||
}
|
||||
@@ -1,75 +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/>.
|
||||
|
||||
//! Rational relay strategy
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
SourceClient as MessageLaneSourceClient, TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
relay_strategy::{RelayReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// The relayer will deliver all messages and confirmations as long as he's not losing any
|
||||
/// funds.
|
||||
#[derive(Clone)]
|
||||
pub struct RationalStrategy;
|
||||
|
||||
#[async_trait]
|
||||
impl RelayStrategy for RationalStrategy {
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool {
|
||||
if let Err(e) = reference.update_cost_and_reward().await {
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Failed to update transaction cost and reward: {:?}. No nonces selected for delivery",
|
||||
e,
|
||||
);
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Rational relayer never wants to lose his funds.
|
||||
if reference.is_profitable() {
|
||||
reference.selected_reward = reference.total_reward;
|
||||
reference.selected_cost = reference.total_cost;
|
||||
return true
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
_reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
) {
|
||||
// rational relayer would never submit unprofitable transactions, so we don't need to do
|
||||
// anything here
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user