The Apriorit team always tries to stay on top of the latest industry trends. While blockchain technology is at the peak of popularity, our developers are diving deep into the creation of blockchain-based applications. In this article, we want to share our experience in developing smart contracts for application licensing via blockchain.
In addition to cryptocurrency, the blockchain is used for security, smart contracts, and record keeping. In this article, we describe how the blockchain can be applied to build a licensing system for an application. We decided to use Ethereum as the decentralized platform for creating our smart contract. A smart contract, which is an application, runs exactly as it’s written without any possibility of changing it. Using smart contracts for software licensing allows tracking the ownership of the license and moving its value around. We’ll go through the whole development process step by step and finally analyze the result.
The traditional approach to licensing involves a web service and some central database server that stores information about licenses and users. When an application first starts, the user has to activate the license somehow (either by entering a login and password or some generated key) and then the application contacts the server to verify the license.
It’s obvious that a problem can arise in case something happens to the database that stores all the information. Of course, the database can be replicated and then easily restored, but things can get worse if an attacker modifies some data.
So let’s see what we get if we replace the central database with decentralized storage.
This approach differs in that the information about all issued licenses is stored in the form of blocks in a blockchain. Since the database is decentralized, it’s not so easy to harm the data. Using a blockchain also eliminates the risk of data tampering, as a blockchain can’t be modified.
The whole process of getting and activating licenses should generally look the same for the end user. Though the internal architecture differs due to integration with a decentralized ledger, all the additional steps for interacting with the blockchain are performed behind the scenes.
The interaction with the distributed database is performed through the interface of a smart contract. An entity token or license token is used to represent the instance of the license.
We can also consider another architecture option that eliminates the necessity for an intermediate web service and is based on direct communication between the application and the blockchain network.
The benefit of such a solution is that the license data is saved directly to the distributed ledger. Therefore, fewer components handle the data and work with the blockchain.
However, this approach assumes that the user has some Ether on their account in order to purchase the license. The application also needs to have credentials of the account owner in order to send transactions to the blockchain.
We’ll focus on the first approach involving a web service and a distributed ledger. Now let’s analyze the licensing process and its integration with the blockchain.
A blockchain-based license is generally purchased on the product website. After purchasing a license, the user receives an activation key. This key is a unique ID of the license token. The license token is transferred to the user’s Ethereum account.
So to prove that the user has purchased a license, their Ethereum account should contain one token on its balance.
In order to activate a license, the user enters the activation key into the application. Under the hood, the application sends a transaction to the blockchain to mark this license as active using the unique identifier of the transaction. If the transaction succeeds, the license is activated. During activation, the token is bound to the unique identifier of the device in order to prevent the same license from being used on several devices. Moreover, according to the smart contract’s logic, the token can be activated just once to prevent reusing the same token several times.
After a license has been activated, the application needs to periodically verify that the license is still valid and hasn’t expired. If the license has already expired, the token is marked as expired and is no longer valid.
Now let’s dive into the technical details of how to implement such a smart contract. Before we start, let’s specify what technologies are used.
For smart contracts:
- Solidity and the Ethereum platform
- Truffle framework for compilation and local testing
- Ethereum Wallet to deploy contracts to the Rinkeby network
For the target application that’s licensed:
- JSON RPC
We’ll need a smart contract for creating and managing the token entity. Since the license token should be non-fungible, we’re going to create our contract in compliance with the ERC-721 standard.
The LicenseToken smart contract holds a list of tokens together with information about the user account balance. Each token is an instance of the LicenseInfo structure, which includes the following information:
- licenseType — type of the license
- registeredOn — date and time when the token was created
- expiresOn — date and time when the token expires (this field is set during token activation)
- state — state of the license (inactive, active, or expired)
- deviceId — unique identifier of the device (e.g. computer) to which the license is bound
The LicenseToken smart contract implements the required functions of the ERC-721 standard, namely:
We didn’t implement several functions because their functionality is beyond the licensing logic.
In addition to the functions mandatory for ERC-721, the contract also provides several methods that contain licensing business logic:
- giveLicense — creates a new token and transfers it to the account of the user who purchased the license
- activate — updates the token to mark it as activated (also sets the expiresOn field to track the lifetime of the license)
- isLicenseActive — checks the current state of the license token for the given token ID
- handleExpiredLicense — updates the state of the license token in case isLicenseActive has detected that the license is expired
The whole token contract looks as follows:
5 Security Tips for Writing Smart Contracts
Since smart contracts are deployed to a decentralized system, it’s crucial to take measures to secure them and limit permissions. Otherwise, any user of the Ethereum network could manage application licenses.
We need to be sure that only the owner of the smart contract can
- transfer tokens;
- give licenses;
- activate licenses.
The owner of the contract can be the account from which the contract has been deployed to the network.
In the code of a smart contract, we can access the address (account) that called the contract method. This can be done with the help of the global variable msg.sender. The concept is to save this address in the constructor of the contract and require certain methods to confirm that the current caller is the owner. As a result, all attempts to execute methods from an account other than the owner’s will fail.
There’s something like a template contract from the Ethereum documentation — owned — that provides this functionality and can be used as the base contract.
Since a smart contract should be deployed to the blockchain network to run, debugging and testing is a little bit complicated. Nevertheless, in order to check that our smart contract works as expected, we can test it with auto tests using the Truffle framework. This is a good way to emulate real cases in order to reveal bugs prior to deploying our smart contract to the main or test networks, since Truffle uses an in-memory blockchain. Moreover, Truffle provides ten test accounts with some Ether on them that can be used for testing.
To make the application able to interact with a distributed database, we should have already deployed our smart contracts to the blockchain network. Since we need to activate the license and check whether it’s active within the target application, it’s necessary to have a way to interact with the contacts.
Ethereum provides the JSON RPC API, which can be used to call smart contracts. The Infura API can be used too. It’s like a wrapper over the JSON RPC API that provides additional scalability and security.
JSON RPC can be called either directly using cURL or using some wrapper libraries depending on the language and technology.
We won’t dive deep into the details of using JSON RPC, which can be found in the Ethereum documentation and may differ depending on the platform used by the target application. Instead, we’ll focus on the main concepts of practical use of this API.
Generally, JSON RPC provides two ways of calling smart contract methods: via sending transactions or via calls.
Here’s a small comparison of these methods:
- Transactions can be sent using the eth_sendTransaction or eth_sendRawTransaction method.
- Each transaction consumes gas (the Ethereum fee for operation execution).
- Each transaction results in creating a new block in the chain and therefore changes the state of the contract data (e.g. it modifies the value of the internal variables).
- It takes some time to confirm each transaction.
- Sending a transaction requires signing or unlocking the account.
- Calls can be sent using eth_call.
- A call doesn’t consume gas.
- A call doesn’t produce a new block, and as a result doesn’t change the state of the data (e.g. if you transfer some amount of tokens from one account to another using eth_call, the balance of both accounts will remain the same).
- Calls are executed almost immediately since they don’t require any confirmation.
As you can see, there are significant differences in the use of transactions and calls that should be taken into consideration.
In the case of application licensing, we can go with the following scheme:
- Methods like giveLicense, activate, and handleExpiredLicense should be definitely executed as transactions since they involve token transfers.
- The isLicenseActive method can be executed as a call since it just verifies the license state.
Taking into account this scheme, we should also consider the time necessary to process and confirm transactions for the application UI/UX.
Transactions should be signed prior to sending to the blockchain, and there are a couple of ways to achieve this:
- A transaction can be signed with the private key on the application side and then sent via the eth_sendRawTransaction method.
- The account from which the transactions are sent can be unlocked with the pass code using the personal.unlockAccount method. After that, the transaction can be sent via the eth_sendTransaction method without any prior signing.
By “the account” we mean the account of the contract owner who’s allowed to execute the contract’s methods.
For authentication needs, the application has to keep either the private key or the password inside it, which is a potential security hole. As an alternative, the application can send requests to the web service that will then send transactions to the blockchain. So it’s necessary to take additional measures to secure the user authentication.
We’ve analyzed the approach to building application licensing on the basis of blockchain technology. We think that the blockchain can be considered an alternative to the traditional licensing approach since it provides the following advantages:
- Data is protected against modification and tampering.
- Data is stored decentrally, so damage to the central database server isn’t an issue. As with any approach, though, it also has some issues:
- Smart contracts should be properly designed and secured to eliminate the possibility of attacks.
- Interaction with a blockchain from the application can impact the UX due to additional time for transaction confirmation.
Which approach to use depends on application specifics and licensing system requirements.
We hope this article was helpful for developers who want to leverage blockchain technology for their needs. The Apriorit team has expertise in developing blockchain-based applications for various purposes. Contact us if you’re interested in adding smart contracts to your software.