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

Feature: Pallet Engine (Add pallet - MVP) #43

Closed
wants to merge 71 commits into from
Closed

Feature: Pallet Engine (Add pallet - MVP) #43

wants to merge 71 commits into from

Conversation

weezy20
Copy link
Contributor

@weezy20 weezy20 commented Mar 8, 2024

Enable pop-cli to add pallets to any runtime.
pop add pallet template -r <runtime_path> or pop a p template -r <runtime_path>

sub0 Todos:

  • add pallet subsubcommand
  • add pallet-template to runtime (chainspec edits not required)
  • unit tests to check pallet-template
  • implement dependency injection (runtime / node)
  • unit tests for dependency injection
  • implement minimal support for FRAME (chainspec + runtime)

M1 Todos:

  • implement name conflict resolution strategy (Branch add-pallet needs to check for duplicated entries. #63)
  • conditional features for dependency
  • optional runtime path, implement store to cache results from previous invocations of pop new parachain to use as a runtime path
  • implement diff tool to monitor edits before committing

Milestone 2 :
Enable full FRAME pallet support

  • todo

Nice to haves:

  • Automatic runtime and node manifest path resolution, based on cache populated during pop new parachain
  • Interactive pallet-template customization on pop add pallet template

@weezy20 weezy20 marked this pull request as ready for review March 9, 2024 09:08
@AlexD10S
Copy link
Collaborator

AlexD10S commented Mar 9, 2024

Do you want me to review and merge now or when all sub0 TODO tasks are completed?

We should create a separate issue to track M1 and M2 tasks

Also suggest a change for the name of the PR to follow this conventions https://www.conventionalcommits.org/es/v1.0.0-beta.2/ A suggestion will be feat: pop add pallet

@weezy20
Copy link
Contributor Author

weezy20 commented Mar 9, 2024

@AlexD10S This should be ready for merging when a few more tasks out of sub0 is completed.

src/engines/pallet_engine/dependency.rs Show resolved Hide resolved
src/commands/add/mod.rs Outdated Show resolved Hide resolved
src/engines/pallet_engine/mod.rs Outdated Show resolved Hide resolved
src/engines/pallet_engine/mod.rs Outdated Show resolved Hide resolved
Comment on lines +115 to +119
// NodePalletDependency(dep) => te.inject_node(dep)?,
// ListBenchmarks(step) => pe.insert(step),
// ListBenchmarks(step) => pe.insert(step),
// ChainspecGenesisConfig(step) => pe.insert(step),
// ChainspecGenesisImport(step) => pe.insert(step),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Their implementation is required later.

src/engines/pallet_engine/template.rs Outdated Show resolved Hide resolved
src/engines/pallet_engine/template.rs Outdated Show resolved Hide resolved
@Daanvdplas
Copy link
Collaborator

Daanvdplas commented Mar 20, 2024

First thing I notice is that the pallet generated from pop new pallet isn't used for adding it. I can run pop add pallet template without it?

@weezy20
Copy link
Contributor Author

weezy20 commented Mar 20, 2024

First thing I notice is that the pallet generated from pop new pallet isn't used for adding it. I can run pop add pallet template without it?

Correct. The feature is not implemented yet but is up for discussion here : #71

Copy link
Collaborator

@Daanvdplas Daanvdplas left a comment

Choose a reason for hiding this comment

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

  • We could potentially add the pallet to the runtime/src/lib.rs commented, then the user has to fill it in the Config items themselves. This would allow to take any pallet config and copy paste it in the runtime. The DefaultConfig transition is something that can be very beneficial to this feature: Adds default config for assets pallet paritytech/polkadot-sdk#3637

example: https://github.com/paritytech/polkadot-sdk/pull/3637/files

With this, the user would only have to implement the left over Config items not handled by the DefaultConfig.

  • let the user specify the pallet index to use in the runtime:
    pop add pallet frame or pop add pallet --path <path to runtime>

  • You very specifically explain what is happening in the code, very nice. However, it would also be nice if you could explain it in a more human understandable way.

src/engines/pallet_engine/mod.rs Outdated Show resolved Hide resolved
steps.push(RuntimePalletImport((
quote!(
// Imports by pop-cli
pub use pallet_parachain_template;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The template that is created has a name. Could we name the pallet like that?

pop new pallet test will result here into pallet_test

Copy link
Contributor Author

@weezy20 weezy20 Mar 21, 2024

Choose a reason for hiding this comment

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

So, what you're looking at here is code for adding the default pallet-parachain-template that lives on cumulus (and subsequently, on the pallet template used by pop new pallet template). There is no support yet to handle custom pallets created by pop new or FRAME.

Copy link
Collaborator

@Daanvdplas Daanvdplas Mar 22, 2024

Choose a reason for hiding this comment

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

Yet but is it not meant for adding a pallet that the user created? Don't see much reason for adding the pallet template. Someone creates a new pallet pop new pallet awesome_pallet and then someone wants to add that pallet to the runtime pop add pallet --path pallets/awesome_pallet

Copy link
Collaborator

Choose a reason for hiding this comment

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

Reading also the other comments I made regarding this topic. What is there for value in adding the pallet_parachain_template? The user will then have to change the name themselves everywhere

steps.push(SwitchTo(State::Config));
steps.push(RuntimePalletConfiguration((
quote!(
/// Configure the pallet template in pallets/template.
Copy link
Collaborator

Choose a reason for hiding this comment

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

"Configure pallet test in pallets/test."

Same for all the other places where this will have an effect.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See comment above please.

steps.push(RuntimePalletConfiguration((
quote!(
/// Configure the pallet template in pallets/template.
impl pallet_parachain_template::Config for Runtime {
Copy link
Collaborator

Choose a reason for hiding this comment

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

TODO: this should be read from the pallet lib.rs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See above please. Same reason as above.

// Build Pallet Details
let __buf = BufReader::new(File::open(&input)?);
let file_end = __buf.lines().count();
let rt = fs::read_to_string(&input)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe this is me but I find this naming confusing, what does it stand for? Multiple cases in the code, any reason why besides shorter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

rt -> runtime.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agree with Daan here, this part is not easy to follow. Clear naming or take some lines into specific function might help

/// Add a new pallet to RuntimeDeclaration and return it.
/// Used to pass a typed AddPallet to modify the RuntimeDeclaration
/// Overwrites existing CRT in output, this means that `self.cursor` has to backtracked to crt_start
/// and updated after the pallet entry has been inserted
Copy link
Collaborator

@Daanvdplas Daanvdplas Mar 21, 2024

Choose a reason for hiding this comment

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

Sorry but I simply don't understand what you are saying here :)

You explain what is happening in the code very detailed, well done! However, it would make the reviewer's work, and anyone diving into the code, much more effective and easy if you could also add a high level explanation of what the code / function does. As a result, the reviewer can get a high level understanding of what the function is doing / meant to do before going going over the code in detail.

It would be really nice if you could document your code in a way where:

  1. First, you explain high level what this function does, or what the code from now on (when following the code) is about to do. in a way where a (parachain) developer understands what is about to happen and why.
  2. Second, provide additional detailed code explanation (this you already have).

Copy link
Contributor Author

@weezy20 weezy20 Mar 21, 2024

Choose a reason for hiding this comment

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

Yeah for this case, I should explain it better. So the commented code in add_pallet_runtime is altogether a different system that I had created during prototyping of pallet engine to add pallets to the CRT macro. What this does is effectively use the structure RuntimeDeclaration that's parsed from the source file, append to it with more checks such as indicies, instances, etc. (some of which have no implementation right now but are put off until we dive into handling duplicated entries), and update the tokens for the CRT macro in place in the output file.

@weezy20
Copy link
Contributor Author

weezy20 commented Mar 21, 2024

  • We could potentially add the pallet to the runtime/src/lib.rs commented, then the user has to fill it in the Config items themselves. This would allow to take any pallet config and copy paste it in the runtime. The DefaultConfig transition is something that can be very beneficial to this feature: Adds default config for assets pallet paritytech/polkadot-sdk#3637

example: https://github.com/paritytech/polkadot-sdk/pull/3637/files

With this, the user would only have to implement the left over Config items not handled by the DefaultConfig.

This is a great idea. Would probably come to fruition when we start work on adding FRAME support.

  • let the user specify the pallet index to use in the runtime:

This can be done as the machinery exists already, just not in the CLI. One thing to note here is that although unimplemented currently, when we start working on unique pallet additions or iow, a name conflict resolution strategy, pallet additions would automatically be indexed, respecting CRT checks such as the requirement for the index to be u8 and respecting the pallet order.

pop add pallet frame or pop add pallet --path <path to runtime>

  • You very specifically explain what is happening in the code, very nice. However, it would also be nice if you could explain it in a more human understandable way.

I'll try my best. Thank you.

@AlexD10S
Copy link
Collaborator

First thing I notice is that the pallet generated from pop new pallet isn't used for adding it. I can run pop add pallet template without it?

About this discussion I don't have it very clear.
If I run pop add pallet template without having run the pop new pallet before parachain doesn't build, because it adds by default in the Cargo.toml a path that doesn't exist:

pallet-parachain-template = { path = "/pathtoparachain/pallets/pallet-parachain-template", version = "1.0.0", default-features = false }

Is that expected? For me is a bug, we should do automatically the pop new pallet or show an error.
We should discuss the issue for this PR: #71

As per https://crates.io/crates/tempdir, tempdir was deprecated ages ago with functionality moved into tempfile which already exists as a dependency. Primary motivation was a security advisory triggered by dependabot.
@weezy20
Copy link
Contributor Author

weezy20 commented Mar 21, 2024

First thing I notice is that the pallet generated from pop new pallet isn't used for adding it. I can run pop add pallet template without it?

About this discussion I don't have it very clear. If I run pop add pallet template without having run the pop new pallet before parachain doesn't build, because it adds by default in the Cargo.toml a path that doesn't exist:

pallet-parachain-template = { path = "/pathtoparachain/pallets/pallet-parachain-template", version = "1.0.0", default-features = false }

Is that expected? For me is a bug, we should do automatically the pop new pallet or show an error. We should discuss the issue for this PR: #71

This is known, not expected at all and is a bug. Do you recommend we address #71 immediately @AlexD10S ?

src/commands/add/mod.rs Show resolved Hide resolved
/// Insert `pallet-parachain-template` into the runtime.
Template,
/// Insert a frame-pallet into the runtime.
Frame(FrameArgs),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I personally don’t like to have the FRAME logic there if is not working. It might be confusing for the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would the user be confused when they're met with a not implemented message ? If I delete this scaffolding code which is minimal btw, I will have to rewrite it when we start with Frame which we are going to do anyways.

Copy link
Collaborator

Choose a reason for hiding this comment

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

With git there is no need to rewrite things, just take it from here into another branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry I have to disagree with that approach. Doesn't solve anything.

}
path
},
None => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

For UX, Is not better to use clap errors?. Will be add runtime_path as mandatory above

If i run cargo run add pallet template it panics

thread 'main' panicked at src/commands/add/mod.rs:62:17:
not implemented: provide a runtime path until feat:cache is implemented: --runtime <path>
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

If I run cargo run up parachain without the mandatory commands it shows me how to use the tool:

error: the following required arguments were not provided:
  --file <FILE>

Usage: pop up parachain --file <FILE>

For more information, try '--help'.

Copy link
Contributor Author

@weezy20 weezy20 Mar 22, 2024

Choose a reason for hiding this comment

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

I agree. This makes more sense when we have a functional cache.. Just for the record,reason to use an Option here is to rely on automatic inference via the pop new cache in the case that user omits -r. But yeah seems right to make it required

path
},
None => {
// TODO: Fetch runtime either from cache
Copy link
Collaborator

Choose a reason for hiding this comment

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

For TODOs is better to create an Issue, than lines of code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some of it is already in the issue and PR description. These are just placeholder comments from where future work can be easily picked up where these were left off.


/// The main entry point into the engine.
pub fn execute(pallet: AddPallet, runtime_path: PathBuf) -> anyhow::Result<()> {
// Todo: Add option to source from cli
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not very clear

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean?

pub fn create_pallet_template(
path: Option<String>,
config: TemplatePalletConfig,
) -> anyhow::Result<()> {
let target = resolve_pallet_path(path);
// TODO : config.name might use `-` or use snake_case. We want to use pallet_template for the pallet dirs
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why adding it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't think it's necessary anymore. Will remove.

@@ -0,0 +1,913 @@
#![allow(unused)]
// This file is part of Substrate modified to fit pallet manipulation needs for pop-cli
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we use everything from here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not yet. This is important when a future implementation will use in place editing of RuntimeDeclaration rather than inserting strings. It's basically the entire parser for construct_runtime!

}
/// Create a new PalletEngine
pub fn new(input: &PathBuf) -> anyhow::Result<Self> {
let tmp_dir = PathBuf::from(format!("/tmp/pallet_engine_{}", uuid::Uuid::new_v4()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is not better to create and remove the /tmp/pallet_engine than having to add a uuid?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How would you prevent name collisions?

Copy link
Collaborator

Choose a reason for hiding this comment

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

but the tmp folder is removed after no?

Copy link
Contributor Author

@weezy20 weezy20 Mar 22, 2024

Choose a reason for hiding this comment

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

No it's not. At least not in code. We are relying on linux system to clean it up by placing it under /tmp on reboot or on non-usage.

frame-benchmarking = { version = "26.0.0", default-features = false, optional = true}
frame-support = { version = "26.0.0", default-features = false}
frame-system = { version = "26.0.0", default-features = false}
frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.1", default-features = false }
Copy link
Collaborator

Choose a reason for hiding this comment

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

I added this line to make it work for Sub0, but is there another way?

Otherwise we will have to always update it here when updating base-parachain: https://github.com/r0gue-io/base-parachain/blob/main/Cargo.toml

Copy link
Contributor Author

@weezy20 weezy20 Mar 22, 2024

Choose a reason for hiding this comment

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

This entire template needs to be updated to use release-polkadot-* dependencies. Cannot have the base-parachain using them and this one using crates-io dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On second thought, I think you've made the appropriate changes already.

tests/add.rs Outdated Show resolved Hide resolved
@AlexD10S
Copy link
Collaborator

First thing I notice is that the pallet generated from pop new pallet isn't used for adding it. I can run pop add pallet template without it?

About this discussion I don't have it very clear. If I run pop add pallet template without having run the pop new pallet before parachain doesn't build, because it adds by default in the Cargo.toml a path that doesn't exist:

pallet-parachain-template = { path = "/pathtoparachain/pallets/pallet-parachain-template", version = "1.0.0", default-features = false }

Is that expected? For me is a bug, we should do automatically the pop new pallet or show an error. We should discuss the issue for this PR: #71

This is known, not expected at all and is a bug. Do you recommend we address #71 immediately @AlexD10S ?

Before merge to main yes

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.

6 participants