mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-21 08:35:40 +00:00
Changed delivery and dispatch fee computation methods (#795)
* removed weight <-> fee mess * updated documentation Co-authored-by: Hernando Castano <castano.ha@gmail.com>
This commit is contained in:
committed by
Bastian Köcher
parent
f7c3bd4e08
commit
324e083cba
@@ -33,17 +33,63 @@ message lane module into your runtime. Basic prerequisites of these helpers are:
|
||||
|
||||
## `MessageBridge` Trait
|
||||
|
||||
The essence of your integration will be a struct that implements a `MessageBridge` trait. Let's
|
||||
review every method and give some implementation hints here:
|
||||
The essence of your integration will be a struct that implements a `MessageBridge` trait. It has
|
||||
single method (`MessageBridge::bridged_balance_to_this_balance`), used to convert from bridged chain
|
||||
tokens into this chain tokens. The bridge also requires two associated types to be specified -
|
||||
`ThisChain` and `BridgedChain`.
|
||||
|
||||
- `MessageBridge::maximal_extrinsic_size_on_target_chain`: you will need to return the maximal
|
||||
extrinsic size of the target chain from this function. This may be the constant that is updated
|
||||
when your runtime is upgraded, or you may use the
|
||||
[message lane parameters functionality](../../modules/message-lane/README.md#Non-Essential-Functionality)
|
||||
to allow the pallet owner to update this value more frequently (you may also want to use this
|
||||
functionality for all constants that are used in other methods described below).
|
||||
Worth to say that if you're going to use hardcoded constant (conversion rate) in the
|
||||
`MessageBridge::bridged_balance_to_this_balance` method (or in any other method of
|
||||
`ThisChainWithMessageLanes` or `BridgedChainWithMessageLanes` traits), then you should take a
|
||||
look at the
|
||||
[message lane parameters functionality](../../modules/message-lane/README.md#Non-Essential-Functionality).
|
||||
They allow pallet owner to update constants more frequently than runtime upgrade happens.
|
||||
|
||||
- `MessageBridge::weight_limits_of_message_on_bridged_chain`: you'll need to return a range of
|
||||
## `ChainWithMessageLanes` Trait
|
||||
|
||||
The trait is quite simple and can easily be implemented - you just need to specify types used at the
|
||||
corresponding chain. There is single exception, though (it may be changed in the future):
|
||||
|
||||
- `ChainWithMessageLanes::MessageLaneInstance`: this is used to compute runtime storage keys. There
|
||||
may be several instances of message lane pallet, included in the Runtime. Every instance stores
|
||||
messages and these messages stored under different keys. When we are verifying storage proofs from
|
||||
the bridged chain, we should know which instance we're talking to. This is fine, but there's
|
||||
significant inconvenience with that - this chain runtime must have the same message lane pallet
|
||||
instance. This does not necessarily mean that we should use the same instance on both chains -
|
||||
this instance may be used to bridge with another chain/instance, or may not be used at all.
|
||||
|
||||
## `ThisChainWithMessageLanes` Trait
|
||||
|
||||
This trait represents this chain from bridge point of view. Let's review every method of this trait:
|
||||
|
||||
- `ThisChainWithMessageLanes::is_outbound_lane_enabled`: is used to check whether given lane accepts
|
||||
outbound messages.
|
||||
|
||||
- `ThisChainWithMessageLanes::maximal_pending_messages_at_outbound_lane`: you should return maximal
|
||||
number of pending (undelivered) messages from this function. Returning small values would require
|
||||
relayers to operate faster and could make message sending logic more complicated. On the other
|
||||
hand, returning large values could lead to chain state growth.
|
||||
|
||||
- `ThisChainWithMessageLanes::estimate_delivery_confirmation_transaction`: you'll need to return
|
||||
estimated size and dispatch weight of the delivery confirmation transaction (that happens on
|
||||
this chain) from this function.
|
||||
|
||||
- `ThisChainWithMessageLanes::transaction_payment`: you'll need to return fee that the submitter
|
||||
must pay for given transaction on this chain. Normally, you would use transaction payment pallet
|
||||
for this. However, if your chain has non-zero fee multiplier set, this would mean that the
|
||||
payment will be computed using current value of this multiplier. But since this transaction
|
||||
will be submitted in the future, you may want to choose other value instead. Otherwise,
|
||||
non-altruistic relayer may choose not to submit this transaction until number of transactions
|
||||
will decrease.
|
||||
|
||||
## `BridgedChainWithMessageLanes` Trait
|
||||
|
||||
This trait represents this chain from bridge point of view. Let's review every method of this trait:
|
||||
|
||||
- `BridgedChainWithMessageLanes::maximal_extrinsic_size`: you will need to return the maximal
|
||||
extrinsic size of the target chain from this function.
|
||||
|
||||
- `MessageBridge::message_weight_limits`: you'll need to return a range of
|
||||
dispatch weights that the outbound message may take at the target chain. Please keep in mind that
|
||||
our helpers assume that the message is an encoded call of the target chain. But we never decode
|
||||
this call at the source chain. So you can't simply get dispatch weight from pre-dispatch
|
||||
@@ -55,66 +101,13 @@ review every method and give some implementation hints here:
|
||||
maximal weight of extrinsic at the target chain. In our test chains, we reject all messages that
|
||||
have declared dispatch weight larger than 50% of the maximal bridged extrinsic weight.
|
||||
|
||||
- `MessageBridge::weight_of_delivery_transaction`: you will need to return the maximal weight of the
|
||||
delivery transaction that delivers a given message to the target chain. There are three main
|
||||
things to notice:
|
||||
- `MessageBridge::estimate_delivery_transaction`: you will need to return estimated dispatch weight and
|
||||
size of the delivery transaction that delivers a given message to the target chain.
|
||||
|
||||
1. weight, returned from this function is then used to compute the fee that the
|
||||
message sender needs to pay for the delivery transaction. So it shall not be a simple dispatch
|
||||
weight of delivery call - it should be the "weight" of the transaction itself, including per-byte
|
||||
"weight", "weight" of signed extras and etc.
|
||||
1. the delivery transaction brings storage proof of
|
||||
the message, not the message itself. So your transaction will include extra bytes. We suggest
|
||||
computing the size of single empty value storage proof at the source chain, increase this value a
|
||||
bit and hardcode it in the source chain runtime code. This size then must be added to the size of
|
||||
payload and included in the weight computation;
|
||||
1. before implementing this function, please take
|
||||
a look at the
|
||||
[weight formula of delivery transaction](../../modules/message-lane/README.md#Weight-of-receive_messages_proof-call).
|
||||
It adds some extra weight for every additional byte of the proof (everything above
|
||||
`pallet_message_lane::EXPECTED_DEFAULT_MESSAGE_LENGTH`), so it's not trivial. Even better, please
|
||||
refer to [our implementation](../millau/runtime/src/rialto_messages.rs) for test chains for
|
||||
details.
|
||||
|
||||
- `MessageBridge::weight_of_delivery_confirmation_transaction_on_this_chain`: you'll need to return
|
||||
the maximal weight of a single message delivery confirmation transaction on this chain. All points
|
||||
from the previous paragraph are also relevant here.
|
||||
|
||||
- `MessageBridge::this_weight_to_this_balance`: this function needs to convert weight units into fee
|
||||
units on this chain. Most probably this can be done by calling
|
||||
`pallet_transaction_payment::Config::WeightToFee::calc()` for passed weight.
|
||||
|
||||
- `MessageBridge::bridged_weight_to_bridged_balance`: this function needs to convert weight units
|
||||
into fee units on the target chain. The best case is when you have the same conversion formula on
|
||||
both chains - then you may just call the same formula from the previous paragraph. Otherwise,
|
||||
you'll need to hardcode this formula into your runtime.
|
||||
|
||||
- `MessageBridge::bridged_balance_to_this_balance`: this may be the easiest method to implement and
|
||||
the hardest to maintain at the same time. If you don't have any automatic methods to determine
|
||||
conversion rate, then you'll probably need to maintain it by yourself (by updating conversion
|
||||
rate, stored in runtime storage). This means that if you're too late with an update, then you risk
|
||||
to accept messages with lower-than-expected fee. So it may be wise to have some reserve in this
|
||||
conversion rate, even if that means larger delivery and dispatch fees.
|
||||
|
||||
## `ChainWithMessageLanes` Trait
|
||||
|
||||
Apart from its methods, `MessageBridge` also has two associated types that are implementing the
|
||||
`ChainWithMessageLanes` trait. One is for this chain and the other is for the bridged chain. The
|
||||
trait is quite simple and can easily be implemented - you just need to specify types used at the
|
||||
corresponding chain. There are two exceptions, though. Both may be changed in the future. Here they
|
||||
are:
|
||||
|
||||
- `ChainWithMessageLanes::Call`: it isn't a good idea to reference bridged chain runtime from your
|
||||
runtime (cyclic references + maintaining on upgrades). So you can't know the type of bridged chain
|
||||
call in your runtime. This type isn't actually used at this chain, so you may use `()` instead.
|
||||
|
||||
- `ChainWithMessageLanes::MessageLaneInstance`: this is used to compute runtime storage keys. There
|
||||
may be several instances of message lane pallet, included in the Runtime. Every instance stores
|
||||
messages and these messages stored under different keys. When we are verifying storage proofs from
|
||||
the bridged chain, we should know which instance we're talking to. This is fine, but there's
|
||||
significant inconvenience with that - this chain runtime must have the same message lane pallet
|
||||
instance. This does not necessarily mean that we should use the same instance on both chains -
|
||||
this instance may be used to bridge with another chain/instance, or may not be used at all.
|
||||
- `MessageBridge::transaction_payment`: you'll need to return fee that the submitter
|
||||
must pay for given transaction on bridged chain. The best case is when you have the same conversion
|
||||
formula on both chains - then you may just reuse the `ThisChainWithMessageLanes::transaction_payment`
|
||||
implementation. Otherwise, you'll need to hardcode this formula into your runtime.
|
||||
|
||||
## Helpers for the Source Chain
|
||||
|
||||
|
||||
Reference in New Issue
Block a user