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

Encode extrinsic call. fix #505 #507

Merged
merged 9 commits into from
Mar 6, 2024
Merged

Encode extrinsic call. fix #505 #507

merged 9 commits into from
Mar 6, 2024

Conversation

imstar15
Copy link
Member

@imstar15 imstar15 commented Feb 27, 2024

Update the TaskScheduled event by incorporating the encodedCall and excluding it from the TaskTriggered event.

  1. Use the call parameter of scheduleDynamicDispatch as encodedCall.

  2. Use the entire extrinsic of scheduleXcmpTask as encodedCall.

Tests:

Add schedule_xcmp_task_and_check_encoded_call_success test

Manual testing:

TaskTriggered event:

image

Decoded call:

image

@imstar15 imstar15 changed the title [WIP]Encode extrinsic call [WIP]Encode extrinsic call. fix #505 Feb 27, 2024
@imstar15 imstar15 changed the title [WIP]Encode extrinsic call. fix #505 Encode extrinsic call. fix #505 Mar 1, 2024
)?;

// Tranform the call into a runtime call and encode it.
let call: <T as crate::Config>::RuntimeCall = Call::schedule_xcmp_task {
Copy link
Member Author

Choose a reason for hiding this comment

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

Tranform the call into a runtime call and encode it.

_ => None,
};

Self::deposit_event(Event::<T>::TaskScheduled { who: owner_id, task_id, schedule_as });
Copy link
Member Author

@imstar15 imstar15 Mar 1, 2024

Choose a reason for hiding this comment

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

Move TaskScheduled event out.

