Intro

This a second part of the seria of publications regarding work on the Swap project. It covers a test coverage of smart contracts.

Test coverage options

Over the Remix

Ethereum dev team provides its own IDE called Remix. Besides many others things it allows to quickly deploy and run smart contracts. It has convenient UI which provides a set of a smart contract methods to interact with.

Remix functionality might be a good option to quickly verify a correctness of just developed contract without many extra dependencies.

However, it has several limitations where two major ones are lack of logs and unclear error messages from the ledger.

Over an another smart contract

There is another interesting way to test smart contracts by implementing another contract which will act as a robot which invokes another contract interface methods and verify the result.

It is something I have met during my research. It still has its place in the Ethereum test world. Despite on I picked up the Hardhat, I use this approach too to verify things which are easier to do on the contract layer.

Over the Hardhat

Hardhat is a development environment for Ethereum software. . By being integrated into Visual Studio Code IDE it covers all my current demands to the ethereum dev environment including clear error messages from the ledger.

Hardhat runs code on its own locally deployed network which allows to quickly deploy, execute and test contracts.

Deployment:

                describe("Swap value suite", async function() {

                    async function deploy() {
                        const factory = await ethers.getContractFactory("SwapValue");
                        const contract = await factory.deploy();
                
                        const utilsFactory = await ethers.getContractFactory("Utils");
                        const contractUtils = await utilsFactory.deploy();
                        return { contract, contractUtils };
                    }

                    // the rest test methods 
                })
            


Test case:
                it("On emit new tokens balance of user changes", async function() {
                    const accounts = await ethers.getSigners();
                    const owner = accounts[0].address;
                    const user1 = accounts[1].address;
                    const { contract } = await loadFixture(deploy);
                    await expect(await contract.balanceOf(owner)).to.be.equal(0);
            
                    // {value: ethers.utils.parseEther("0.123") }
                    const customMetadata = { 
                        _offer : "Software development for Android.", 
                        _availableSince: 0,
                        _availabilityEnd: 0,
                        _isConsumed: false,
                        _lockedUntil: 1000 
                    };
                    await contract.safeMint(owner, customMetadata, "https://gelassen.github.io/blog/");
            
                    await expect(await contract.balanceOf(owner)).to.be.equal(1);
                });
            

Over web3j on the mobile client

The test coverage on the mobile client (and server side) is done as a part of integration tests.

Testnets

After automating tests locally, it is still important to verify code on the production chain. The Ethereum team & the community provides special testnets for such purposes.

After the Merge event which has been happened in the middle of autumn in 2022, only two testnets are left alive.

My experience with Sepolia testnet is negative, they had some issue they promised to solve after 5th of october 2022, but even later later I still experience with some issues.

After that the Goerly became is the only option left for tests, but unexpectedly it became very slow.
Web3j has a time threshold of 10 minutes. Goerly testnet increases time to mint a token - receive a receipt. It was near a minute on 10th of October, 4 hours 5 days later and 10.5 hours on 27th of October

Not sure about exact cause of such changes in the testnet, but it made further development quite slow and painful. After research I decided to move to deploy own private network to continue development. It was good because from business perspective I also made a pivot to launch product on a private chain as it had been shown in the previous publication of this seria.

Private chain

At the moment of writing Ethereum offers Mainnet and two test nets: Sepolia and Goerli. A bunch of tools, e.g. hardhat, provides local development testnet. However, deploying your own testnet on your machine or VMs is out of scope in the official documentation.

There is a collection of available public testnets https://chainlist.org/.

Ethereum official repository provides source code for chain and such tool as puppeth for a quick configuration of the private chain.

1. Create folders for nodes

2. Create accounts in nodes (we will need to remember address of the key and secret key by itself):

                $geth --datadir ./node1/data account new 
$geth --datadir ./node2/data account new
$geth --datadir ./node3/data account new


3. Generate genesis block (the main configuration file):
                $puppeth    
            


4. Export chain configuration:
                $puppeth (reselect option 2. Manage existing genesis)
            


5. Initialize all nodes with chain config:
                $geth --datadir ./node1/data init .json 
$geth --datadir ./node2/data init .json
$geth --datadir ./node3/data init .json


6. Start nodes:
                $geth --datadir ./node1/data --port 2001 (default authrpc.port 8551) 
$geth --datadir ./node2/data --port 2002 --authrpc.port 8552
$geth --datadir ./node3/data --port 2003 --authrpc.port 8553


7. Link all nodes with a main one:
                $geth attach ipc:node1/data/geth.ipc 
$admin.nodeInfo.enode
(reply would be something similar to "enode://64dccd02d5d1166cfb4913f0d0c164dff2b9c61fd55182461010569e15319c7ff5cb4dc8b502e441c38c80ae1b42c2cc95c7e170ed973bb0353d766669c5447c@195.178.22.21:2001?discport=39805")
$geth attach ipc:node2/data/geth.ipc
$admin.addPeer(enode://64dccd02d5d1166cfb4913f0d0c164dff2b9c61fd55182461010569e15319c7ff5cb4dc8b502e441c38c80ae1b42c2cc95c7e170ed973bb0353d766669c5447c@127.0.0.1:2001")


Repeat for all nodes: each node should have reference in peers on all OTHERS nodes. Known issue: https://github.com/ethereum/go-ethereum/issues

8. To make node as a miner:
                $geth attach ipc:node3/data/geth.ipc 
$personal.unlockAccount()
$miner.setEtherbase()
$miner.start()
$miner.stop()
$eth.getBalance(eth.accounts[0])

What is next

This publication covers options to cover by tests ethereum smart contracts, a recent state with testnets, a way to deploy private network.

Automation tests strategy is to cover all general workflows, important corner cases plus 'test per found bug'.

For more details you could check the source code. Part 1 of this seria is available by link. Next publications in this seria will cover backend & frontend and their test coverage, project deployment automatization.