The Workflows of Developing NEO Smart Contracts
Abstract: The typical development workflow of developing NEO smart contracts has two actual phases: Coding (edit in IDE and compile to .avm) and Testing (deploy, invoke and check results on test nets). This workflow requires compiling and deployment for debugging any code changes. With the help of some latest toolsets developed by the NEO community, a 4-phase workflow is emerged to further improve the development efficiency.
In this tutorial, we’ll first give a brief discussion of the standard 2-phase workflow with some useful references, then introduce the 4-phase workflow along with related new development tools. Unless otherwise specified, the discussion takes C# as the smart contract language.
It’s certainly possible that I make mistakes or miss some points in this tutorial, very appreciated for any comment.
1. Two-Phase Workflow
Conventionally we have two actual phases in NEO smart contract development: Coding and Testing. This official tutorial provides more details about this workflow.
For the coding phase, NEO officially supports C# (examples HERE). We can also develop a smart contract with Java and Python. Since we can easily find pages of tutorials and sample codes to tell how to code NEO smart contracts on Google and Youtube, I would bypass this part in this tutorial.
We rely on test nets to do the testing phase. As shown in the above figure, we have many choices for the test nets.
Public test nets
The most common approach is to use public test nets. There are three major public test nets maintained by NEO Smart Economy, CoZ and NEL respectively. Alex Guba’s tutorial elaborates on how to synchronize the blocks and request GAS before testing on the NEO and CoZ test nets, while NEL’s test net is more friendly to Chinese developers with localization support.
In many cases, you can run RPC calls via NEO API (Full reference) for blockchain interaction. Some APIs are available only when you have a running NEO-CLI node with an opened wallet. However, if the test net equips Neo-Scan, you can call similar services instead without running such node. For example, API getBalance requires a running node, but you can use get_balance of Neo-Scan for similar functionality. I created a Postman collection to help test these remote procedures. Just change the values of the test net(or Neo-Scan) domains to play with it.
NeoCompiler Eco has a new and special public test net which inspired our move to the four-phase workflow. We’ll talk about it more in the next chapter.
Private test nets
Another good approach is to set up your own private test net. Comparing with the public test nets, private test nets’ advantage is that you can take full control. The first reason for using private test nets is that it’s really helpful and encouraging with the illusion of holding millions of NEO and GAS in the wallet. At meanwhile, compared with public test nets, we don’t need to worry about the chain regenesis, connection failure, or maybe some other developers mistakenly jam the network.
NEO’s official site provides the step-by-step tutorial of setting up a private net on cloud services. But after checking my bill from Azure, I wouldn’t recommend it unless you have to share the chain data with other people. Neo-privatenet-docker is great to build the private test net on your local machine, while saves your time from tons of configuration and instructions. If you run it on a laptop, well… it’s also helpful to keep your body temperature in winter.
The limitation of the 2-phase workflow
This 2-phase workflow is mature being adopted by the majority of existing projects. Nevertheless, it has some limitations compared with conventional software projects. The major one is that the debugging is very costly. To monitor variables’ runtime values, the best choice is to use runtime notification such as this one:
byte[] ba0 = CallSomeFunction();
byte[] ba1 = CallAnotherFunction();//Print out the value of ba0 and ba1 to ApplicationhLog
Runtime.Notify(ba0, ba1);
Even in the happy path, we still need to recompile the project with neon, then ensure enough GAS to do the redeployment, then compose the proper parameters with correct format, then invoke the contract and wait for 20 –30 seconds for the generation of the next block, then call the API getapplicationlog to fetch the log in JSON, then print the response with pretty format to find the logged values (check the bold part in the following sample response). Since usually the logged values are expressed in byte arrays, we also need to convert them back to Strings or BigIntegers. Well, it’s altogether 7 steps.
[
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"txid": "0x7e3f08a8af4290693184b413ba1d58bede8462cb565baba8ffcc380bf947e317",
"executions": [
{
"trigger": "Application",
"contract": "0x32682404d4313ecf80b70e1323ccf908a80fdfc0",
"vmstate": "HALT, BREAK",
"gas_consumed": "0.039",
"stack": [],
"notifications": [
{
"contract": "0xaeccdcf6d7ecf827e7e6baec3c233eca08c27ee3",
"state": {
"type": "Array",
"value": [
{
"type": "ByteArray",
"value": "010203"
},
{
"type": "ByteArray",
"value": "04090d"
}
]
}
}
]
}
]
}
}
]
There’s a chapter Unit Testing introduced in the official document, but the examples there still require compiling and/or deployment of the .avm in advance.
My team norchain.io felt this limitation strongly when we were developing the NEO-based blockchain game CarryBattle. With the community’s help, we started to try a 4-phase workflow, with increased the development efficiency quite a lot.
2. Four-Phase Workflow
The four phases of this workflow are Editing, Debugging, Private Testing and Beta Testing. The major ideas are:
- Utilizing some new tools to separate Coding phase into Editing and Debugging. In the debugging phase, we step over or run the local test cases like conventional software projects as much as possible, without interaction with blockchain.
- Divide the Testing phase to Private Testing and Beta Testing, using privateNet/NeoCompiler Eco for private testing and public testNets for beta testing respectively. With this approach we can best ensure the flexibility and compatibility with minimum effort.
For the editing and debugging phases, I recommend two approaches: Neo-Debugger and Neunity.
Neo-Debugger
The project of Neo-Debugger is developed by Relfos. With the special version of Neon and the debug json file, you can write the invocation level test cases and run the source code step by step in the IDE, tracking the GAS usage and application logs without interacting blockchain. Another nice feature of Neo-Debugger is that it can step over the OpCode while check the stack. Nikolaj-K has a video tutorial for Neo-Debugger.
Fabio also did nice project SCTracker with similar idea, but he decided to skip when he knew the existence of Neo-Debugger. But still thank him for the contribution.
Neunity.Adapter
Neo-Debugger did a great job with NeoVM level debugging, however it still has some limitations. For examples, it does no yet support variable monitoring, breakpoints, or function level test cases.
The Adapter layer of the framework Neunity created by Norchain.io is taking a different way of local debugging. The idea of Neunity.Adapter is:
- Introduce an adapter layer to isolate the differences between NeoVM and normal .Net projects. We have two adapters Neunity.Adapter.NEO and Neunity.Adapter.Unity with the same set of function signatures while different namespaces and implementations. They are used for NEO smart contracts and Unity projects (actually also applicable for many other .Net projects), respectively. Most of these functions are about the type conversions, operators or system call emulations.
- Then we can write the application logic above adapter layer. Obviously, by simply alter the namespace, this application logic can be used by either smart contract or a normal .Net projects.
- Now we can use function level test-driven development(TDD), and even share the logic with C# Dapp client.
I have a Video Tutorial to demonstrate how to use Neunity.Adapter to do the function level TDD, do step over tests with variable monitors and call stacks.
As compared with below table, we can see the advantages of Neo-Debugger and Neunity.Adapter, respectively. In our experience, Neo-Debugger is more suitable for smaller scale projects as it consumes zero GAS overhead, while Neunity.Adapter is more suitable for larger scale or more complex projects as it better supports TDD, multiple classes, breakpoints, variable tracking, etc.
The design of Neunity practises the large scale software project methodologies (I mean the scale of the system logic. Does not mean the single invocation has to be complex or expensive). That’s why filling the gap between .Net developers and NEO developers by the adapter layer takes the important first step. At meanwhile, Neunity also provides a Neunity.Tools layer with the flexible serialization(NuSD), HTTP-like communication protocol(NuTP), URI-like storage management (NuIO), etc. We hope the effort to assist more NEO blockchain Dapps come to be practical for landing.
Private Testing
After complete the logic by iterating Coding and Debugging phases, we can move to the private Testing Phase and start interacting with blockchain. We suggest to use private testNet or NeoCompiler Eco for private testing, since their environment are simple and easy to interact and manage.
The public testNet of NeoCompiler Eco developed by NeoResearch is new and special. It doesn’t require applying GAS while provides a whole gamut of web-based GUI tools, including compiling, import opcode, deployment, invocations, transactions, conversion, etc. NeoResearch also recently integrated gitter.im for instant chatting to better communicate with developers. Igor has a nice tutorial to go through its basic functionalities.
Another nice thing of this testNet is that the blocks are generated every 5–7 seconds, almost 5 times faster than normal. It shortens the waiting time and you can barely collide with other developers’ invocations in the same block, which makes the test almost as simple as private testnets. That’s why we suggestion to consider it as a private testing option.
Beta Testing
If successfully tested all the functionalities in the phase private testing, we can move to the last phase before give the Dapp live. The public test nets are the best place for beta testing, since it’s close to the mainNet. Another good thing is that you can also invite your friends to help test from their end. Your smart contract should stand still for the challenge from parallel invocations and potential blind or invalid inputs.
Summary
NEO has many advantages comparing with many other public blockchain projects: such as high transaction speed, relatively friendly development languages (C#, Python), international and active community atmosphere.
To improve the development workflow would help enhance NEO’s language advantage, and synergy the sparkling ideas into live projects without spending too much time in resolving trivial issues.
Hope this tutorial can provide two cents from my limited knowledge. Thanks Fabio and Relfos for help on this tutorial. Welcome for any suggestions and comments.