Code generation algorithm
Intro
To generate our codebase dynamically, we implement a mini custom framework where we define each pallets config restricted by specific rules on how to write it.
Our algorithm parses the configs and inserts the code into a pre-coded base template located in /generator/template
Writing Pallet Configs
Every pallet should have it's own config file defined inside the /src/pallets/configs
folder
The config file should export a const object which implement the IPalletConfig
interface
When implementing the interface we also define all possible Traits
and GenesisConfig
fields of the implementing pallet.
The interface consist of name
, metadata
, runtime
and dependencies
fields
name
Defines the name of the pallet and is an enum value ofESupportedPallets
, this is because when later we define dependencies of another pallet we can link it to existing config through the unique name using the enummetada
It simply contains some relevant metadata of the pallet, nothing special hereruntime
This object contains most of the required data for generating the code for the pallet needed to insert into the node. It contains runtime modules needed for it to be implemented insideconstruct_runtime
, values for Trait implementation and data for the genesis config. If some code is unique and couldn't easily been abstracted it's put inside theadditionalChainSpecCode
andadditionalRuntimeLibCode
fieldsdependencies
This field defines the pallets dependency data to put inside theCargo.toml
file, additional pallets it needs (This is where theESupportedPallets
enum comes in handy, because we can now recursively find dependencies and insert them into the code if not already inserted), and also other standard deps needed for the pallet to function
Diving deeper into IPalletRuntimeConfig
IPalletRuntimeConfig
Substrate Project Generation
The main files our Algorithm touches are:
The runtime
lib.rs
- This is where we import and implement new Modules/Pallets. We can think of it as themain
file of our Substrate NodeThe manifest
Cargo.toml
- This is where we define any external dependencies needed for our pallets to runThe chain_spec.rs - This is the file where we define the initital values for our blockchain. We can think of it as a genesis file of our chain
What happens exactly?
The business logic of recursively resolving dependencies and order of writing the pallets into the codebase and file writing is inside
/src/services/codeGenerator.service.ts
file.But before the file is written, it's first read and converted into a string, where specific utility functions mutate it to include the new code. -
/src/utils/substrateManifest.util.ts
- Manages the Manifest file -/src/utils/substrateRuntime.util.ts
- Manages the Runtime and Chainspec filesAll the code is written into
/generator/temporary/${Date.now()}-${userId}
folder.
To prevent collision due to async nature of a web server, we must use userId
to uniquelly identify one session's code and not collide with a concurrent request.
Last updated