Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outbound queue v2 #4

Open
wants to merge 8 commits into
base: xcm-v5
Choose a base branch
from
Open

Outbound queue v2 #4

wants to merge 8 commits into from

Conversation

yrong
Copy link
Owner

@yrong yrong commented Oct 18, 2024

Resolves: https://linear.app/snowfork/issue/SNO-1205

@yrong
Copy link
Owner Author

yrong commented Oct 21, 2024

Workflow

  1. on AH we add a custom exporter returns a lower fee(without the cost on Ethereum) charged from the user when exporting to Ethereum, essentially predict the route by content of XCM, more details in Predicate route table by Xcm paritytech/polkadot-sdk#6074, since there is no XCMV5 branch ready for tests yet, as a workaround we can execute raw xcm with some custom instruction on AH to differ V2 with V1.

  2. on BH we route the new XCM(with V2 specific instructions) to the new pallet OutboundQueueV2, in which we convert the XCM to Message structure as following:

pub struct Message {
    /// Origin
    pub origin: H256,
    /// ID
    pub id: H256,
    /// Fee
    pub fee: u128,
    /// Commands
    pub commands: BoundedVec<Command, ConstU32<5>>,
}

which means we can execute multiple commands on Ethereum in one message.

  1. Then we abi encode the message and store it into a merkle tree as before, meanwhile add the pending fee into LockedFee storage and increase the nonce. more detais here

  2. add a new extrinsic submit_delivery_proof in which we verify the event log is truely happened on Ethereum side, and add the fee to RewardLeger.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey I'd prefer to move the crate to primitives/merkle-tree rather than adding more code to core. In fact I think the core crate has too much code and potentially needs be split up further.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't just add V2 code and leave v1 code as is. The two versions need to co-exist in a coherent and neatly ordered manner.

I think we should move to this layout:

* core/src/outbound/v1/mod.rs
* core/src/outbound/v2/mod.rs

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -172,3 +174,13 @@ impl Default for AssetMetadata {

/// Maximum length of a string field in ERC20 token metada
const METADATA_FIELD_MAX_LEN: u32 = 32;

// Origin for high-priority governance commands
pub fn primary_governance_origin() -> H256 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now a V1-only type, so should go in core/src/v1/mod.rs.

Copy link
Owner Author

@yrong yrong Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

850fe96
Actually it's V2 specific.

The usage in

if ticket.origin != primary_governance_origin() {
ensure!(!Self::operating_mode().is_halted(), SendError::Halted);
}
is to allow upgrading even when bridge is halted.

}

// Origin for lower-priority governance commands
pub fn second_governance_origin() -> H256 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub id: H256,
/// Commands to execute in Ethereum
pub commands: BoundedVec<CommandWrapper, ConstU32<5>>,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably limit to 8 (I like constants being a factor of 2). And we should probably use a constant.

Suggested change
pub commands: BoundedVec<CommandWrapper, ConstU32<5>>,
pub commands: BoundedVec<CommandWrapper, ConstU32<MAX_COMMANDS>>,

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token::Tuple(vec![
Token::FixedBytes(Vec::from(x.channel_id.as_ref())),
let header = vec![
Token::FixedBytes(x.origin.as_bytes().to_owned()),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the the sol! macro to auto-generate encoders for InboundMessage? Its from this library which is already used by outbound queue: https://alloy.rs/

Token::FixedBytes is from the older ethabi-decode crate which we should stop using and migrate to alloy crates.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mode: OperatingMode,
},
/// Transfer ether from an agent contract to a recipient account
TransferNativeFromAgent {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command doesn't exist anymore, I believe

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

/// ABI-encode the Command.
pub fn abi_encode(&self) -> Vec<u8> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the sol! macro from the alloy-rs crates to generate the encoders automatically? We should deprecate use of ethabi::encode, as its an unmaintained library.

See example from https://github.com/paritytech/polkadot-sdk/blob/aeebf2f383390f2f86527d70212162d5dbea8b93/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs#L11

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// The base transaction cost, which includes:
// 21_000 transaction cost, roughly worst case 64_000 for calldata, and 100_000
// for message verification
const MAXIMUM_BASE_GAS: u64 = 185_000;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't be needed in V2.

Copy link
Owner Author

@yrong yrong Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yrong yrong changed the base branch from v2 to master October 24, 2024 16:55
@yrong yrong changed the base branch from master to xcm-v5 October 29, 2024 02:03
@yrong
Copy link
Owner Author

yrong commented Oct 29, 2024

Check details in emulated tests how to construct transfer message for both ENA&PNA with XCMV5 instructions.

cargo test -p bridge-hub-westend-integration-tests --lib tests::snowbridge_v2  -- --nocapture

@yrong yrong marked this pull request as ready for review October 29, 2024 12:44
BoundedVec::try_from(ticket.encode()).map_err(|_| SendError::MessageTooLarge)?;

T::MessageQueue::enqueue_message(message.as_bounded_slice(), origin);
Self::deposit_event(Event::MessageQueued { message: ticket.clone() });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't sufficient for dry-running, because the message at this stage in the processing pipeline isn't the same that is forwarded to the Ethereum gateway. Its missing information such as the gas limit. Without knowing the gas limits, we can't dry run properly on Ethereum.

In other words, we need the dry-run API to output the final message, the SCALE-encoded equivalent of this type: https://github.com/Snowfork/snowbridge/blob/fa9b8a7b3551cc9df8ee3239dc2830be5d84728e/contracts/src/v2/Types.sol#L8

This makes it much more easy for the UX to dry-run the resulting message on Ethereum.

We can ignore the message nonce for dry-run purposes on Ethereum.

So I you think you should explore adding a custom runtime API that takes the ExportMessage XCM, converts it to the final ethereum command.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meanwhile to remove the fee when validate ExportMessage so that we can decrease the delivery fee config on AH and make it as an user input.

More context in paritytech#4826 (comment)

@yrong yrong force-pushed the outbound-queue-v2 branch 2 times, most recently from 80dad67 to 74d23af Compare November 4, 2024 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants