Though a blockchain is just a distributed ledger with an immutable chain of data, blockchains can be successfully implemented in various business spheres. Theyโre helpful if you need to keep track of records or make them unchangeable. And peer-to-peer networks allow you to restore information in case of data loss.
On the other hand, using one of the most popular public blockchain networks for your company isnโt really safe, because your sensitive data will be accessible to everyone. Also, a public blockchain can simply lack some functionality needed for your business needs.
The Graphene framework speeds up the design of custom blockchain networks while enabling to implement your business logic. In this article, one of our Apriorit blockchain experts shares his experience creating a custom blockchain network using the Graphene framework.
Contents
- Pros and cons of a private blockchain network
- Developing your own blockchain vs customizing an existing solution
- The Graphene framework
- The smart contract module in Graphene
- Further modification of the Graphene network
- Performing a network update
- Example using the Graphene framework
- Adding a data structure
- Defining the operations
- Accessing the operations
- Building the node
- Deploying and setting up the network
- Consensus algorithm
- Conclusion
- Resources
Pros and cons of a private blockchain network
A blockchain network can meet the requirements of various kinds of businesses. Here are some examples of how blockchain networks can be applied for different business purposes:
- Logistics โ Keep track of shipments and deliveries
- Client records โ Check and record a clientโs history
- Work management โ Place work orders and track progress
- Finance โ Provide infrastructure for cross-border transactions, accounting, and auditing
With so many public blockchain platforms out there, youโll probably be able to find one that more or less meets your needs. However, there are two things to consider before creating a public blockchain:
- Any data on a public network is accessible to all network members, among which may be unrelated or malicious users. Therefore, you canโt store any sensitive information on a public blockchain.
- Youโll become dependent on the host network. If anything happens to the main network, your application will be vulnerable.
So if privacy and independence are important for your company, a custom blockchain implementation is the obvious choice.
On the other hand, creating and implementing your own blockchain network is a big challenge. Letโs consider two possible ways of creating a blockchain for your business.
Developing your own blockchain vs customizing an existing solution
There are three ways to implement blockchain technology in your business. Letโs look at them:
- Create a custom blockchain network. The main advantage of this approach is that a custom network can meet any and all requirements. Youโll have control over each stage of development, with the ability to implement any changes and business rules you need. On the other hand, creating such a network is not an easy task. Youโll have to develop a consensus algorithm, implement a peer-to-peer network, design communication protocols, and more. This requires a lot of time and effort from your development team and therefore can be quite expensive. On top of that, youโll have to ensure that your network has no bugs and is safe to use.
- Create a private network based on an existing blockchain Almost every mainstream blockchain supports private networks. You can create a copy of the public network in your private environment. This private network will contain only your data and handle your transactions. It will be incompatible with the main network, so external peers wonโt be able to synchronize with the private chain. Deploying your favorite blockchain on a local server and setting up a running network will take just a few hours. The downside of a private network is the lack of customization. Changing some core network properties, such as the consensus mechanism, will require modifying the networkโs source code. Depending on the software architecture, this may be difficult.
- Build a private blockchain on the Graphene framework. This method combines the best features of the two previous approaches. It allows you to make a fully custom blockchain network without researching and developing complex consensus mechanisms and an advanced peer-to-peer networking solution. The Graphene framework provides you with all necessary functionality and makes it easy to create a custom blockchain that suits your own business logic.
The Graphene framework
The Graphene framework is a solution for creating custom blockchain implementations. It contains all the components required for creating a working network. At the same time, Graphene blockchain development leaves room for implementing the business logic your company needs. So this framework is perfect for automating business processes with a blockchain.
Graphene comes pre-packaged with the following components:
- A barebones blockchain implementation with data storage
- An efficient and advanced consensus algorithm
- A complete P2P networking solution with HTTP APIs
- A framework for adding custom functionality
- Elliptic-curve cryptography, hashing, block construction, etc.
Implementing a blockchain using Graphene technology allows you to focus on your business needs without worrying about details of network development. Moreover, the framework is modular. You can easily change any parts. You can do anything from adding custom commands to the command-line interface (CLI) to changing the entire consensus algorithm.
Compared to existing popular blockchain implementations, the basic Graphene framework allows you to build interactions faster thanks to its advanced consensus mechanism.
The blockchain framework uses an algorithm called delegated proof of stake, or DPoS. This algorithm selects trusted delegates (or witnesses), which can produce blocks with no additional mining required. Witnesses are selected by an approval vote. Anyone holding the native network currency can vote for their favorite witness. During each maintenance period in Graphene, these votes are recounted and the top witnesses are selected to create new blocks and maintain the ledger. The witnesses receive a reward for maintaining the ledger. The total number of witnesses and conditions for becoming one can be configured manually. This allows Graphene to work more efficiently than classic proof-of-work (PoW) blockchain networks.
Usually, a witness:
- is a known entity (no anonymous witnesses);
- is trusted by stakeholders;
- has the capacity to run and maintain a full node.
The DPoS consensus is organized so that all witnesses are equal, even if one of them has many more votes. So thereโs no chance for a 51% attack, as in PoW networks.
Smart contracts in Graphene blockchain technology are tied to the network itself. This improves scalability and performance. And while itโs less flexible than other solutions (such as EOS and Ethereum), the business logic of an existing network still can be updated or changed with Graphene.
Graphene is the basis for several known blockchain networks:
- BitShares
- Steem
- Peerplays
- BitEthereum
- Smoke
- Scorum
Each of these networks introduces some specialized functionality on top of the Graphene core. For example, EOS adds support for advanced smart contracts. Steem adds media tokens and other smart assets.
The most famous of these networks is BitShares. It inherits all the benefits of Graphene, such as speed and scalability, and adds many features including price-stable cryptocurrencies (smart coins), decentralized asset exchange, and automatic recurring payments.
These examples show just how customizable Graphene is.
Read also:
Custom Accounting Software Development: Core Characteristics, Architectural Components, and Features
The smart contract module in Graphene
Graphene doesnโt have smart contracts in the usual sense. Instead, all of your business logic is embedded in the network. In other words, in order to create a smart contract, we need to modify the Graphene source code.
A Graphene blockchain implementation allows us to easily add custom actions to the network. An action or an operation in Graphene is just a function within the source code with several additional requirements:
- The operation arguments must be a struct so that transaction parameters can be stored on the blockchain.
- The operation must have a validate() function that performs a sanity check of the parameters. This function checks if the arguments are well-formed, meaningful, and placed within a predefined range. For example, you may check that a user doesnโt transfer tokens to themselves, since itโs a pointless operation.
- The operation must have an evaluator. The evaluator is the actual brain behind the operation. It contains two functions:
- do_evaluate(), which checks parameters like function validation. This function performs higher-level validations such as, Does the user have enough tokens to transfer? and Has the contract expired? These are more than simple input confirmations; theyโre an actual part of the business logic.
- do_apply(), which applies the necessary changes. For example, it can update the userโs balance, change data stored on the blockchain, etc.
Overall, an operation executes like this:
Groups of such operations form smart contracts on the Graphene platform. Obviously, since these โsmart contractsโ are embedded into the source code, thereโs no easy way to change them once the network is running. However, this approach has two benefits as compared to simply deploying a smart contract on a private network:
- Speed โ The smart contract is compiled into native executable instructions just as the rest of the networkโs code. This way, the smart contract executes as fast as possible, with no additional overhead of a virtual machine (unlike with EVM in Ethereum or WASM in EOS).
- Security โ Removing the ability to add custom smart contracts, Graphene gets rid of one of the major attack vectors.
Further modification of the Graphene network
Once the blockchain network is up, you can continue to adjust it according to your business demands. This is especially useful in case you need to implement a primary feature block as fast as possible and work out the rest in your free time.
There are several ways to expand your network functionality:
- Add more options to access smart contract operations. Adding commands to the CLI will help a lot during testing, and a great GUI will surely attract many users.
- Add more advanced operations to smart contracts. For example, you can add automatic functionality during network maintenance to clean up expired data or update account states.
- Support operations between contracts, for example issuing and accepting payments using custom tokens. And of course, you can refine protocols and improve existing functions.
- Change core functionality of the framework. For example, if all of your block producers can be trusted, you donโt need the advanced consensus mechanism present in Graphene.
Performing a network update
Data on any blockchain network is permanent. If you want to perform an update โ or even add some functionality to your network โ youโll have to perform a hard fork. Blocks added to a chain after the hard fork will be incompatible with the old consensus due to the changes.
As you can see, at a specified point all nodes switch to the modified verification algorithms. Thereโs no actual split. However, since the new blocks are incompatible with the old ones, this is called a hard fork.
A convenient way to implement a similar update in Graphene is to place a hard fork guard around each changed part of the code like this:
FC_ASSERT( db().head_block_time() > HARDFORK_NEW_FEATURE_TIME,
// New code is added after this point
"Operation not allowed before HARDFORK_ NEW_FEATURE _TIME.");
Where HARDFORK_ NEW_FEATURE _TIME is a constant that contains the time when the hard fork should occur.
Example using the Graphene framework
To show you an example of this technology, weโll develop a blockchain on the Graphene framework. Letโs create a network for musicians and producers. In order to keep our example simple, weโll implement only basic business logic, so it might not cover some specific cases.
There are three actors in our example:
- A user buys music with cryptocurrency embedded in our network.
- A producer (or a studio) sells albums to users and makes profit.
- A musician negotiates a contract with a producer in order to release an album.
In this network, a producer creates a contract that includes an estimate and a reward. A musician accepts it and creates an album. If the contract is fulfilled, the musician gets their reward. If not, the producer gets their money back. To keep our network simple, any other activity connected with contracts and music happens off-chain.
Our sample network will provide the following functionality:
- The ability for musicians and producers to safely create contracts:
- Create a contract
- Agree on the terms of the contract
- Complete the contract and distribute rewards
- Handle incomplete and expired contracts
- The ability to sell musical albums and distribute profits according to a contract.
Our blockchain will act as the backend for these operations. The general procedure for creating a music contract looks like this:
Or, if the contract expires, the procedure looks like this:
Selling an album is just as simple as exchanging native cryptocurrency for the album. By default, all profit goes directly to the producer, but this can be configured in the contract and a percentage may be shared with the musician.
All of this functionality is achievable with a smart contract. However, for our purposes, a separate network is required. For example, we may want to attract users by providing free transactions, which is usually impossible with a smart contract on an existing network.
Adding a data structure
Before we start creating operations for our network, we must define what types of data will be available. This data will be stored in the state database on the blockchain.
So the full structure will look like this:
class music_contract_object: public graphene::db::abstract_object < music_contract_object > {
public: static
const uint8_t space_id = implementation_ids;
static
const uint8_t type_id = impl_ music_contract_object_type;
uint32_t contract_id = 10;
account_id_type producer; // the account id of the producer
account_id_type musician; // the account id of the musician
asset amount; // contract amount
time_point_sec ratification_deadline; // deadline till the contract must be signed
time_point_sec contract_expiration; // contract expiration time
asset pending_fee; // fee for creating the contract
bool musician_signed = false; // whether the musician signed the contract
}
To use the defined data structure, we must create a database object index. This index is used just for the storage backend. And then we can register the object with the database like this:
void database::initialize_indexes()
{
. . .
add_index< primary_index<music_contract_index>>();
}
Defining the operations
Weโve already specified operations and validators of our network in previous sections of this article. Letโs introduce the key actors and functionality for creating smart contracts on our network. At this point, we can define it this way:
struct music_contract_create_operation : public base_operation {
struct fee_parameters_type {
uint64_t fee = 1 * GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
account_id_type producer;
account_id_type musician;
asset amount;
uint32_t contract_id=0;
string details;
time_point_sec ratification_deadline;
time_point_sec contract_expiration;
void validate()const {
FC_ASSERT( amount.amount > 0 );
FC_ASSERT( producer != musician );
}
void get_required_active_authorities( flat_set<account_id_type>& a )const{ a.insert(producer); }
account_id_type fee_payer()const { return producer; }
};
We can create other operations with contracts in a similar way. The next step is adding evaluators that check the parameters of a smart contract, such as estimated deadlines and the ability of some network users to act as both musicians and producers:
class contract_create_evaluator : public evaluator< contract_create_evaluator>
{
public:
typedef music_contract_create_operation operation_type;
void_result do_evaluate( const music_contract_create_operation& o );
object_id_type do_apply( const music_contract_create_operation& o );
};
void_result contract_create_evaluator::do_evaluate(const music_contract_create_operation& o)
{
FC_ASSERT( o.ratification_deadline > db().head_block_time() );
FC_ASSERT( o.contract_expiration > db().head_block_time() );
if(o.amount.asset_id == asset_id_type())
FC_ASSERT( db().get_balance( o.producer, o.amount.asset_id ) >= (o.amount + o.fee) );
return void_result();
}
object_id_type contract_create_evaluator::do_apply(const music_contract_create_operation& o)
{
try {
db().adjust_balance( o.producer, -o.amount );
const music_contract_object& ctr = db().create<music_contract_object>([&]( music_contract_object& ctr) {
ctr.contract_id = o.contract_id;
ctr.producer = o.producer;
ctr.musician = o.musician;
ctr.amount = o.amount;
ctr. pending_fee = o.fee;
ctr.ratification_deadline = o.ratification_deadline;
ctr.contract_expiration = o.contract_expiration;
});
return ctr.id;
} FC_CAPTURE_AND_RETHROW( (o) )
}
Now we have a functional smart contract that can check parameters and perform actions accordingly. Unfortunately, thereโs no way to use it from outside the source code. There are two ways you can access the smart contract: using the command-line interface or via the HTTP API. Of course, for a real project you may want to implement both, or even implement a GUI using your smart contract operations directly. For now, a basic HTTP API will be enough to test our operations.
Accessing the operations
Creating a simple API for your smart contract is straightforward. First, we have to define a class that will contain all of the functions accessible via HTTP:
class music_api
{
public:
music_api(graphene::chain::database& db);
~music_api();
/* explain */
optional<music_contract_object> get_contract( account_id_type publisher, uint32_t contract_id ) const;
private:
graphene::chain::database& _db;
};
. . .
optional<music_contract_object> get_contract( account_id_type publisher, uint32_t contract_id ) const
{
optional< music_contract_object > result;
try
{
result = _db.get_contract( publisher, contract_id );
}
catch ( ... ) {}
return result;
}
Then, we have to register the API and its functions using the FC_API macro:
FC_API(graphene::app::music_api,
(get_contract)
. . .
)
Building the node
Now we can move on to building the node executable. The process goes like this:
- Install some necessary libraries and GCC 4.9.
- Download and build Boost 1.57.0 (make sure to use the same compiler version for building Boost, your prototype, and other Graphene parts).
- Compile the executables using make.
Here are some useful tips that can help you avoid mistakes during the build process:
- Use enough RAM. Building a project requires at least 4 GB of RAM. This may be an issue if youโre building on a virtual machine. Donโt forget to allocate enough RAM to the VM beforehand to avoid starting over.
- Create a Docker container for your builds. This allows you to configure the build environment once and use it anywhere.
- Make sure to use the specified versions of the Boost library and GCC. The build process requires precise library versions. Itโs possible to build using newer versions, but this may take a lot of effort.
The GUI wallet is optional and requires building a separate version of the QT Framework, which may take a long time. You can save a lot of time by skipping it during the build process unless you specifically want to develop the GUI wallet.
Deploying and setting up the network
Once you have all the necessary executables, deploying the network is simple. You can start a Graphene witness node by running:
./programs/witness_node/witness_node
You can open RPC to access the node from wallets using the flag:
--rpc-endpoint 127.0.0.1:8090
And to enable block production, you can use the flag:
--enable-stale-production
You can access the witness node directly through HTTP requests using curl, or access it through the included CLI or GUI wallet. However, in order to have your contract operations available as commands in the wallet, you must modify the wallet source code by adding the appropriate calls.
Consensus algorithm
Graphene has a unique consensus algorithm that can receive a special application in our example. In our case, producers and studios fit the description of witnesses. Moreover, we can modify the voting process to include album sales rather than direct votes in order to select top witnesses for block generation.
Note that in terms of a smart contract, thereโs no difference between a producer with a witness node and one without. However, since we control the network, itโs possible to limit the list of producers only to registered customers. Any additional requirements can be made in order for a producer to join the network, including running a witness node.
Conclusion
A blockchain network offers great promise for your business. But existing blockchain networks can be slow and expensive. And with a public network, youโre putting the fate of your business in the hands of outsiders. Creating a custom blockchain allows you to tune this technology according to your business needs.
Building a custom blockchain is difficult and expensive. However, the Graphene framework makes creating a custom blockchain network easier and cheaper.
At Apriorit, we have vast experience developing blockchain-based solutions. We can help you improve your custom blockchain network, perform security testing, or create a new network for your business.