-
Notifications
You must be signed in to change notification settings - Fork 108
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
Arbitrary call from Polkadot to Ethereum contract #924
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #924 +/- ##
==========================================
- Coverage 74.42% 73.99% -0.44%
==========================================
Files 41 41
Lines 1834 1915 +81
Branches 74 79 +5
==========================================
+ Hits 1365 1417 +52
- Misses 449 475 +26
- Partials 20 23 +3
Flags with carried forward coverage won't be shown. Click here to find out more.
☔ View full report in Codecov by Sentry. |
9339348
to
c9ce72b
Compare
@yrong I have added a new extrinsic in the template parachain. To use the BridgeXcmSender, I need to add a bunch of config from the |
Yes, actually it's not required. But since you've done some integration already so I just did some fix in faccaee based on current implementation. For the smoke test
Log in bridgehub shows it reach
The fee part is not correctly handled yet but agree as you mentioned we can focus on the basic flow as first step. |
0104666
to
7d07acf
Compare
Ok(execution_fee) | ||
} | ||
|
||
fn is_transact(&self) -> bool { | ||
for instruction in self.iter.clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of cloning the iterator, it might make sense to use Peekable iterator. This will allow peeking of the next instruction without advancing the iterator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand Peekable
, it only looks one message ahead, and to move the cursor you have to call iter.next(). I am looking for message Transact
, and at this point the next message is DescendOrigin
(if that is even correct).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I wrote this conversion code in recursive descendant parser style. Basically, you should only need to peek one instruction to decide which branch to go down.
The two branches here are whether to do a transact or a token unlock. So how I would use peek would be instead of this code, I would use the following psuedo code:
let result = match iter.peek() {
DescendOrigin => transact_message(), // This must be a transact because we peeked DescendOrigin
WithdrawAsset => native_tokens_unlock_message(), // This must be a token unlock because we peeked WithdrawAsset
ReserveAssetDeposited => polkadot_token_burn_message(), // This doesnt exist yet, but will once we support polkadot assets
_ => return Error::UnexpectedInstruction, // The peeked instruction is unknown so we fail because we didnt expect the instruction
}
Then inside transact_message()
you would consume whatever you need from DescendOrigin
, then advance the iterator, and then match Transact
. If you cant match transact at this point you fail with Error::UnexpectedInstruction
. But in this case you know that your expecting transact so a better error name to use would be Error::TransactExpected
.
log::trace!(target: "xcm::ethereum_blob_exporter", "before transact."); | ||
|
||
let data = if let Transact { | ||
origin_kind: _origin_kind, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to assert origin_kind is OriginKind::SovereignAccount
because execution on an agent is the same as executing using a sovereign account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 6b3b09d.
|
||
let inner_message = Box::new(Xcm(vec![ | ||
Instruction::UnpaidExecution { weight_limit: Unlimited, check_origin: None },// TODO update to paid | ||
Instruction::DescendOrigin(contract_location), // TODO not sure if this is right, want to pass the contract address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alistair-singh the Transact
instruction doesn't have a field to specify the contract to be executed on Ethereum. Is DescendOrigin
an OK way to send across the address of the arbitrary contract to be executed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not need to use DescendOrigin
and SetTopic
here. The Xcm we should send and match should simply be:
UnpaidExecution { ... }
Transact { ... }
The contract address needs to be passed call
field using (address, function_selector, params)
. You already have (function_selector, params)
implemented so just prepend the target contract address.
2577727
to
22c8d69
Compare
@claravanstaden For the issue you mentioned yesterday I just made a fix in 5db9786 and the smoke test shows e2e flow work as expected. |
…hains' into clara/transact-on-polkadot-parachains
|
||
let inner_message = Box::new(Xcm(vec![ | ||
Instruction::UnpaidExecution { weight_limit: Unlimited, check_origin: None },// TODO update to paid | ||
Instruction::DescendOrigin(contract_location), // TODO not sure if this is right, want to pass the contract address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not need to use DescendOrigin
and SetTopic
here. The Xcm we should send and match should simply be:
UnpaidExecution { ... }
Transact { ... }
The contract address needs to be passed call
field using (address, function_selector, params)
. You already have (function_selector, params)
implemented so just prepend the target contract address.
}); | ||
|
||
let inner_message = Box::new(Xcm(vec![ // TODO send the Ethereum gas fee here too | ||
Instruction::UnpaidExecution { weight_limit: Unlimited, check_origin: None },// TODO update to paid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This UnpaidExecution
is for buying execution on the destination chain i.e. Ethereum. We do not support buying of execution on Ethereum so we use the unpaid execution right now. Execution is paid for currently by the channels agent who rewards the relayer for relaying the message.
We could potentially buy execution on the target by matching the below xcm:
WithdrawAsset (ETH, 1000)
BuyExecution (ETH)
The code already can match this, however, we assert the execution is unpaid currently.
Ok(execution_fee) | ||
} | ||
|
||
fn is_transact(&self) -> bool { | ||
for instruction in self.iter.clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I wrote this conversion code in recursive descendant parser style. Basically, you should only need to peek one instruction to decide which branch to go down.
The two branches here are whether to do a transact or a token unlock. So how I would use peek would be instead of this code, I would use the following psuedo code:
let result = match iter.peek() {
DescendOrigin => transact_message(), // This must be a transact because we peeked DescendOrigin
WithdrawAsset => native_tokens_unlock_message(), // This must be a token unlock because we peeked WithdrawAsset
ReserveAssetDeposited => polkadot_token_burn_message(), // This doesnt exist yet, but will once we support polkadot assets
_ => return Error::UnexpectedInstruction, // The peeked instruction is unknown so we fail because we didnt expect the instruction
}
Then inside transact_message()
you would consume whatever you need from DescendOrigin
, then advance the iterator, and then match Transact
. If you cant match transact at this point you fail with Error::UnexpectedInstruction
. But in this case you know that your expecting transact so a better error name to use would be Error::TransactExpected
.
Closing, will be re-done in SNO-866. |
Cumulus companion: Snowfork/cumulus#57