Yesterday, the Substrate Seminar initiated by Parity Tech was hosted by Patract CTO Aten to introduce the full-stack tools being built to power Wasm smart contract development for Substrate based chains.
View for this wonderful video playback：https://www.crowdcast.io/e/substrate-seminar/39
Here is the share from Patract CTO — — Aten.
Hi everyone, we are the Patract Labs, and I’m the technical leader from the team. You can call me Aten. It is a great honor to share the work we have done on WASM in the Polkadot ecosystem. First, let’s introduce Patract Labs briefly. Patract is a Tech Lab, building WASM smart contract in Polkadot. We are focusing on providing support for Pallet-Contracts, ink! and other related techniques.
As stated on our website: Patract’s mission is to accelerate the smart contract industry’s transition to WASM technology stack. Polkadot is really a great platform. It provides unlimited imagination for developers, and allows people to build their own chain with substrate. Meanwhile, many business scenarios can be implemented by deploying, composing contracts, So we believe, Polkadot’s parachain with contract platform, will have stronger activity than other ecosystems.
Parity is mainly focusing on Substrate and Polkadot’s fundamental infrastructure, so there maybe some missing on the WASM smart contract part. Between contract developers and platforms, there is a large gap. Our mission at Patract, is to create a bridge between the gap.
It has already taken 5 or 6 years to gradually build a large ecosystem for smart contracts on Ethereum. Imagine a contract developer who wants to build in Ethereum. He has enough tools to use, It’s very easy to copy and create new contracts. While in Polkadot, a developer who wants to deploy a WASM contract doesn’t have that luck. This part in Polkadot is totally blank. And that’s our mission in Patract. We are here, to build a multi-functional toolchain for Polkadot WASM contract ecosystem.
This image is from Truffle suite website. Everyone who builds in Ethereum knows Truffle. We can see that Truffle suite tools are designed around the development workflow of plan -> code -> build -> release an so on. Therefore, Truffle, Ganache and other products are designed around this workflow. These products collaboratewith each other and help developers around the workflow of contract development.
Therefore, our Patract’s products also follows this design idea: We have launched the testnet named Jupiter to provide a basic contract running environment, which we design the zkMega pallet to provide some zero-knowledge proof support.
Then, for developers, we work around the workflow of develop->debug->test- and ->deploy.
- Redspot is a product similar to Truffle, a tool to make contract development become projectized. It covers the entire process of contract development such as Develop->Debug and so on.
- Europa is a product similar to Ganache. It is a simulation node that provides a contract running environment, and it records a lot of contract information during executing contracts.
- Metis is a project similar to OpenZepplin contracts. it’s purpose is to establish a way for developers to write contracts in a standard way.
- Ask! is a contract language which we are developing, based on AssemblyScript. It is used for writing Wasm contracts, same as ink!, but because it is based on AssemblyScript, which is a variant of TypeScript, So it may become more popular with developers.
- Himalia is the general name of contract SDKs in multiple languages, similar to Web3.js, web3J, Web3py, and so on. Currently Polkadot.js is officially designed by Parity, but other languages do not have good support for contracts, such as go, java, python and .Net. Himalia is for this purpose, and this project has finished two languages SDK for go and python。
- Leda is used to monitor the contract running information. For example, the storage rent mechanism of the pallet-contracts will cause the contract to be destroyed when it does not have enough money, so monitoring contract on-chain data is required. The project is currently only in planning, because ink! and pallet-contracts cannot be widely used in production environment.
- Carpo is our contract WebIDE that integrates all our products on the developer side into a service, and will provide developers with a one-stop contract development process. There is a Remix in Ethereum, but the Remix cannot give developers a good experience, for it does not have a good language service system, (but it does a good job for helping contract development, I mean, it is designed for contract).
- And the Substrate playground is a good usecase, but it lacks the design of For Contract Development. Therefore, we believe that Carpo will greatly help the contract development ecosystem, because it’s designed for the contract development, and the experience can be close to the local developing. Carpo is in planning now, but we expect this project to start around July.
- Elara is a product that provides blockchain endpoints for developers and users, similar to Infura in Ethereum. Our Elara has some unique designs, which can provide more connected node services with fewer resources. We are re-writing this part recently, and it will be more robust in the future.
- For the user side, our products mainly include PatraScan and PatraStore. Among them, PatraScan adopts a different design with other blockchain scan in the Polkadot ecosystem, thus it could show more detailed blockchain information. For PatraStore, we adopt a concept similar to dapp platform, which allows users to experience all kinds of dapps in one-stop, now it only contains several sample open source DApps. For now, PatraScan is in development and PatraStore is running for first version.
By the way, we are building the document for WASM Contract and our other products, which is named Substrate Contract Book. The document can be a greatly useful tool to help developers learning and writing WASM contracts in one stop.
Next, let‘s go through some cases and find out how does our product work.
First, let me show you how to use Redspot and Europa to develop contracts.
- You should make sure you have nodejs in your computer
- npx redspot-new erc20
- Look at this, this is not just a simple contract, it’s a project which contains scripts, tests, and you could use redspot command to do many things.
- This method regulates the way to organize a contract project. It has many advantages, such as the https://github.com/CycanTech/ELC project. This project is an ink! project built by redspot. it’s a multi-contract structure. Since the deployment of multi-contract projects is complicated, for example, first need to deploy this contract, and next deploy this contract.
If another developer wants to reproduce this project, including deploying and testing, he only needs to clone the project to local directly, keep the project structure, and use redspot command to compile, deploy, test and other processes without spending time to study how to rebuild multi-contract relationships.
- Now we need to run a node to deploy and run the contract. Parity has its own Canvas testnet environment for contract testing, but in the actual development of local testing process, using node to test is time-consuming and troublesome. Therefore, we designed Europa to replace the node which runs the contract
- First, we run europa in this way, it’s similar to a normal substrate node. and we open apps, we can see that apps can connect to europa directly,
- Then we try to do a transfer, and we can see that the extrinsic is packed immediately, without the need to wait for the time of block interval. This feature saves developers a lot of time. This feature is very important in developing and debugging, or in combination with redspot for integration testing, or in other cases. so europa is a better simulation of a node environment.
- Now we have a node to execute the contracts. then we go back to Redspot.
- First we execute npx Redspot compile, we could see that Redspot auto detects the contract directory, and do compile. the detected directory config is in redspot.config.ts file. All based Redspot configs could be found here, and more features could refer to our document. Here the config part introduces all configs.
- Now, we can see the compiled products is in artifacts directory, and the name is your contract project name.
- Parity apps can react with node to deploy the contracts, we try this first. We deploy this contract and call transfer. It’s a normal workflow.
- But please note that, image if we change the contract and wanna test it, first we compile it again. Then we need to re-deploy it and call a function. We can find that, this process in apps is very troublesome and boring.
- Then we look at the deploy script in this directory. Like what we do in apps, deploy a contract and call a function, we can write those action as a script.
- Then, we only need to execute run command to run this script( npx redspot run scripts/deploy.rs), so this script will automatically do the same thing in apps. When the contract changes, after compiling, we can execute the run command to quickly do the same thing. We can see that, Redspot cooperating with Europa can greatly free the power of contract developers.
- Next, we look at the scripts in the tests directory. You can notice that test provides rich tools for testing. Redspot’s testing framework is based on mocha and chai, and we have designed our own redspot/chai plug-in for test. View for details.
- Here, we emphasize that redspot is forked from Hardhat, so redspot can expand its rich functions through plug-ins. For example, the redspot/chai is a plugin, and here is the imported plugins. Currently we have some basic plug-ins, and community developers can also participate in enriching the features of Redspot.
- Now we switch to europa to take a look. During calling the contract, a lot of information is printed in europa’s log. Compared with normal system, when execute the contract in EVM or in pallet-contracts directly, the execution process of the contract is a black box for developers. Therefore, europa is committed to display the internal information of execution and turn the execution process into a white box to provide developers with rich execution information.
- We collect a contract’s execution process into a NestedRuntime, so for once execution, we can see the contract address, selector, parameters, gas and other information in the contract execution. Notice the gas_left here. When in a cross call contract situation, I mean a contract calls another contract, only the gas consumed during the entire call can be known, but the gas consumed by each layer of the contract call cannot be known. And the gas_left shows one layer contract gas consumption, it can solve this problem.
- For example, in a call, contract A calls contract B. In normal case, we only know the gas consumptionfor the whole process, and don’t know how much gas for A and B respectively. And in Europa, the gas_left here shows the gas consumption inside the contract. So we can figure out the gas consumption through this field.
- And env_trace shows the call of host_function in this contract execution. According to host_function, we can get more information to help user to solve the bug of contracts, for example we can follow the sequence of host_function to guess where the contract is trapped. If the contract is trapped, the following host_function will not be printed.
- The nest field represents the crosscall for contract. For example, in the process of A calling B, contract A is the outer layer NestedRuntime, and contract B will appear in the nest part with the same NestedRuntime structure.
- Therefore, through Europa, the execution process of the contract can be turned into a white box , allowing developers to debug the code in a better way.
- In addition, Europa can also print out the Wasm backtrace when contract traps. To test this, We add a panic in “constructor” function. Of course, when init the contract, it will trap here. So, we execute command to deploy contract, and switch to Europa log. View for details.
- you can see that the Wasm error can’t be parsed to show more details. To analyze this parts, we need to install the cargo-contract under our patract repo, not parity. For our cargo-contract providers debug compiling feature. (cargo install cargo-contract — git click — branch=v0.10.0 — force)
- Then we switch to the contracts directory to compile contract. Please note that our cargo-contract can add the — debug parameter to compile, and then we replace the target contract file in the artifacts directory, because, redspot can recognize the contract file here.
- Now, we execute the run command again, but notice we need to add no-compile flag in case redspot recompiles the contract, and we can see the detailed Wasm backtrace print during this execution, and from the print process we can see that the error location appears in new function part, here, is the same location we just added panic code.
This is the workflow of ink! collaboration of our Redspot and Europa. After the Ask! could be used in production, we will add the Ask! config here for Redspot to recognize Ask! contract files, so that the ink! and Ask! contracts can be developed in one project at the same time.
Patract’s data service layer
Next we introduce Elara and PatraScan system. In fact, our data-related services are built on our Patract Data Service Layer. The core of Data Service is to export all on-chain data to an external database, including blocks, extrinsics, and state data, which is the most important. There is a Substrate-archive project in the Parity repo. its purpose is to run alongside a Substrate-backed chain to index all Blocks, State, and Extrinsic data into PostgreSQL. View for details: https://github.com/paritytech/Substrate-archive .
When we were building Data Service in the early days, we used this project. But there were many problems and bugs in the project at that time. Therefore, members of our team submitted code to this project. But with the development of our work, we believe that the Substrate-archive no longer meets our requirements at many points. Therefore, we no longer use Substrate-archive as the data export component of our Data Service, and we rewrite an Archive project by ourselves. It’s not open source now.
Based on the Data Service Layer, we currently have two projects in progress, Elara and PatraScan. Among them, Elara is a service providing node endpoints, which is similar to Infura. Its goal is to provide more node connection services with as less resources as possible. Some time ago, the parity public node for Apps was offline, and the service for wallet was stopped for a period of time. The endpoints available at that time were Onfinality and our Elara. In that time, we used a small amount of resources to carry a large number of connecting requests, which is based on the architecture shown in this figure.
In Elara’s system, when users access through endpoints, they are not directly connecting to nodes, but connecting to our Elara middleware. Elara middleware is designed as a form that can be expanded in parallel. In this component, Elara manages connection from the user side, including queries and subscription requests, and Elara classifies the access requests according to some strategy.
The subscription request from client is hosted by Elara and subscribed by the Elara middleware to the node. In this way, Elara middleware receives the state update notification of each block, and notify related connection client. The query request is forwarded by Elara to the Patract Data Service Layer instead of querying the node directly. In this way, we transfer the connection and computing pressure from node to Elara, thus, Elara has stronger scalability than node. And in this way, we don’t need to build a blockchain node cluster and waste lots of resources.
PatraScan & Other Scans
Then we look at the right side, the right side is the structure of our PatraScan.
Look at this, All current blockchain scans basically subscribe to the events, and then, query the data of the chain based on the event information, then construct a database of the scan, and finally display it to users. While, PatraScan uses directly exported chain state to display data. The former is related strongly to business, while the latter is related weakly to business.
For example, when a transfer appears on the chain, for other scans, its approach is generally like this:
- First, they need to know that there is the business logic of transfer on the chain, and after the transfer occurs, a event will be printed. And they need to understand that when the transfer occurs, the balance of the sender and receiver will change.
- Subscribe to this event.
- When meeting an event such as transfer, they need to query the chain for the balance of the sender and receiver, then update their own database.
We call this scan strongly related to business, because it needs to make different processing according to each event. For example, transfer needs to update the balance of the sender and receiver, and staking needs to query more data related to staking. This approach is more like a Pull behavior.
And for PatraScan, we do not need to deal with different situations according to the business logic of the chain, but consider how to reasonably display the onchain-state data. For example, for the transfer operation, the data on the chain will change according to the logic of the transfer. After the state is exported, when querying the balance of an account, we will directly display the state of the account, without the need to update the related database table separately. This approach is more like a Push behavior.
PatraScan & Apps
Compared with Apps, the pattern of PatraScan is actually closer to the pattern of Polkadot Apps (I mean this one). As shown in the figure, the structure of apps is split into business and view. Then for apps, actually, it’s a process of re-combining the on-chain state, that is on the user side, business logic and view are combined together. Therefore, Apps can directly access the chain and display the onchain state.
For PatraScan, the structure is equal to that, we move the business logic of apps to the backend, and combine the onchain state in the backend, display them in the frontend view. The part combined business and onchain state is called PatraScan API and can be used in different places.
At now, PatraScan’s product logic is being designed, and most of the underlying infrastructure of Scan has been completed. After the product logic design is ok, Scan will start to develop, so it will be launched soon.
PatraScan is a way to use our Patract’s Data Service Layer. After the PatraScan project is completed, we can design more data layer-based products. For example, in the Ethereum ecosystem, there are lots of data analysis /əˈnæləsɪs/ services for DeFi, which are the secondary development for onchain data. We expect that the next product is related to GraphQL.
And the third part is our Ask! contract language. The design of Pallet-contracts has nothing to do with the contract language. And because there are many languages that can be compiled into Wasm, so, we can design contract languages that can run on pallet-contracts based on different programming languages.
Then, if we already have ink! , why do we need to design a new contract DSL based on other languages? This is because different languages will have different programming paradigms. In different business scenarios, different programming paradigms may be required. We think there is no such thing that covers all business scenarios using only one language.
To give a typical example, there is an inherited feature in solidity, while there is no inheritance in rust. Instead, it uses trait system and combination pattern. Therefore, in different business scenarios, it’s suitable to use different language systems to write different contracts.
On the other hand, the crosscall contract is actually more like the calling process between microservice, because the more important feature of the contract is that, the resource of the contract is only related to the current contract, that is a contract is an independent unit. Because the state storage of the contract is only related to the instance of this contract.
Between microservice, only the interface specifications between the invocations are agreed upon, and the respective implementation methods of the microservices are not limited. Therefore, the contract is the same. Different contracts can be implemented in different languages, as long as the interface of the contract calling the contract is uniformed. Therefore, Ask! is compatible with ink! in the contract call at the beginning of the design.
So we design the Ask!, which developers have another option to write Wasm contracts.
The overall design and model of Ask! are close to ink!. Let’s take a look at this comparison table between Ask! and ink!.
In terms of based language, ink! is based on rust, Ask! is based on AssemblyScript (aka AS). AS is a strict variant of TypeScript. Therefore, its programming paradigm is closed to TypeScript, and TS is currently a very popular programming language with a wide range of developers.
Ink! and Ask! are based on the original language and add the contract features by modifying the AST in the original file, both of those are the same. (I mean the Abstract Syntax Tree)
The ways to modify the AST are different, which is mainly due to the different features provided by the compilers of different languages. Ink! uses procedural macros, while Ask! uses compiler plug-ins. This means that if you want to compile the Ask! contract, you need to use the completed compiling environment provided by Ask!, however, you can compile ink! only use rust compiler if you want.
For the basic elements provided by the contract languages. The designs of the two are the same, and both are more following the solidity design.
For storage model designs. Since the Substrate state is based on the k/v state, ink! designed the concept of Spread Layout on the storage model. Ask! has not made any special innovations here. So, it can be regarded as an another implementation.
Ways to reuse code. Reusing code is divided into two models under the concept of contract, cross-contract call, and reuse existing code.
- Cross-contract call. ink! tries to use trait_definition to define the interface, but the current implementation of this part is not good enough. For Ask!, we adopt the concept of interface, which is similar to the design of solidity.
- Code reuse. Since ink! is based on Rust, the code can only be combined. While, Ask! can use inheritance. But ink!’s current support for reuse is very limited.
- A typical case is, if there is already an ERC20 contract standard implementation, like the OpenZepplin-Contracts library, if you want to add an issue_token function to this standard contract. Then in ink!, currently developers only can copy the entire contract from the source repo to local, and add this function.
- (Unless ink! is designed on the contract composability. And because the resources of the contract are bound to this contract, it is difficult to design this piece of composition semantics. )
- As for Ask!, it can design a way similar to solidity’s inheritance, inheriting from this ERC20 contract and extending the issue_token function directly.
All the above, is the content shared by our team Patract. In summary, first we introduced the design ideas of all our products, and then we selected 3 scenarios and introduced our design.
Thanks for the time of all. This is what I shared with you today. We are really appreciated.
Patract is providing solutions for the development of Parachains and DApps in the Wasm smart contract ecosystem of Polkadot. We help the community to design and develop on-chain contract modules and Runtime support, and provide DApp developers with full-stack tools and services support, covering development, testing, debugging, deployment, monitoring, data provider and front-end development stages.