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 testNets). 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 accelerate 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 very 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 clear details about this workflow.
For the coding phase, NEO officially supports C# (examples HERE). We can also develop the smart contract with Java and Python. You can easily find pages of tutorials and sample codes to tell how to code NEO smart contracts on Google and Youtube, so I would bypass this part in this tutorial.
We rely on testNets to do the testing phase. As shown in the above figure, we have many choices for the test nets.
The most common approach is to use the 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 testNet 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. But if the testNet is empowered by Neo-Scan, you can call similar services instead without running nodes. 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 testNet(or Neo-Scan) domains to play with it.
NeoCompiler Eco has a new and special public testnet which inspired us move to the four-phase workflow. We’ll talk about it more in the next chapter.
Another good approach is to set up your own private testNet. Comparing with the public testNets, private testNets’ advantage is that you can take fully control. The first reason for using private testNets is that it’s really helpful and encouraging with the illusion of holding millions of NEO and GAS in the wallet. At meanwhile, comparing with public testNets, 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 privateNet 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 testnet on your local machine, while saves your time from tons of configuration and instructions. If you run it on laptop, it’s also helpful to keep your body temperature in Canadian winter.
The limitation of the 2-phase workflow
This 2-phase workflow is mature and is adopted by the majority of existing projects. Nevertheless, it has some limitations comparing with conventional software projects. The major one is that the debugging is really costly. To monitor variables’ runtime values, the best choice is to use runtime notification as shown in the following snippet:
byte ba0 = CallSomeFunction();
byte ba1 = CallAnotherFunction();
//Print out the value of ba0 and ba1 to ApplicationhLog
Even in the happy path, we need to recompile the project with neon, then ensure enough GAS and do the redeployment, then compose the proper parameters with correct format, then invoke it and wait for 20 –30 seconds for the next block, then call the API getapplicationlog to fetch the log in JSON, then print the response with pretty format to find the log values (check the highlighted part in the following sample). The log values are usually expressed as byte arrays so we also need to convert them back to String or BigInteger… Altogether 7 steps.
"vmstate": "HALT, BREAK",
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.
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.
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.
- 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.
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.
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 testNets 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.
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.