This is copy from https://kusama.polkassembly.io/post/766
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.
This proposal will complete the following functions on the basis of v0.2:
ask-cli
The positioning and function of ask-cli
is similar to that of cargo contract
, it mainly completes the following functions:
ask-cli init
command to create a new contract project. It will mainly complete the following tasks:ask
, and the dependencies of ask.ask-cli compile
command to control the compilation process. The compile
command will provide two modes of debug
and release
, and the default is to use the release
mode to compile. among them: debug
mode, debugging information will be generated in the .wasm
file, and the .wast
and metadata.json
files will be generated at the same time, and the files expanded by Preprocessor will be saved to the extension/
folder.release
mode, the highest level of optimization options will be used to compile, and only .wasm
and metadata.json
files will be generated.@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:
this.sv.varA
.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;
// ...
}
}
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.
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
}
}
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
}
}
]
}
}
}
()
annotationsIn 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.
Event
syntax, provide js library for parsing Event data_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.emit
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:
return
method is called in the constructor method, the this.emit
method will not be called, resulting in the event not being sent.For these reasons, we will optimize the implementation of Event to avoid the above problems by providing js library to parse Event data.
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.
Some seal_xxx
methods in pallet-contract
have been changed. In v0.3, the changed methods will be upgraded to the latest stable version.
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.
ask-cli
.init
, compile
functions.@storage
to @contract
:@storage
logic in the implementation of contract to realize the read and write ability of state variables.seal_set_storage
is only called once.@immediately
annotation, which acts on state variables, and the annotated variables will immediately call seal_set_storage
to save.()
method@event
class, optimize implementation method and support event inheritance.seal_xxx
method to the latest stable version of pallet-contract.Hash
AccountId
BlockNumber
Balance
data type in the env environment.ask-cli
for project initialization and compilation.@storage
into @contract
for simpler state variable management.seal_set_storage
by updating state variables lazily.Map
and Array
in metadata.json
.()
to JSON format.Event
syntax and added support for inheritance.Hash
, AccountId
, BlockNumber
, and Balance
.