Skip to content

Commit 0e9cca0

Browse files
committed
Rebase inbound queue
1 parent 4796240 commit 0e9cca0

7 files changed

Lines changed: 101 additions & 789 deletions

File tree

bridges/snowbridge/pallets/inbound-queue-v2/src/benchmarking/mod.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,6 @@ mod benchmarks {
2323
create_message.block_roots_root,
2424
);
2525

26-
let sovereign_account = sibling_sovereign_account::<T>(1000u32.into());
27-
28-
let minimum_balance = T::Token::minimum_balance();
29-
30-
// So that the receiving account exists
31-
assert_ok!(T::Token::mint_into(&caller, minimum_balance));
32-
// Fund the sovereign account (parachain sovereign account) so it can transfer a reward
33-
// fee to the caller account
34-
assert_ok!(T::Token::mint_into(
35-
&sovereign_account,
36-
3_000_000_000_000u128
37-
.try_into()
38-
.unwrap_or_else(|_| panic!("unable to cast sovereign account balance")),
39-
));
40-
4126
#[block]
4227
{
4328
assert_ok!(InboundQueue::<T>::submit(

bridges/snowbridge/pallets/inbound-queue-v2/src/envelope.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3-
use snowbridge_core::{inbound::Log, ChannelId};
3+
use snowbridge_core::inbound::Log;
44

5-
use sp_core::{RuntimeDebug, H160, H256};
5+
use sp_core::{RuntimeDebug, H160};
66
use sp_std::prelude::*;
77

88
use alloy_primitives::B256;
99
use alloy_sol_types::{sol, SolEvent};
1010

1111
sol! {
12-
event OutboundMessageAccepted(bytes32 indexed channel_id, uint64 nonce, bytes32 indexed message_id, bytes payload);
12+
event OutboundMessageAccepted(uint64 indexed nonce, uint128 fee, bytes payload);
1313
}
1414

1515
/// An inbound message that has had its outer envelope decoded.
1616
#[derive(Clone, RuntimeDebug)]
1717
pub struct Envelope {
1818
/// The address of the outbound queue on Ethereum that emitted this message as an event log
1919
pub gateway: H160,
20-
/// The message Channel
21-
pub channel_id: ChannelId,
2220
/// A nonce for enforcing replay protection and ordering.
2321
pub nonce: u64,
24-
/// An id for tracing the message on its route (has no role in bridge consensus)
25-
pub message_id: H256,
22+
/// Total fee paid in Ether on Ethereum, should cover all the cost
23+
pub fee: u128,
2624
/// The inner payload generated from the source application.
2725
pub payload: Vec<u8>,
2826
}
@@ -41,9 +39,8 @@ impl TryFrom<&Log> for Envelope {
4139

4240
Ok(Self {
4341
gateway: log.address,
44-
channel_id: ChannelId::from(event.channel_id.as_ref()),
4542
nonce: event.nonce,
46-
message_id: H256::from(event.message_id.as_ref()),
43+
fee: event.fee,
4744
payload: event.payload,
4845
})
4946
}

bridges/snowbridge/pallets/inbound-queue-v2/src/lib.rs

Lines changed: 41 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -38,49 +38,35 @@ mod test;
3838

3939
use codec::{Decode, DecodeAll, Encode};
4040
use envelope::Envelope;
41-
use frame_support::{
42-
traits::{
43-
fungible::{Inspect, Mutate},
44-
tokens::{Fortitude, Preservation},
45-
},
46-
weights::WeightToFee,
47-
PalletError,
48-
};
41+
use frame_support::PalletError;
4942
use frame_system::ensure_signed;
5043
use scale_info::TypeInfo;
5144
use sp_core::H160;
52-
use sp_runtime::traits::Zero;
5345
use sp_std::vec;
54-
use xcm::prelude::{
55-
send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash,
46+
use xcm::{
47+
prelude::{send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm},
48+
VersionedXcm, MAX_XCM_DECODE_DEPTH,
5649
};
57-
use xcm_executor::traits::TransactAsset;
5850

5951
use snowbridge_core::{
6052
inbound::{Message, VerificationError, Verifier},
61-
sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters,
62-
StaticLookup,
63-
};
64-
use snowbridge_router_primitives::inbound::v2::{
65-
ConvertMessage, ConvertMessageError, VersionedMessage,
53+
BasicOperatingMode,
6654
};
67-
use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError};
55+
use snowbridge_router_primitives::inbound::v2::Message as MessageV2;
6856

6957
pub use weights::WeightInfo;
7058

7159
#[cfg(feature = "runtime-benchmarks")]
7260
use snowbridge_beacon_primitives::BeaconHeader;
7361

74-
type BalanceOf<T> =
75-
<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
76-
7762
pub use pallet::*;
7863

79-
pub const LOG_TARGET: &str = "snowbridge-inbound-queue";
64+
pub const LOG_TARGET: &str = "snowbridge-inbound-queue:v2";
8065

8166
#[frame_support::pallet]
8267
pub mod pallet {
8368
use super::*;
69+
use codec::DecodeLimit;
8470

8571
use frame_support::pallet_prelude::*;
8672
use frame_system::pallet_prelude::*;
@@ -101,44 +87,17 @@ pub mod pallet {
10187
/// The verifier for inbound messages from Ethereum
10288
type Verifier: Verifier;
10389

104-
/// Message relayers are rewarded with this asset
105-
type Token: Mutate<Self::AccountId> + Inspect<Self::AccountId>;
106-
10790
/// XCM message sender
10891
type XcmSender: SendXcm;
10992

110-
// Address of the Gateway contract
93+
/// Address of the Gateway contract
11194
#[pallet::constant]
11295
type GatewayAddress: Get<H160>;
11396

114-
/// Convert inbound message to XCM
115-
type MessageConverter: ConvertMessage<
116-
AccountId = Self::AccountId,
117-
Balance = BalanceOf<Self>,
118-
>;
119-
120-
/// Lookup a channel descriptor
121-
type ChannelLookup: StaticLookup<Source = ChannelId, Target = Channel>;
122-
123-
/// Lookup pricing parameters
124-
type PricingParameters: Get<PricingParameters<BalanceOf<Self>>>;
125-
12697
type WeightInfo: WeightInfo;
12798

12899
#[cfg(feature = "runtime-benchmarks")]
129100
type Helper: BenchmarkHelper<Self>;
130-
131-
/// Convert a weight value into deductible balance type.
132-
type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
133-
134-
/// Convert a length value into deductible balance type
135-
type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
136-
137-
/// The upper limit here only used to estimate delivery cost
138-
type MaxMessageSize: Get<u32>;
139-
140-
/// To withdraw and deposit an asset.
141-
type AssetTransactor: TransactAsset;
142101
}
143102

144103
#[pallet::hooks]
@@ -149,14 +108,10 @@ pub mod pallet {
149108
pub enum Event<T: Config> {
150109
/// A message was received from Ethereum
151110
MessageReceived {
152-
/// The message channel
153-
channel_id: ChannelId,
154111
/// The message nonce
155112
nonce: u64,
156113
/// ID of the XCM message which was forwarded to the final destination parachain
157114
message_id: [u8; 32],
158-
/// Fee burned for the teleport
159-
fee_burned: BalanceOf<T>,
160115
},
161116
/// Set OperatingMode
162117
OperatingModeChanged { mode: BasicOperatingMode },
@@ -184,8 +139,6 @@ pub mod pallet {
184139
Verification(VerificationError),
185140
/// XCMP send failure
186141
Send(SendError),
187-
/// Message conversion error
188-
ConvertMessage(ConvertMessageError),
189142
}
190143

191144
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo, PalletError)]
@@ -215,9 +168,9 @@ pub mod pallet {
215168
}
216169
}
217170

218-
/// The current nonce for each channel
171+
/// The nonce of the message been processed or not
219172
#[pallet::storage]
220-
pub type Nonce<T: Config> = StorageMap<_, Twox64Concat, ChannelId, u64, ValueQuery>;
173+
pub type Nonce<T: Config> = StorageMap<_, Identity, u64, bool, ValueQuery>;
221174

222175
/// The current operating mode of the pallet.
223176
#[pallet::storage]
@@ -230,7 +183,7 @@ pub mod pallet {
230183
#[pallet::call_index(0)]
231184
#[pallet::weight(T::WeightInfo::submit())]
232185
pub fn submit(origin: OriginFor<T>, message: Message) -> DispatchResult {
233-
let who = ensure_signed(origin)?;
186+
let _who = ensure_signed(origin)?;
234187
ensure!(!Self::operating_mode().is_halted(), Error::<T>::Halted);
235188

236189
// submit message to verifier for verification
@@ -244,63 +197,46 @@ pub mod pallet {
244197
// Verify that the message was submitted from the known Gateway contract
245198
ensure!(T::GatewayAddress::get() == envelope.gateway, Error::<T>::InvalidGateway);
246199

247-
// Retrieve the registered channel for this message
248-
let channel =
249-
T::ChannelLookup::lookup(envelope.channel_id).ok_or(Error::<T>::InvalidChannel)?;
250-
251-
// Verify message nonce
252-
<Nonce<T>>::try_mutate(envelope.channel_id, |nonce| -> DispatchResult {
253-
if *nonce == u64::MAX {
254-
return Err(Error::<T>::MaxNonceReached.into())
255-
}
256-
if envelope.nonce != nonce.saturating_add(1) {
257-
Err(Error::<T>::InvalidNonce.into())
258-
} else {
259-
*nonce = nonce.saturating_add(1);
260-
Ok(())
261-
}
262-
})?;
263-
264-
// Reward relayer from the sovereign account of the destination parachain, only if funds
265-
// are available
266-
let sovereign_account = sibling_sovereign_account::<T>(channel.para_id);
267-
let delivery_cost = Self::calculate_delivery_cost(message.encode().len() as u32);
268-
let amount = T::Token::reducible_balance(
269-
&sovereign_account,
270-
Preservation::Preserve,
271-
Fortitude::Polite,
272-
)
273-
.min(delivery_cost);
274-
if !amount.is_zero() {
275-
T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?;
276-
}
200+
// Verify the message has not been processed
201+
ensure!(!<Nonce<T>>::contains_key(envelope.nonce), Error::<T>::InvalidNonce);
277202

278-
// Decode payload into `VersionedMessage`
279-
let message = VersionedMessage::decode_all(&mut envelope.payload.as_ref())
203+
// Decode payload into `MessageV2`
204+
let message = MessageV2::decode_all(&mut envelope.payload.as_ref())
280205
.map_err(|_| Error::<T>::InvalidPayload)?;
281206

282-
// Decode message into XCM
283-
let (xcm, fee) = Self::do_convert(envelope.message_id, message.clone())?;
207+
// Decode xcm
208+
let versioned_xcm = VersionedXcm::<()>::decode_with_depth_limit(
209+
MAX_XCM_DECODE_DEPTH,
210+
&mut message.xcm.as_ref(),
211+
)
212+
.map_err(|_| Error::<T>::InvalidPayload)?;
213+
let xcm: Xcm<()> = versioned_xcm.try_into().map_err(|_| <Error<T>>::InvalidPayload)?;
284214

285215
log::info!(
286216
target: LOG_TARGET,
287-
"💫 xcm decoded as {:?} with fee {:?}",
217+
"💫 xcm decoded as {:?}",
288218
xcm,
289-
fee
290219
);
291220

292-
// Burning fees for teleport
293-
Self::burn_fees(channel.para_id, fee)?;
221+
// Set nonce flag to true
222+
<Nonce<T>>::try_mutate(envelope.nonce, |done| -> DispatchResult {
223+
*done = true;
224+
Ok(())
225+
})?;
226+
227+
// Todo: Deposit fee(in Ether) to RewardLeger which should cover all of:
228+
// T::RewardLeger::deposit(who, envelope.fee.into())?;
229+
// a. The submit extrinsic cost on BH
230+
// b. The delivery cost to AH
231+
// c. The execution cost on AH
232+
// d. The execution cost on destination chain(if any)
233+
// e. The reward
294234

295-
// Attempt to send XCM to a dest parachain
296-
let message_id = Self::send_xcm(xcm, channel.para_id)?;
235+
// Attempt to forward XCM to AH
236+
let dest = Location::new(1, [Parachain(1000)]);
237+
let (message_id, _) = send_xcm::<T::XcmSender>(dest, xcm).map_err(Error::<T>::from)?;
297238

298-
Self::deposit_event(Event::MessageReceived {
299-
channel_id: envelope.channel_id,
300-
nonce: envelope.nonce,
301-
message_id,
302-
fee_burned: fee,
303-
});
239+
Self::deposit_event(Event::MessageReceived { nonce: envelope.nonce, message_id });
304240

305241
Ok(())
306242
}
@@ -318,61 +254,4 @@ pub mod pallet {
318254
Ok(())
319255
}
320256
}
321-
322-
impl<T: Config> Pallet<T> {
323-
pub fn do_convert(
324-
message_id: H256,
325-
message: VersionedMessage,
326-
) -> Result<(Xcm<()>, BalanceOf<T>), Error<T>> {
327-
let (xcm, fee) = T::MessageConverter::convert(message_id, message)
328-
.map_err(|e| Error::<T>::ConvertMessage(e))?;
329-
Ok((xcm, fee))
330-
}
331-
332-
pub fn send_xcm(xcm: Xcm<()>, dest: ParaId) -> Result<XcmHash, Error<T>> {
333-
let dest = Location::new(1, [Parachain(dest.into())]);
334-
let (xcm_hash, _) = send_xcm::<T::XcmSender>(dest, xcm).map_err(Error::<T>::from)?;
335-
Ok(xcm_hash)
336-
}
337-
338-
pub fn calculate_delivery_cost(length: u32) -> BalanceOf<T> {
339-
let weight_fee = T::WeightToFee::weight_to_fee(&T::WeightInfo::submit());
340-
let len_fee = T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0));
341-
weight_fee
342-
.saturating_add(len_fee)
343-
.saturating_add(T::PricingParameters::get().rewards.local)
344-
}
345-
346-
/// Burn the amount of the fee embedded into the XCM for teleports
347-
pub fn burn_fees(para_id: ParaId, fee: BalanceOf<T>) -> DispatchResult {
348-
let dummy_context =
349-
XcmContext { origin: None, message_id: Default::default(), topic: None };
350-
let dest = Location::new(1, [Parachain(para_id.into())]);
351-
let fees = (Location::parent(), fee.saturated_into::<u128>()).into();
352-
T::AssetTransactor::can_check_out(&dest, &fees, &dummy_context).map_err(|error| {
353-
log::error!(
354-
target: LOG_TARGET,
355-
"XCM asset check out failed with error {:?}", error
356-
);
357-
TokenError::FundsUnavailable
358-
})?;
359-
T::AssetTransactor::check_out(&dest, &fees, &dummy_context);
360-
T::AssetTransactor::withdraw_asset(&fees, &dest, None).map_err(|error| {
361-
log::error!(
362-
target: LOG_TARGET,
363-
"XCM asset withdraw failed with error {:?}", error
364-
);
365-
TokenError::FundsUnavailable
366-
})?;
367-
Ok(())
368-
}
369-
}
370-
371-
/// API for accessing the delivery cost of a message
372-
impl<T: Config> Get<BalanceOf<T>> for Pallet<T> {
373-
fn get() -> BalanceOf<T> {
374-
// Cost here based on MaxMessagePayloadSize(the worst case)
375-
Self::calculate_delivery_cost(T::MaxMessageSize::get())
376-
}
377-
}
378257
}

0 commit comments

Comments
 (0)