Blockchain payments are still nascent, so there are gaps in understanding how these solutions work technically. To fill these gaps, we at Itransition’s Blockchain Center of Excellence got together to figure out an approach to solving the practical implementation issues with these types of applications.
Our R&D project consisted in elaborating a process of identifying and mitigating potential problems of building blockchain apps, as well as observing limitations in different conditions and environments, such as Windows and Linux.
On this project, we encountered difficulties in the following areas of development:
In this article, we discuss these problems and the ways we resolved them. We also make a conclusion about the practical value of using Hyperledger Fabric for blockchain application development.
The team consisted of four blockchain developers. The project’s goal was to integrate a transparent comprehensive blockchain-based donation system with the online payment platform Stripe. Using the application, users could exchange fiat money into tokens and donate them to charity organizations. This would eliminate potential fraud, mistrust and corruption thanks to the transparency of blockchain tech.
In Docker, all containers are added to a default network. Hyperledger Fabric creates a separate container for each chaincode instance. These containers are added to an isolated network based on system configurations. We don’t control the container where the chaincode runs as it is controlled by the peer.
Our network name did not match the chaincode container network name. One misnamed environment variable (COMPOSE_PROJECT_NAME) lifted this container for chaincode execution in a different network. When we tried to instantiate the contract, the process crashed by timeout, without any error descriptions.
We gave the right name to the network by setting the correct value of environment variable COMPOSE_PROJECT_NAME. That way, peers could communicate well with chaincode containers (aka smart contracts).
Debugging smart contracts is hard. This happens for two reasons: we write code essentially in the dark; all contract methods are called by peers.
We loaded the contract in the development mode and manually debugged it. Because Node.js is dynamically typed, it was impossible to fix some errors before we instantiated the contract.
We decided to rewrite the contract in Go instead of Node.js to facilitate debugging and discovering hidden errors.
In Go, there were no issues with instantiating contracts. During the compilation stage, we had crashes yet were able to fix them without instantiating the contract on the peer.
There was no need to download a bunch of NPM packages in Go, as opposed to Node.js, during contract instantiation. As a result, the contract instantiated much faster than in Node.js. The process of installation and instantiating the contract took 10-15 seconds in Go compared to 2-3 minutes in Node.js.
There was a problem with copying certificate files with long paths, which is a typical Docker issue in a Windows environment. When we copied such files inside the Docker container, the copying process ended abruptly for no clear reason.
We defined Docker volumes to store such files and then copied those files when Docker Compose was running. Also, we added these directories to .dockerignore.
One of the tasks was to generate a list of all donations by a particular user or a list of all donations given to one of the featured organizations.
At first, our team thought it possible to address Hyperledger directly and read the necessary transactions from blocks so that we could filter them based on certain criteria. However, there was an issue: we could only read one block at a time.
Therefore, in order to read the entire history of transactions, it was necessary to request every block in the chain. Each block contains transaction IDs. An Endpoint for fetching all transactions from a block or several blocks doesn’t exist in the Fabric Rest API. We had to fetch each transaction one after another. To read 100 blocks containing 100 transactions, each would require 10,000 requests to the API.
We initially stored only the user’s balance (number of tokens) in the State database. Since we wanted to enable reading transaction history, we started saving all the additional information about transactions in the State database. This information included the last received transaction and balance changes. Balance changes included information on the number of tokens or, in case of a donation, the sum of the donation and the receiving organization. For the organization, we stored the donator’s information and the sum of the donation.
Because of keeping the last transaction, we managed to enable fetching the history with the GetHistoryForKey function of the shim package. We did it by keeping track of the transactions transferred by the system while the balance was changing.
Some developers used Linux, and some used Windows (due to the corporate policy or for another reason). In the latter case, there is a problem. When you install gRPC on a Windows machine, it will not work if the rest of the infrastructure is tailored to Linux.
To solve this rather typical issues, we had to assemble the module manually to work on Windows.
When our application’s users want to top up their balance, it can be done through Stripe.
The system launches the smart contract that in turn initiates the money transfer from the platform’s wallet to the user’s wallet. Via a separate contract, the user donates the money to an organizations’ wallet.
As soon as the payment system places the payment, it is to notify our system if the payment processing is successful or not. Unsuccessful payments happen because of insufficient funds, for example.
In the development environment, it was impossible to receive requests from Stripe. This was purely a development problem, as we didn’t have this issue during staging.
To solve this issue, we used ngrok to send the answer from Stripe to local developer machines.
It worked in the following way: ngrok creates a special tunnel, which gives us an ngrok account that Stripe can notify. In its turn, ngork notifies our team through its own address.
Online search or professional Hyperledger Fabric communities contained very little information, in addition to rather limited technical documents of the platform itself. So when there were questions, the team found no answers to them. The existing documentation was insufficient to resolve our issues.
The team had to study the source code and rely on the information provided on the platform’s official website. In the course of our project, we were creating detailed instructions for future teams to compensate for the lack of source information.
When considering platforms for implementing blockchain payments and integrating Stripe, our team researched both Ethereum and Hyperledger (Sawtooth and Fabric) as viable options.
While Ethereum boasts advantages like a wide community and plenty of available documentation, it serves original blockchain infrastructures for creating wallets, cryptocurrencies, and crypto payments. Also, there is a base guest price for deployment. For this particular project, Ethereum did not fully meet the business requirements. It wasn’t looking great in terms of medium- and long-term support either.
The team chose Hyperledger as the platform was specifically created for developing business-oriented blockchain solutions with future-proof features like the possibility of rapid growth and easy scalability. Besides, we felt the financial advantage of cost free deployment.
Our team also compared Fabric against Sawtooth.
Sawtooth had solid features for developing blockchain payment systems with a slightly different consensus model than Fabric. But the tool had no analogs for chaincode (essentially the synonym for smart contract development and integration in Fabric), which was the main deciding factor for us.
Additionally, Fabric looked like a more viable option because of its out the box advantages. These include flexibility, full decentralization, and impressive update and support features, which were all important for further development.
Also, to provide an ordering service to the blockchain network, Hyperledger Fabric uses Apache Kafka, proven to be easy to scale and very powerful. To top it all, we found the key-value state database embedded in the peer process, the State database (CouchDB and LevelDB), which is easily scalable, particularly when it comes to CouchDB.
Business-wise, the team is glad that its predictions about Hyperledger Fabric proved to be true, having seen the advantages of scalability, fast growth, and cost-effectiveness in action.