Patract's treasury proposal for Ask! v0.3 (AssemblyScript Contract)
Ask!'s goal is to provide a set of contract frameworks and compilation tools using AssemblyScript as the programming language. Contracts written through Ask! can run in the FRAME Pallet-Contracts , and eventually can call each other with contracts written by ink!. One month before, Ask! had completed the development of v0.2, and here was Development Report, External Review Form and Review Report for the previous version. After v0.3, we will release Ask! 1.0 as the first production version for massive test and usage for community developers and detailed docs.
Main features of v0.3
This proposal will complete the following functions on the basis of v0.2:
1. Add project management tool ask-cli
The positioning and function of ask-cli
is similar to that of cargo contract
, it mainly completes the following functions:
- Initialize the Ask! project. Provide
ask-cli init
command to create a new contract project. It will mainly complete the following tasks:- Check the current latest version of
ask
, and the dependencies of ask. - Create a project directory and initialize basic settings.
- Download/update all dependencies to the local directory.
- Check the current latest version of
- Encapsulate the compilation process of ask.
- Provide
ask-cli compile
command to control the compilation process. Thecompile
command will provide two modes ofdebug
andrelease
, and the default is to use therelease
mode to compile. among them:- In the
debug
mode, debugging information will be generated in the.wasm
file, and the.wast
andmetadata.json
files will be generated at the same time, and the files expanded by Preprocessor will be saved to theextension/
folder. - In
release
mode, the highest level of optimization options will be used to compile, and only.wasm
andmetadata.json
files will be generated.
- In the
- Provide
2. Performance optimization
2.1 Merging the functions of @storage
into @contract
, reducing the process of state variable definition.
In the implementation of v0.2 version, the @storage
annotation was introduced, which is specifically used to mark that a certain class is used to save state variables, such as:
@storage
class StateVariable {
varA: i8;
varB: u8;
@ignore
varC: bool
// ...
}
@contract
class Contract {
sv: StateVariable;
// ...
@message
msgA(): void {
this.sv.varA = 8;
// ...
}
}
With this implementation method, the original purpose is to distinguish state variables and ordinary variables, so that when some parameters need to be passed across methods, ordinary variables can be used without additional storage burden, but this requirement is in v0.2 With the introduction of @ignore
, there can be better implementations. At the same time, the use of @storage
to distinguish variable types has obvious disadvantages:
- Introduced additional coding burden, each time you use it, you need to use the writing method of
this.sv.varA
. - When the contract has an inheritance relationship, it is not convenient to arrange the storage location of the data in the subclass and the parent class.
Therefore, in v0.3, the functions of @storage
and @contract
will be merged. The contract in the above example can be written more directly as follows:
@contract
class Contract {
varA: i8;
varB: u8;
@ignore
varC: bool
// ...
@message
msgA(): void {
this.varA = 8;
// ...
}
}
2.2 Optimize the key generation logic used when storing state variables: Use continuous hash data instead of dynamic hash(string).
In the implementation of v0.2, the key used when storing state variables is obtained by calculating hash("_lang_ask.contract.varA")
. This generation method is not convenient for more reasonable arrangement of storage locations, especially for collection types such as map and array.
In v0.3, for non-@ignore variables defined in the contract, storage locations will be generated in an orderly manner according to their declaration order (including variables of the parent class), as in the above example。The storage location of varA
is 0x0000000000000000000000000000000000000000000000000000000000000001
, the storage location of varB
is 0x0000000000000000000000000000000000000000000000000000000000000002
... and so on.
2.3 In the process of a message call, when the value of the state variable is changed multiple times, reduce the number of calls to seal_set_storage
In the implementation of v0.2, every time the value of the state variable is changed, the seal_set_storage
method will be called in real time to save the result to the chain. The advantage of this implementation is that the value of the state variable will change in real time, which is very important when calling each other across contracts. But in most cases, it is not necessary to update state variables in real time, which will waste gas and consume IO operations.
In v0.3, the state variable will be updated in a lazy way, that is: in the process of a message call, the value of the state variable can be modified multiple times, but only after the message call is completed, will the final result be saved to the chain , So no matter how many times the state variable is modified, the seal_set_storage
method will only be called once. At the same time, in order to meet the need to update state variables in real time when calling across contracts, a new annotation @immediately
is introduced, which is annotated on state variables. If the state variable of @immediately is modified, its value will be real-time Update to the chain.
@contract
class Contract {
varA: i8;
@immediately
varB: u8;
// ...
@message
msgA(): void {
this.varA = 9; // won't update onchain value
// ...
this.varA = 18; // won't update onchain value
this.varB = 19; // update onchain value to 19 immediately
// ...
this.varB = 29; // update onchain value to 29 immediately
// ...
// update onchain value of this.varA to 18
}
}
2.4 Define the export format of Map and Array in metadata.json.
In v0.2, we provide the implementation of StorableMap
and StorableArray
, and in spread mode, they are saved as a doubly linked list, so that you can iteratively access all the data in StorableMap
and StorableArry
offline through the information provided in metadata.json. In order to achieve this goal, we will generate the necessary information for the StorableMap and StorableArray in the storage
object of metadata.json. For StorableMap, its storage information is like:
{
"name": "someMap",
"layout": {
"struct": {
"fields": [
{// StorableMap info of entry node
"name": "entries",
"type": "spread", // storage mode, "spread" | "packed"
"layout": {
"key": "0x0000000000000000000000000000000000000000000000000000000000000002" // storage position
}
},
{
"name": "key",
"layout": {
"ty": 5 // data type of key
}
},
{
"name": "value",
"layout": {
"ty": 5 // data type of value
}
}
]
}
}
}
For StorableArray, like:
{
"name": "someArray",
"layout": {
"struct": {
"fields": [
{// StorableArray info of entry
"name": "entries",
"type": "spread", // storage mode, "spread" | "packed"
"layout": {
"key": "0x0000000000000000000000000000000000000000000000000000000000000002" // storage position
}
},
{
"name": "key",
"layout": {
"ty": 5 // data type of key
}
}
]
}
}
}
2.5 Use JSON instead of ()
annotations
In the implementation of v0.2, the parameter of the annotation is provided by ()
, such as@message(payable = true, selector = "0x1234")
. In v0.3, it will be: @message({payable: true, selector: "0x1234"})
to improve the readability and maintainability of the code.
2.6 Enhance Event
syntax, provide js library for parsing Event data
- Support @event inheritance
Event is essentially derived from the_lang.Event
class, in terms of syntax they should support inheritance. But in v0.2 does not support inheritance operations, in v0.3, we will support the Event class can be inherited. - Optimize the constructor and implementation method
In v0.2, because of the functional limitation of Proprecess, when we generate the Event construction method, we call theemit
method by default, and the code of the Event class after the Preprocessor is expanded:
class Transfer extends _lang.Event {
private from: AccountId;
private to: AccountId;
private value: u128;
constructor(from: AccountId, to : AccountId, value: u128) {
super();
this.from = from;
this.to = to;
this.value = value;
// code inserted by compiler
this.emit();
}
}
This implementation has the following problems:
- If the
return
method is called in the constructor method, thethis.emit
method will not be called, resulting in the event not being sent. - The emit is defaultly used when constructing the Event, which is very unintuitive in coding.
For these reasons, we will optimize the implementation of Event to avoid the above problems by providing js library to parse Event data.
2.7 Enhanced annotation syntax and parameter checking
In the previous version, we have successively introduced multiple annotations, sub-annotations and annotation parameters, but before compilation, there was no good check during compilation, and no clear enough prompt information was provided when an error occurred. So in the v0.3, we will check all annotations and parameters in Preprocess, and provide friendly compilation information when errors occur.
2.8 Optimize the size of the generated wasm file
2.9 Upgrade the seal_xxx method in pallet-contract
Some seal_xxx
methods in pallet-contract
have been changed. In v0.3, the changed methods will be upgraded to the latest stable version.
3. Provide system parameter types in custom env
In the previous version, we used the FRAME provided in the Europa project by default, and defined the data types of the following system-level variables:
type Hash Array<u8>(32);
type AccountId Array<u8>(32);
type BlockNumber UInt32;
type Balance UInt128;
Although the default data type can meet most of the needs, in order to meet a small number of custom requirements, we will provide developers with the ability about custom Hash
AccountId
BlockNumber
Balance
data type in the v0.3 to adapt to different FRAME.
4. Unit Testing and Documentation
- Provide unit testing of Preprocess and framework.
- Provide tutorial documents for contract development.
- Provide framework API documentation.
Detailed timeline v0.3 (3 developers * 10 weeks)
- Week 1~2: ask-cli
- Complete the architecture design and implementation of
ask-cli
. - Implement
init
,compile
functions.
- Week 3~6: Performance optimization work.
- Merge
@storage
to@contract
:- Expand the
@storage
logic in the implementation of contract to realize the read and write ability of state variables. - Optimize the key generation logic when storing state variables.
- A new method is added to the implementation of contract to generate storage logic for state variables, ensuring that
seal_set_storage
is only called once. - Add
@immediately
annotation, which acts on state variables, and the annotated variables will immediately callseal_set_storage
to save.
- Expand the
- Enhance contract syntax.
- Standardize annotation usage, use JSON format instead of
()
method - Enhance compile-time syntax checking, when encountering unsupported annotations and parameters, a compilation error will be thrown.
- Enhance
@event
class, optimize implementation method and support event inheritance.
- Standardize annotation usage, use JSON format instead of
- Optimize the size of the generated wasm file.
- Define the export format of Map and Array in metadata.json, and provide js parsing library.
- Upgrade the
seal_xxx
method to the latest stable version of pallet-contract.
- Week 7:
- Customize the
Hash
AccountId
BlockNumber
Balance
data type in the env environment. - Update the usage of predefined environment variables in the framework.
- Week 8~10: Complete documentation and unit tests.
- Provide local test cases for Preprocess and framework.
- Provide ask contract development tutorial.
- Provide a tutorial on how to use ask-cli.
- Provide API documentation for each component in the framework.
Cost of v0.3 (30 developers * weeks)
- Operating activities: $6000 ( Rent and Devices: $200 per developer * week )
- Employee payments: $87000 ($2900 per developer * week)
- Total Cost: $93000 and monthly average: $203/KSM @ 28JUL
- Treasury Proposal: 458 KSM
How to verify v0.3 (github & docs & samples)
- Officially released npm library of ask and ask-cli.
- Reimplement the contract in examples with a new contract implementation method.
- Complete contract development tutorial.
- Complete API documentation.
Comments (7)
That sounds great to me. I would add a single comment about
ask-cli init
, make sure you use proper scaffolding and ideally provide an easy access to patch the template source as this is likely to evolve over time and it would be great for everyone to have an easy maintenance.You may get inspiration from https://yeoman.io/ on that topic.
Thank you very much, this suggestion is very helpful