/// Validate and schedule task.
/// This will also charge the execution fee.
pub fn validate_and_schedule_task(
action: ActionOf<T>,
owner_id: AccountOf<T>,
schedule: Schedule,
abort_errors: Vec<Vec<u8>>,
) -> DispatchResult {
) -> Result<TaskIdV2, DispatchError> {
Copy link
Member Author

@imstar15 imstar15 Mar 1, 2024

Choose a reason for hiding this comment

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

Return TaskIdV2 or DispatchError.


let schedule = schedule.validated_into::<T>()?;
Self::deposit_event(Event::<T>::TaskScheduled {
Copy link
Member Author

@imstar15 imstar15 Mar 1, 2024

Choose a reason for hiding this comment

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

Deposit TaskScheduled event.

Copy link
Member

Choose a reason for hiding this comment

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

Before this change validate_and_schedule_task does 2 things:

  • write the task into storage
  • generate the event

so the caller just need to call it, and never have to worry about manually make the the TaskSchedule event manually. But after this change, we have to remember to also call generate TaskSchedule event whenever we call validate_and_schedule_task

I had a feeling we will eventually make a mistake and forgot the second call deposit_event.

I think we should find a way to just need to write one task schedule function and it handle both for us.

maybe create a new helper function for that? and validate_and_schedule_task can be make private.

open to idea but i think it's very useful to just call that function and it does all the setup.

on thsi new approach you can see that we have to add the extra TaskSchedule everywhere after that.

Copy link
Member Author

@imstar15 imstar15 Mar 5, 2024

Choose a reason for hiding this comment

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

If we need to throw an event in the validate_and_schedule_task function, we should pass the pre-constructed encoded_call into the validate_and_schedule_task function.

Because the encoded_call for schedule_xcmp_task needs to be constructed using the original function parameters and cannot be built within the validate_and_schedule_task function by using the action parameter passed to it.

That's why I opted to split Self::deposit_event(Event::<T>::TaskScheduled { ... }) out this function.

Hi @chrisli30 , what are your thoughts on this?

Copy link
Member

Choose a reason for hiding this comment

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

yes, I understand it.

What I mean is the reason the previous dev wrote it that way is to ensure we don't forgot.

Now with this approach, everytime we want to schedule a task, we will need to always make 2 call:

  1. validated_and_schedule_task
  2. deposit_event(TaskSchedule)

CleanShot 2024-03-04 at 21 34 59

Therefore I think it make sense to introduce a new helper function that does:

  1. take the right input
  2. call validated_and_schedule_task
  3. call deposit_event(TaskSchedule)

Make it work in a way where we cannot make mistake.

Copy link
Member Author

@imstar15 imstar15 Mar 5, 2024

Choose a reason for hiding this comment

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

I wrote the helper function called schedule_task_with_event. What are your thoughts on it? @v9n

Pseudocode:

pub fn schedule_task_with_event(
	action: ActionOf<T>,
	owner_id: AccountOf<T>,
	schedule: Schedule,
	abort_errors: Vec<Vec<u8>>,
	encoded_call: Option<Vec<u8>>,
) -> DispatchResult {
	// Schedule the task.
	let task_id: TaskIdV2 = Self::validate_and_schedule_task(
		action.clone(),
		who.clone(),
		schedule_value,
		vec![],
	)?;

	Self::deposit_event(Event::<T>::TaskScheduled {
		who,
		task_id,
		schedule_as,
		encoded_call: Some(encoded_call),
	});

	Ok(())
}

Copy link
Member

Choose a reason for hiding this comment

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

Looks good.

I would call it just schedule_task though. But leave that to your to decide.

One last request can you make validate_and_schedule_task to not public, we don't want anyone to call it directly. (inside they can still call it obviously) and instead everyone will just call schedule_task moving forward and this function will handle all the setup.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay!
However, the name "schedule_task" has already been used.

@@ -1034,6 +1035,62 @@ fn schedule_xcmp_works() {
})
}

#[test]
fn schedule_xcmp_task_and_check_encoded_call_success() {
Copy link
Member Author

@imstar15 imstar15 Mar 1, 2024

Choose a reason for hiding this comment

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

Add schedule_xcmp_task_and_check_encoded_call_success test.

@imstar15 imstar15 marked this pull request as ready for review March 1, 2024 15:54
+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
+ GetDispatchInfo
+ From<frame_system::Call<Self>>
+ IsSubType<Call<Self>>
+ IsType<<Self as frame_system::Config>::RuntimeCall>;
+ IsType<<Self as frame_system::Config>::RuntimeCall>
+ From<crate::Call<Self>>;
Copy link
Member Author

@imstar15 imstar15 Mar 2, 2024

Choose a reason for hiding this comment

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

Specify that RuntimeCall must implement the From<crate::Call<Self>> trait, enabling the conversion of Pallet::Call to RuntimeCall.

@imstar15 imstar15 requested review from v9n and chrisli30 March 4, 2024 01:00
Copy link
Member

@chrisli30 chrisli30 left a comment

Choose a reason for hiding this comment

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

The screenshot of the encoded call looks legit. I have left one comment. @v9n , could you double check the code?

pallets/automation-time/src/lib.rs Show resolved Hide resolved
@imstar15
Copy link
Member Author

imstar15 commented Mar 4, 2024

What is the reason of this type re-definition?

In Substrate version 0.9.38, the definition of Call within the Pallet configuration has been renamed to RuntimeCall to distinguish between PalletCall and RuntimeCall.

Related discussion:
paritytech/substrate#11736 (comment)

PR:
paritytech/substrate#11981

@@ -217,18 +217,18 @@ benchmarks! {
let schedule = ScheduleParam::Fixed { execution_times: times };

let caller: T::AccountId = account("caller", 0, SEED);
let call: <T as Config>::Call = frame_system::Call::remark { remark: vec![] }.into();
let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
Copy link
Member

Choose a reason for hiding this comment

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

can you see if we need .into(). I think Rust might be able to auto call this already (I saw similar suggestion by Clippy a while ago).

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried removing into() but encountered some errors.

error[E0308]: mismatched types
   --> pallets/automation-time/src/benchmarking.rs:220:42
    |
220 |         let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: vec![] };
    |                   --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `Call<_>`
    |                   |
    |                   expected due to this
    |
    = note: expected associated type `<T as pallet::Config>::RuntimeCall`
                          found enum `frame_system::Call<_>`
    = help: consider constraining the associated type `<T as pallet::Config>::RuntimeCall` to `frame_system::Call<_>` or calling a method that returns `<T as pallet::Config>::RuntimeCall`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: call `Into::into` on this expression to convert `frame_system::Call<_>` into `<T as pallet::Config>::RuntimeCall`
    |
220 |         let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
    |                                                                                             +++++++

For more information about this error, try `rustc --explain E0308`.
error: could not compile `pallet-automation-time` (lib) due to previous error

What do you think the correct way to write it should be?

Copy link
Member

Choose a reason for hiding this comment

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

That's fine. I was just asking.

Because I saw before in a similar PR https://github.com/OAK-Foundation/OAK-blockchain/pull/421/files this tool remove all the .into() so that's why I was just asking.

If Rust cannot infer it for this case we will need to explicitly call it. no problem.

Self::deposit_event(Event::<T>::TaskScheduled {
who,
task_id,
schedule_as: Self::get_schedule_as_from_action(action),
Copy link
Member

Choose a reason for hiding this comment

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

why do we need to call get_schedule_as_from_action ? shouldn't we just access schedule_as variable on line 461 directly?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, You're right. 👍
Fixed!

Copy link
Member

@v9n v9n left a comment

Choose a reason for hiding this comment

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

I think the code can be improved. it's a bit repetivei and there is something I'm not clear.

@imstar15 imstar15 requested review from chrisli30 and v9n March 5, 2024 05:36
Copy link
Member

@v9n v9n left a comment

Choose a reason for hiding this comment

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

lgtm

@imstar15 imstar15 merged commit ee601bb into master Mar 6, 2024
3 checks passed
@imstar15 imstar15 deleted the task-encoded-call branch April 26, 2024 11:49
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.

3 participants