{"id":37868,"date":"2019-10-31T22:20:16","date_gmt":"2019-10-31T19:20:16","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blokchejn-chto-nam-stoit-poc-postroit\/"},"modified":"2019-10-31T22:20:16","modified_gmt":"2019-10-31T19:20:16","slug":"blokchejn-chto-nam-stoit-poc-postroit","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/blokchejn-chto-nam-stoit-poc-postroit","title":{"rendered":"Blockchain: what does it cost us to build PoC?","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><i>Eyes are scared, but hands are itching!<\/i><\/p>\n<p>In previous articles, we explored the technologies on which blockchains are built (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/443282\/\">What will it take to build blockchain?<\/a><\/noindex>) and the cases that can be implemented using them (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/449986\/\">What does it take to build a case?<\/a><\/noindex>). It\u2019s time to get hands-on! For implementing pilots and Proof of Concepts (PoC), I prefer to use cloud services because they can be accessed from anywhere in the world and often save time on tedious environment setup, as there are pre-installed configurations. So, let\u2019s create something simple, like a network for transferring coins between participants, and we will modestly name it Citcoin. We will use IBM Cloud and the universal blockchain Hyperledger Fabric for this. First, let\u2019s understand why Hyperledger Fabric is called a universal blockchain?<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/c19278d99d5b7edb9f50ea6306c2fd46.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Hyperledger Fabric \u2014 Universal Blockchain<\/h2>\n<p>\nGenerally speaking, a universal information system consists of:<\/p>\n<ul>\n<li>A set of servers and a software core that executes business logic;<\/li>\n<li>Interfaces for interacting with the system;<\/li>\n<li>Tools for registering, authenticating and authorizing devices\/individuals;<\/li>\n<li>A database that stores operational and archival data:<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/f11fe73de54b0573d44fae903d367df9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nYou can read the official definition of Hyperledger Fabric at <noindex><a rel=\"nofollow\" href=\"https:\/\/www.hyperledger.org\">the website<\/a><\/noindex>, and in short, Hyperledger Fabric is an open-source platform that allows building private blockchains and executing arbitrary smart contracts written in JS and Go programming languages. Let\u2019s take a detailed look at the architecture of Hyperledger Fabric and verify that it is a versatile system, with only specific ways of storing and recording data. The specifics are that data, like in all blockchains, is stored in blocks, which are added to the blockchain only if participants reach a consensus, and once recorded, the data cannot be altered or deleted unnoticed.<\/p>\n<h2>Architecture of Hyperledger Fabric<\/h2>\n<p>\nThe diagram presents the architecture of Hyperledger Fabric:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/7488d70b330af2bbae1db67005f22a3e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>Organizations <\/b> \u2014 organizations contain peers, thus the blockchain exists with the support of organizations. Different organizations can join the same channel.<\/p>\n<p><b>Channel <\/b> \u2014 a logical structure that groups peers together, thereby defining the blockchain. Hyperledger Fabric can handle multiple blockchains simultaneously with different business logic.<\/p>\n<p><b>Membership Services Provider (MSP)<\/b> \u2014 is the Certificate Authority (CA) for issuing identities and assigning roles. To create a node, one needs to interact with the MSP.<\/p>\n<p><b>Peer Nodes<\/b> \u2014 verify transactions, store the blockchain, execute smart contracts, and interact with applications. Peers have an identity (digital certificate) issued by the MSP. Unlike the Bitcoin or Ethereum networks, where all nodes are equal, in Hyperledger Fabric, nodes play different roles:<\/p>\n<ul>\n<li>Peer can be <b>endorsing peer<\/b> (EP) and execute smart contracts.<\/li>\n<li><b>Committing peer<\/b> (CP) \u2014 only saves data in the blockchain and updates the 'World state'.<\/li>\n<li><b>Anchor Peer<\/b> (AP) \u2014 if multiple organizations participate in the blockchain, anchor peers are used to connect them. Each organization must have one or more anchor peers. Through AP, any peer in the organization can obtain information about all peers in other organizations. The gossip protocol is used to synchronize information between AP. <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gossip_protocol\">gossip protocol<\/a><\/noindex>.<\/li>\n<li><b>Leader Peer<\/b> \u2014 if an organization has several peers, only the leader peer will receive blocks from the Ordering service and distribute them to other peers. The leader can be set statically or dynamically chosen by the peers in the organization. The gossip protocol is also used to synchronize information about leaders.<\/li>\n<\/ul>\n<p>\n<b>Assets <\/b> \u2014 entities of value that are stored in the blockchain. More specifically, these are key-value data in JSON format. It is these data that are recorded in the 'Blockchain'. They have a history stored in the blockchain and a current state stored in the 'World state'. Data structures are filled randomly depending on business needs. There are no mandatory fields; the only recommendation is that assets should have an owner and represent value. <\/p>\n<p><b>Ledger <\/b> \u2014 consists of the 'Blockchain' and the 'World state' database, which stores the current state of assets. World state uses LevelDB or CouchDB.<\/p>\n<p><b>Smart contract<\/b> \u2014 the business logic of the system is implemented through smart contracts. In Hyperledger Fabric, smart contracts are called chaincode. Chaincode defines assets and transactions over them. Technically speaking, smart contracts are software modules implemented in programming languages like JS or Go.<\/p>\n<p><b>Endorsement policy<\/b> \u2014 for each chaincode, you can set policies on how many and from whom confirmations are needed for a transaction. If no policy is specified, the default is: \u201cthe transaction must be confirmed by any member of any organization in the channel\u201d. Examples of policies:<\/p>\n<ul>\n<li>The transaction must be confirmed by any administrator of the organization;<\/li>\n<li>Any member or client of the organization must confirm it;<\/li>\n<li>Any peer of the organization must confirm it.<\/li>\n<\/ul>\n<p>\n<b>Ordering service<\/b> \u2014 packages transactions into blocks and sends them to peers in the channel. Ensures message delivery to all peers in the network. For industrial systems, it uses <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Apache_Kafka\">the Kafka message broker<\/a><\/noindex>, for development and testing <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/hyperledger\/fabric\/tree\/master\/orderer\/consensus\/solo\">Solo<\/a><\/noindex>.<\/p>\n<h2>CallFlow<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/9060864bd1002da881d7f17ef8ec0b0c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>The application interacts with Hyperledger Fabric using Go, Node.js, or Java SDK;<\/li>\n<li>The client creates a transaction tx and sends it to the endorsing peers;<\/li>\n<li>The peer checks the client's signature, executes the transaction, and sends the endorsement signature back to the client. Chaincode is executed only on endorsing peers, and the result of its execution is distributed to all peers. This algorithm is called \u2014 PBFT (Practical Byzantine Fault Tolerant) consensus. It differs from <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Byzantine_fault\">classical BFT<\/a><\/noindex> in that messages are sent and confirmation is expected not from all participants, but only from a specific set;<\/li>\n<li>After the client receives a number of responses meeting the endorsement policy, it sends the transaction to the Ordering service;<\/li>\n<li>The Ordering service forms a block and sends it to all committing peers. The Ordering service ensures the sequential recording of blocks, which eliminates the so-called ledger fork (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/443282\/\">see the section 'Forks'<\/a><\/noindex>);<\/li>\n<li>Peers receive the block, recheck the endorsement policy, write the block to the blockchain, and change the state in the 'World state' DB.<\/li>\n<\/ul>\n<p>\nThat is, there is a division of roles among nodes. This ensures scalability and security of the blockchain:<\/p>\n<ul>\n<li>Smart contracts (chaincode) are executed by endorsing peers. This ensures the confidentiality of smart contracts, as they are not stored by all participants, but only by the endorsing peers.<\/li>\n<li>Ordering must work quickly. This is ensured by the fact that Ordering only forms the block and sends it to a fixed set of leader peers.<\/li>\n<li>Committing peers only store the blockchain \u2014 there can be many of them, and they do not require significant power or instant performance. <\/li>\n<\/ul>\n<p>\nFor more details on the architectural solutions of Hyperledger Fabric and why it works the way it does, you can check here: <noindex><a rel=\"nofollow\" href=\"https:\/\/hyperledger-fabric.readthedocs.io\/en\/latest\/arch-deep-dive.html\">Architecture Origins<\/a><\/noindex> or here: <noindex><a rel=\"nofollow\" href=\"https:\/\/arxiv.org\/abs\/1801.10228v2\">Hyperledger Fabric: A Distributed Operating System for Permissioned Blockchains<\/a><\/noindex>.<\/p>\n<p>So, Hyperledger Fabric is indeed a versatile system, with which you can:<\/p>\n<ul>\n<li>Implement arbitrary business logic using the smart contract mechanism;<\/li>\n<li>Record and retrieve data from the blockchain database in JSON format;<\/li>\n<li>Provide and verify access to the API using a Certificate Authority. <\/li>\n<\/ul>\n<p>\nNow that we have a bit of an understanding of the specifics of Hyperledger Fabric, let's finally do something useful!<\/p>\n<h2>Deploying the blockchain<\/h2>\n<p><\/p>\n<h3>Task Definition<\/h3>\n<p>\nThe task is to implement a Citcoin network with the following functions: create an account, get balance, refill the account, transfer coins from one account to another. Let's draw an object model, which we will later implement in the smart contract. So, we will have accounts that are identified by names (name) and contain a balance (balance), along with a list of accounts. Accounts and the list of accounts are assets in Hyperledger Fabric terminology. Accordingly, they have a history and a current state. I will try to illustrate this visually:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/a4f111da59bc7982b51d583857db6d5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThe top figures represent the current state, which is stored in the \"World state\" database. Below them are figures showing the history stored in the blockchain. The current state of the assets is modified by transactions. An asset can only change entirely, so as a result of executing a transaction, a new object is created, and the current value of the asset goes into history. <\/p>\n<h3>IBM Cloud <\/h3>\n<p>\nCreate an account in <noindex><a rel=\"nofollow\" href=\"https:\/\/cloud.ibm.com\">IBM Cloud<\/a><\/noindex>. To use the blockchain platform, you need to upgrade to Pay-As-You-Go. This process may not be quick, as IBM requests additional information and verifies it manually. On a positive note, I can say that IBM has decent educational materials that allow you to deploy Hyperledger Fabric in their cloud. I liked the following series of articles and examples:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/IBM\/Create-BlockchainNetwork-IBPV20\/blob\/master\/README.md\">Create a basic blockchain network using the Blockchain Platform<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/IBM\/SmartContractTrading-wFabric1-4-VSCodeExt\/blob\/master\/README.md\">Create and execute a blockchain smart contract<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/IBM\/auction-events\/blob\/master\/README.md\">Emit events from Blockchain Platform<\/a><\/noindex><\/li>\n<\/ul>\n<p>\nThe following are screenshots from the IBM Blockchain platform. This is not a guide on how to create a blockchain, but just a demonstration of the scope of the task. So, for our purposes, we create one Organization:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/7cb30cade6315abc69f4322a2dbcd094.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn it, we create nodes: Orderer CA, Org1 CA, Orderer Peer:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/4a2239a9b7ded8ba5a11ffad86a35094.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe create users:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/6792b12c9316f47b0cdfaf771dacc782.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe create a Channel and name it citcoin:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/ea3983f209326713dcd25762c348ac96.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn essence, a Channel is a blockchain, so it starts with a zero block (Genesis block):<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/416df6b6ef832c6550a2642592e57250.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Write a Smart Contract<\/h3>\n<p><\/p>\n<pre><code class=\"javascript\">\/*\n * Citcoin smart-contract v1.5 for Hyperledger Fabric\n * (c) Alexey Sushkov, 2019\n *\/\n \n'use strict';\n \nconst { Contract } = require('fabric-contract-api');\nconst maxAccounts = 5;\n \nclass CitcoinEvents extends Contract {\n \n    async instantiate(ctx) {\n        console.info('instantiate');\n        let emptyList = [];\n        await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(emptyList)));\n    }\n    \/\/ Get all accounts\n    async GetAccounts(ctx) {\n        \/\/ Get account list:\n        let accounts = '{}'\n        let accountsData = await ctx.stub.getState('accounts');\n        if (accountsData) {\n            accounts = JSON.parse(accountsData.toString());\n        } else {\n            throw new Error('accounts not found');\n        }\n        return accountsData.toString()\n    }\n     \/\/ add a account object to the blockchain state identifited by their name\n    async AddAccount(ctx, name, balance) {\n        \/\/ this is account data:\n        let account = {\n            name: name,\n            balance: Number(balance),       \n            type: 'account',\n        };\n        \/\/ create account:\n        await ctx.stub.putState(name, Buffer.from(JSON.stringify(account)));\n \n        \/\/ Add account to list:\n        let accountsData = await ctx.stub.getState('accounts');\n        if (accountsData) {\n            let accounts = JSON.parse(accountsData.toString());\n            if (accounts.length &lt; maxAccounts)\n            {\n                accounts.push(name);\n                await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(accounts)));\n            } else {\n                throw new Error('Max accounts number reached');\n            }\n        } else {\n            throw new Error('accounts not found');\n        }\n        \/\/ return  object\n        return JSON.stringify(account);\n    }\n    \/\/ Sends money from Account to Account\n    async SendFrom(ctx, fromAccount, toAccount, value) {\n        \/\/ get Account from\n        let fromData = await ctx.stub.getState(fromAccount);\n        let from;\n        if (fromData) {\n            from = JSON.parse(fromData.toString());\n            if (from.type !== 'account') {\n                throw new Error('wrong from type');\n            }   \n        } else {\n            throw new Error('Accout from not found');\n        }\n        \/\/ get Account to\n        let toData = await ctx.stub.getState(toAccount);\n        let to;\n        if (toData) {\n            to = JSON.parse(toData.toString());\n            if (to.type !== 'account') {\n                throw new Error('wrong to type');\n            }  \n        } else {\n            throw new Error('Accout to not found');\n        }\n \n        \/\/ update the balances\n        if ((from.balance - Number(value)) &gt;= 0 ) {\n            from.balance -= Number(value);\n            to.balance += Number(value);\n        } else {\n            throw new Error('From Account: not enought balance');          \n        }\n \n        await ctx.stub.putState(from.name, Buffer.from(JSON.stringify(from)));\n        await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));\n                 \n        \/\/ define and set Event\n        let Event = {\n            type: \"SendFrom\",\n            from: from.name,\n            to: to.name,\n            balanceFrom: from.balance,\n            balanceTo: to.balance,\n            value: value\n        };\n        await ctx.stub.setEvent('SendFrom', Buffer.from(JSON.stringify(Event)));\n \n        \/\/ return to object\n        return JSON.stringify(from);\n    }\n \n    \/\/ get the state from key\n    async GetState(ctx, key) {\n        let data = await ctx.stub.getState(key);\n        let jsonData = JSON.parse(data.toString());\n        return JSON.stringify(jsonData);\n    }\n    \/\/ GetBalance   \n    async GetBalance(ctx, accountName) {\n        let data = await ctx.stub.getState(accountName);\n        let jsonData = JSON.parse(data.toString());\n        return JSON.stringify(jsonData);\n    }\n     \n    \/\/ Refill own balance\n    async RefillBalance(ctx, toAccount, value) {\n        \/\/ get Account to\n        let toData = await ctx.stub.getState(toAccount);\n        let to;\n        if (toData) {\n            to = JSON.parse(toData.toString());\n            if (to.type !== 'account') {\n                throw new Error('wrong to type');\n            }  \n        } else {\n            throw new Error('Accout to not found');\n        }\n \n        \/\/ update the balance\n        to.balance += Number(value);\n        await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));\n                 \n        \/\/ define and set Event\n        let Event = {\n            type: \"RefillBalance\",\n            to: to.name,\n            balanceTo: to.balance,\n            value: value\n        };\n        await ctx.stub.setEvent('RefillBalance', Buffer.from(JSON.stringify(Event)));\n \n        \/\/ return to object\n        return JSON.stringify(from);\n    }\n}\nmodule.exports = CitcoinEvents;\n<\/code><\/pre>\n<p>\nIntuitively, everything here should be clear:<\/p>\n<ul>\n<li>There are several functions (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) that the demo program will call using the Hyperledger Fabric API.<\/li>\n<li>The functions SendFrom and RefillBalance generate events (Event) that the demo program will receive.<\/li>\n<li>The instantiate function is called once when the smart contract is instantiated. In fact, it is called not just once but each time the smart contract version is changed. Therefore, initializing the list with an empty array is a bad idea, as we will lose the current list when the smart contract version changes. But it\u2019s okay; I'm just learning).<\/li>\n<li>Accounts and the account list (accounts) are JSON data structures. JS is used for data manipulation.<\/li>\n<li>You can obtain the current value of an asset by calling the getState function, and update it with putState.<\/li>\n<li>When creating an Account, the AddAccount function is called, where a comparison is made against the maximum number of accounts in the blockchain (maxAccounts = 5). Here\u2019s a flaw (did you notice it?) that leads to an infinite increase in the number of accounts. Such errors should be avoided)<\/li>\n<\/ul>\n<p>\nNext, we load the smart contract into the Channel and instantiate it:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/45ad234efc9838b711f96642988f073e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe look at the transaction for installing the Smart Contract:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/39605b9d09468fd0c5f0557ed8b692a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe look at the details of our Channel:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/ccaf803cf34e52f77dac448f9c83e672.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAs a result, we get the following schema of the blockchain network in the IBM cloud. Also in the diagram is a demo program running in the Amazon cloud on a virtual server (details about it will be in the next section):<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/64e5c0f27d351ee3b60d2ea471a7f58c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Creating a GUI for calling Hyperledger Fabric API<\/h2>\n<p>\nHyperledger Fabric has an API that can be used for:<\/p>\n<ul>\n<li>Creating a channel;<\/li>\n<li>Connecting a peer to a channel;<\/li>\n<li>Installing and instantiating smart contracts in a channel;<\/li>\n<li>Calling transactions;<\/li>\n<li>Requesting information from the blockchain.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Application development<\/h3>\n<p>\nIn our demo program, we will use the API only for calling transactions and requesting information, as we have already completed the other steps using the IBM blockchain platform. We are writing a GUI using the standard technology stack: Express.js + Vue.js + Node.js. A separate article could be written about how to start creating modern web applications. Here is a link to a series of lectures that I liked the most: <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/Fa4cRMaTDUI\">Full Stack Web App using Vue.js &amp; Express.js<\/a><\/noindex>. As a result, we achieved a client-server application with a familiar graphical interface in Google's Material Design style. The REST API between the client and server consists of several calls:<\/p>\n<ul>\n<li>HyperledgerDemo\/v1\/init \u2014 initialize the blockchain;<\/li>\n<li>HyperledgerDemo\/v1\/accounts\/list \u2014 get the list of all accounts;<\/li>\n<li>HyperledgerDemo\/v1\/account?name=Bob&amp;balance=100 \u2014 create Bob's account;<\/li>\n<li>HyperledgerDemo\/v1\/info?account=Bob \u2014 get information about Bob's account;<\/li>\n<li>HyperledgerDemo\/v1\/transaction?from=Bob&amp;to=Alice&amp;volume=2 \u2014 transfer two coins from Bob to Alice;<\/li>\n<li>HyperledgerDemo\/v1\/disconnect \u2014 close the connection to the blockchain.<\/li>\n<\/ul>\n<p>\nI placed the API description with examples on<noindex><a rel=\"nofollow\" href=\"https:\/\/documenter.getpostman.com\/view\/7152141\/SVfTNSeb\"> the website 'Postman'<\/a><\/noindex> \u2014 a well-known program for testing HTTP APIs.<\/p>\n<h3>Demo application in the Amazon cloud<\/h3>\n<p>\nI uploaded the application to Amazon since IBM still hasn't upgraded my account and allowed me to create virtual servers. As a cherry on top, I attached the domain: <noindex><a rel=\"nofollow\" href=\"http:\/\/www.citcoin.info\">www.citcoin.info<\/a><\/noindex>. I will keep the server on for a bit, then turn it off since the rental costs are accumulating and citcoin coins are not yet listed on the exchange. I am including screenshots of the demo in the article to illustrate the workflow. The demo application can:<\/p>\n<ul>\n<li>Initialize the blockchain;<\/li>\n<li>Create an Account (but currently, a new Account cannot be created as the maximum number of accounts defined in the smart contract has been reached);<\/li>\n<li>Fetch the list of Accounts;<\/li>\n<li>Transfer citcoin coins between Alice, Bob, and Alex;<\/li>\n<li>Fetch events (but currently events cannot be displayed, so for simplicity, it\u2019s stated in the interface that events are not supported);<\/li>\n<li>Log actions.<\/li>\n<\/ul>\n<p>\nFirst, we initialize the blockchain:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/773ce08270f1b22e64a79fce267bb25f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNext, we create our account, not skimping on the balance:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/f1cd24aedd5e9618046c5e1ab49ceede.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe retrieve the list of all available accounts:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/796f897ca1345430f755055372d03421.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe select a sender and receiver, obtaining their balances. If the sender and receiver are the same, their balance will be topped up:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/58eb2ed4a4bac51e0dca1b0331d7910a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe monitor transaction execution in the log:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/528760998e8dc27a73c4409f55b22087.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThat\u2019s all with the demo program. Next, we can view our transaction on the blockchain:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/1d6bc12f3609b118472afec31b089f09.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAnd the overall list of transactions:<\/p>\n<p><img decoding=\"async\" alt=\"Blockchain: what does it cost us to build PoC?\" src=\"\/wp-content\/uploads\/2019\/09\/96675fcda8088307326dadf7852e6ce7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWith that, we have successfully completed the PoC for creating the Citcoin network. What else needs to be done for Citcoin to become a full-fledged coin transfer network? Just a bit more:<\/p>\n<ul>\n<li>At the account creation stage, implement the generation of private\/public keys. The private key should be stored by the account user, while the public key should be in the blockchain.<\/li>\n<li>Make a coin transfer where the user is identified not by name, but by the public key.<\/li>\n<li>Encrypt transactions going from the user to the server with their private key.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Conclusion <\/h2>\n<p>\nWe have implemented the Citcoin network with features: add account, check balance, top up account, transfer coins from one account to another. So, what did it cost us to build the PoC?<\/p>\n<ul>\n<li>We need to study blockchain in general and Hyperledger Fabric in particular;<\/li>\n<li>Learn to use IBM or Amazon clouds;<\/li>\n<li>Learn the JavaScript programming language and some web framework;<\/li>\n<li>If any data needs to be stored not in the blockchain, but in a separate database, learn to integrate with PostgreSQL, for example;<\/li>\n<li>And lastly, but not the least \u2014 without knowledge of Linux, you can't go far in today's world!)<\/li>\n<\/ul>\n<p>\nOf course, it's not rocket science, but it will require some effort!<\/p>\n<h3>Source code on GitHub<\/h3>\n<p>\nI've placed the source code on <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/AlexeySushkov\/Citcoin-blockchain\">GitHub<\/a><\/noindex>. Brief description of the repository:<br \/>\nCatalog &#171;<b>server<\/b>&#187; \u2014 Node.js Server<br \/>\nCatalog &#171;<b>client<\/b>&#187; \u2014 Node.js Client<br \/>\nCatalog &#171;<b>blockchain<\/b>&#187; (parameter values and keys are, of course, non-functional and are provided for example purposes only):<\/p>\n<ul>\n<li>contract \u2014 the source of the smart contract<\/li>\n<li>wallet \u2014 user keys for using the Hyperledger Fabric API. <\/li>\n<li>*.cds \u2014 compiled versions of smart contracts<\/li>\n<li>*.json files \u2014 sample configuration files for using the Hyperledger Fabric API<\/li>\n<\/ul>\n<p>\n<b>It's only the beginning!<\/b><br \/>\n<br \/>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466157\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0413\u043b\u0430\u0437\u0430 \u0431\u043e\u044f\u0442\u0441\u044f, \u0430 \u0440\u0443\u043a\u0438 \u0447\u0435\u0448\u0443\u0442\u0441\u044f! \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u044b (\u0427\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c?) \u0438 \u043a\u0435\u0439\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0441 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c (\u0427\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u043a\u0435\u0439\u0441 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c?). \u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438! \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0438\u043b\u043e\u0442\u043e\u0432 \u0438 PoC (Proof of Concept) \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u043b\u0430\u043a\u0430, \u0442.\u043a. \u043a \u043d\u0438\u043c \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28421,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-37868","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0413\u043b\u0430\u0437\u0430 \u0431\u043e\u044f\u0442\u0441\u044f, \u0430 \u0440\u0443\u043a\u0438 \u0447\u0435\u0448\u0443\u0442\u0441\u044f! \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u044b (\u0427\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/blokchejn-chto-nam-stoit-poc-postroit\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0411\u043b\u043e\u043a\u0447\u0435\u0439\u043d: \u0447\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 PoC \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c? | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0413\u043b\u0430\u0437\u0430 \u0431\u043e\u044f\u0442\u0441\u044f, \u0430 \u0440\u0443\u043a\u0438 \u0447\u0435\u0448\u0443\u0442\u0441\u044f! \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u044b (\u0427\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/blokchejn-chto-nam-stoit-poc-postroit\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:20:16+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:20:16+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Blockchain: what does it take to build a PoC? | ProHoster","description":"The eyes are afraid, but the hands are itching! In previous articles, we examined the technologies on which blockchains are built (What does blockchain cost us.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/blokchejn-chto-nam-stoit-poc-postroit","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0411\u043b\u043e\u043a\u0447\u0435\u0439\u043d: \u0447\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 PoC \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c? | ProHoster","og:description":"\u0413\u043b\u0430\u0437\u0430 \u0431\u043e\u044f\u0442\u0441\u044f, \u0430 \u0440\u0443\u043a\u0438 \u0447\u0435\u0448\u0443\u0442\u0441\u044f! \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u044b (\u0427\u0442\u043e \u043d\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d.","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/blokchejn-chto-nam-stoit-poc-postroit","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:20:16+00:00","article:modified_time":"2019-10-31T19:20:16+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"37868","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 19:34:11","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:19:22","updated":"2026-01-23 19:34:11","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/37868","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=37868"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/37868\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/28421"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=37868"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=37868"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=37868"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}