Академический Документы
Профессиональный Документы
Культура Документы
This is a guest post by KC TAM on Using Various Tools for Smart Contract Development: Remix, Web3 on
TestRPC.
I recently read a good article on Blockgeeks, in which Ameer is trying to put everything about coding Decentralized
Applications into one masterpiece. What a very ambitious and great work it is! Of which there are several
components, and I would like to elaborate a bit on some of these tools, and how they can be used for contract
development.
This series of article is not for Smart Contract 101 or Ethereum platform. You definitely can find a lot of good
material in Blockgeeks. But I am sure by going through this, you will grab some ideas on these tools and hope this
helps when you are working on the Smart Contract with Solidity.
I will first make a quick description of the Smart Contract I have chosen. And later deploy this contract in four
environments. Here is a quick summary of the four environments we are showing here.
This application is taken from the Smart Contract in Chapter 4: Ethereum Accounts from the book “Blockchain
Applications a Hands-On Approach” by A. Bahga and V. Madisetti. It has been modified to match some
requirement on the latest release of Solidity.
This application is called Revenue Sharing. In short, a list of addresses is given when the contract is deployed.
Anyone can send a certain amount of money (here it is ethers or ether’s denomination) and this amount of money is
equally distributed to the addresses on the list. It is a rather simple Solidity contract.
contract RevenueSharing {
address public creator;
mapping(uint => address) public shareholders;
uint public numShareholders;
function kill() {
if (msg.sender == creator) selfdestruct(creator);
}
}
Function RevenueSharing() has the same name of the contract itself. It is the constructor, and only called once when
the contract is deployed. We see in this contract an array of addresses is supplied, and this array of addresses are
stored in another array called shareholders.
Function shareRevenue() is the only main function in this contact. When executing this function with an amount of
ethers (in msg.value), the amount is divided into the number of shareholders (numShareholders), and each address
in the shareholder array will get the portion. We will execute this function in our demo.
Function kill() is used for removing the contract. We will not use this function in the demo.
Note that all variables are defined with public. This helps us to observe more detail in the contract. In real life, we
should be careful when making variables or functions public due to security consideration.
Remix
Overview
Remix is a suite of tools to interact with the Ethereum blockchain in order to debug transactions (directly quoted
from here). There is an IDE version (Remix IDE) and an online version, which we will use here.
There are many tools inside Remix, but the following tools are of our interests,
Solidity Compiler. which generates a lot of useful information that we will use in another environment
Runtime Environment. Remix provides three:
Injected Web3: to provider such as Mist or MetaMask
Web3 Provider: to local host through ipc
JavaScript VM: a simulated environment
Among the runtime environments, we are using JavaScript VM. In the JavaScript VM, Remix comes with five
Ethereum accounts, each of which is deposited with 100 ethers. This is good enough for testing our smart contract.
Also, mining is not required as it is done automatically.
You can easily access Remix from any browser (url: http://remix.ethereuem.org). This is a screenshot of Remix.
Area for Smart Contract: we are pasting the Solidity code of contract here.
Area of Compilation and Runtime: in Compilation tag, here show any compilation errors or warnings. in Run
tag, we deploy the contract and execute contract functions.
Area of Transaction Logs: all transaction detail can be observed here.
If we click Details, we will see a lot of information for this contract. Among them they are,
Bytecode
ABI
Web3 Deploy
They are needed when deploying this contract in another environment. We will refer this back later.
As we see no errors after compilation, we can run this contract onto Remix JavaScript environment.
After selecting JavaScript VM, we will see some accounts are populated in Account fields.
And as said, each of which are pre-deposited 100 ethers, just for testing. As we will use these accounts later, we can
copy them first.
The Gas limit is to specify how much gas we can spend on any transaction. As we are in test environment, we do
not worry this too much. I have tried some big contract deployment and the default gas limit is not adequate.
Anyway, it can be increased to whatever value when needed.
The Value part is where we send the amount of ethers during contract deployment and executing a function. In our
case, we do not put any value in contract deployment, but put some ethers when executing the function. See below
for more detail.
2. Deploy the Contract
Now we see the contract RevenueSharing is already selected (we have only one contract in our code). We will use
Create button to deploy this contract onto the JavaScript VM.
Something is required, as hinted in the input area: “address[] addresses”, when the contract is deployed. Remember
this contract requires a list of addresses as sharing targets? For demo purpose, we will use the 3rd, 4th and 5th
addresses listed above as the address list. So paste this beside the Create button:
Environment: JavaScript VM
Account: the first account when deploying this contract (begins with 0xca3…)
Paste the address array above beside Create button
Also, we see the variables marked as “public” is now shown, they are,
shareholders
numShareholders
creator
shareRevenue()
kill()
Before everything, we observe that the account balance is reduced by a small amount of ethers. The difference
(417,626 weis, 1 wei = 10-18 ether) is the cost of deploying this contract. In real life, it is the real ethers deducted
from your account when you deploy a contract.
We can first check the variables by pressing the variable buttons. Here we examine the numShareholders and
creator. For shareholders, as it is an array, we need to specify an index (0, 1 or 2), corresponding to the addresses we
put when the contract is deployed (created).
Now we execute shareRevenue(). We use the first account to deposit 30 ethers when executing this function (This is
only for this function. In many cases this is not required.). According to the contract logic, the 30 ethers are to be
distributed among the account list, that is, the 3rd, 4th and 5th account in our account list. As of now, the balance of
each of them is still 100 ethers.
We use the same place to execute the function. Here we make sure to,
After the function is executed, we examine the balance of each accounts, and see if it is executed according to our
design.
First, we see 30 ethers are deducted from 1st account, and all the three accounts on the list now have 110 ethers. So
the 30 ethers deducted from 1st account is now distributed among the three accounts. This part works perfects
according to the contract.
Also, if we closely examine the balance of 1st account, some additional amount of ethers is deducted. The
difference is 47,776 wei, which is the cost for this transaction. Every transaction, execution of function, or
deployment of contract costs you some amount of ethers.
Transaction Log
We have not touched the transaction log during our test, but everything is kept in log, even the inquiry of a variable.
Let us take a look on detail from two selected logs.
1. Contract Deployment
We can see who has deployed this contract, the contract address, and the transaction cost required to deploy it.
Summary
This is how Remix helps in testing the code we develop. It comes with very handy features and intuitive user
interface. In next article we will use another environment, testrpc, to work on the same contract and see how it
works.
Overview
TestRPC is a simulation of an Ethereum blockchain, which comes with 10 pre-defined Ethereum accounts and
supports mnemonics (that is, one can generate the same set of accounts with the same set of mnemonics). It does not
come with a User Interface as Remix, and we need node console plus the web3 library to interact with this
blockchain.
Preparation
The demo is done through command line or terminal. Use a terminal tool that supports screen spliting. I am using
iTerm2 on my Mac.
Install node and npm: please refer here for installation on your platform.
Remark: I recently found that when installing web3 with npm, the 1.0.0 beta version is installed, where the
commands used before (based on 0.20.4) do not work. Therefore we instead specify the version of web3.
Open a terminal and split the screen into two. The left side is the node console, where we will work most of our
time. The right side is where we run the TestRPC.
Start TestRPC
On the right side, start the TestRPC
Web3 object
We need to instruct node console we are using web3 and pointing the blockchain web3 is interfacing.
I have found a handy function (link) that can show balance for all accounts. Here is the function.
Simply copy-n-paste this function into node console. Now we can call the function checkAllBalances() at any time,
and it will show up the balance of all accounts in ether. Note that this function will be gone after we quit the node
console, but we can add it back at any time needed.
Among the information, three are of our interests: bytecode, ABI and Web3Deploy
The bytecode is the binary version of our contract after compilation and the instruction set to be run in Ethereum
Virtual Machine (EVM), and the ABI (application binary interface) is the interface we are interacting with the
contract bytecode.
Remix is kind enough to prepare the code in Web3Deploy, in which the bytecode and ABI are already included in
the commands. Therefore we just need to use the Web3Deploy part.
First, as required by the contract, we need to define a list of target accounts. For demo purpose, the three accounts
starting from the second account are used, that is, from eth.accounts[1] to eth.accounts[3].
Then we follow what Web3Deploy suggests.
Create a class for revenue-sharing contract based on the ABI. Simply copy that line from Web3Deploy.
node console
> var revenuesharingContract =
web3.eth.contract([{"constant":true,"inputs":[],"name":"creator","outputs":[{
"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":
"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable
":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"i
nputs":[],"name":"numShareholders","outputs":[{"name":"","type":"uint256"}],"
payable":false,"stateMutability":"view","type":"function"},{"constant":true,"
inputs":[{"name":"","type":"uint256"}],"name":"shareholders","outputs":[{"nam
e":"","type":"address"}],"payable":false,"stateMutability":"view","type":"fun
ction"},{"constant":false,"inputs":[],"name":"shareRevenue","outputs":[{"name
":"success","type":"bool"}],"payable":true,"stateMutability":"payable","type"
:"function"},{"inputs":[{"name":"addresses","type":"address[]"}],"payable":fa
lse,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"
inputs":[{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false
,"name":"_numShareholders","type":"uint256"}],"name":"Disburse","type":"event
"}]);
Now deploy the contract with the bytecode, plus the necessary information. Again, we can copy that line from
Web3Deploy. The deployed contract is an object called revenuesharing.
node console
> var revenuesharing = revenuesharingContract.new(
addresses,
{
from: web3.eth.accounts[0],
data:
'0x6060604052341561000f57600080fd5b60405161049d38038061049d833981016040528080518201919050506000336000806101000a81548
173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550815160028
1905550600090505b81518110156100f957818181518110151561009157fe5b90602001906020020151600160008381526020019081526020016
0002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373fffffffffffffffffffffffffffffffffffffff
f160217905550808060010191505061007a565b50506103938061010a6000396000f30060606040526004361061006d576000357c01000000000
00000000000000000000000000000000000000000000000900463ffffffff16806302d05d3f1461007257806341c0e1b5146100c757806368eca
613146100dc578063ab377daa14610105578063e579a0bd14610168575b600080fd5b341561007d57600080fd5b61008561018a565b604051808
273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910
390f35b34156100d257600080fd5b6100da6101af565b005b34156100e757600080fd5b6100ef610240565b60405180828152602001915050604
05180910390f35b341561011057600080fd5b6101266004808035906020019091905050610246565b604051808273fffffffffffffffffffffff
fffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610170610279565b604
051808215151515815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1
681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673fffffffffffffffffffffffffffffffffffffff
f163373ffffffffffffffffffffffffffffffffffffffff16141561023e576000809054906101000a900473fffffffffffffffffffffffffffff
fffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b60025481565b600160205280600052604060002060009150549
06101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060006002543481151561028b57fe5b049150600090505b6
0025481101561031d576001600082815260200190815260200160002060009054906101000a900473fffffffffffffffffffffffffffffffffff
fffff1673ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f1935050505015156
1031057600080fd5b8080600101915050610293565b7f9c26340b8d01b4e039192edfd25f4a56ed070d45afe866b8685658b1ed3cd74d3460025
4604051808381526020018281526020019250505060405180910390a1600192505050905600a165627a7a72305820f0e717ba935e00c43896cc9
266a85af91a519061c044503be0a52b93f721d1610029',
gas: '4700000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + '
transactionHash: ' + contract.transactionHash);
}
})
Now we can use the object revenuesharing to interact with this deployed contract.
Before we execute the shareRevenue() function, let’s take a look on the balance.
Note that some amount is deducted in accounts[0], who has deployed the contract. The amount of ether paid for the
deployment is 417,626 weis. You can check it is the exact transaction cost when we did this in Remix.
node console
> revenuesharing.shareRevenue({from: web3.eth.accounts[0], value:
web3.toWei(30), gas: 4700000});
Here we are calling the function shareRevenue(), and specifying that it is executed by accounts[0], with 30 ethers
(toWei is a function in web3 is used to convert 30 ethers to wei, as wei is the unit accepted in the command). We
also put the gas we allow to spend (It’s way more than required but we will get refund after execution).
Summary
We have successfully done the same thing on TestRPC. The overall flow is almost the same as that in Remix,
except that we have to work on node console and web3 to interact with the blockchain in TestRPC. Next time we
will do almost the same thing on a private Ethereum blockchain.
Author: KC TAM
KC began his blockchain journey just a few months ago. His interest is to dig out more detail “how things work”,
and share with others what he has learnt.’LinkedIn: https://www.linkedin.com/in/ktam1/
One of the projects you will inevitably stumble upon when you visit blockchain conferences and follow blockchain
news is Hyperledger of the Linux Foundation. But while it is relatively straight forward to understand
what cryptocurrencies like Bitcoin and even Ethereum are, it is more difficult to get your head around the
Hyperledger initiative. But if you do, you’ll find some exciting projects for non-currency, industrial blockchain
applications.
What is Hyperledger?
Let’s start with what Hyperledger is not: Not a company. Not a cryptocurrency. Not a blockchain. Hyperledger is
rather something like a hub for open industrial blockchain development. On its website Hyperledger explains:
Hyperledger does not support Bitcoin or any other cryptocurrency. But the platform is thrilled by blockchain
technology. Not since the Web itself, the website tells, “has a technology promised broader and more fundamental
revolution than blockchain technology.” Blockchains has the potential to “build a new generation of transactional
applications that establishes trust, accountability, and transparency at their core while streamlining business
processes and legal constraints.”
So we have a lot of promises – and we have Hyperledger. With it, the Linux Foundation aims to create an
environment in which communities of software developer and companies meet and coordinate to build blockchain
frameworks. The Linux Foundation founded the platform in December 2015. In February 2016 it announced the
first founding members, in March 2016 ten more members joined.
Today Hyperledger has an impressive list of more than 100 members. The list covers a wide scope of well know
industry leaders. It includes mobility tech giants like Airbus and Daimler, IT-companies like IBM, Fujitsu, SAP,
Huawei, Nokia, Intel and Samsung, financial institutions like Deutsche Börse, American Express, J.P. Morgan,
BBVA, BNP Paribas and Well Fargo, as well as Blockchain startups like Blockstream, Netki, Lykke, Factom, bloq
and Consensys. A lot of the world’s largest companies in Tech and Finance meet at Hyperledger with some of the
hottest blockchain startups.
Something like the executive government of Hyperledger is the committee of leaders. It consists of more than 10
executives, most with decades of experience in Open Source and tight connections to several industries. You’ll find
leaders of the Apache Foundation and the W3C Consortium as well as engineers from IBM and more. Some of
Hyperledgers’s members, like Richard Brown and Tamas Blumer, already worked with Blockchain for years. For its
members, Hyperledger does not only provide technical knowledge and software frameworks but also various
contacts to industries and developers.
Relatively early in the history of Hyperledger, the project had to make an important decision. Executive Director
Brian Behlendorf was asked if there will be an “Hyperledger Coin”, a monetary unit running on the Hyperledger
blockchains. Behlendorf answered that the Hyperledger Project itself will never build its own cryptocurrency.
“You’ll never see a Hyperledger coin,” he said, “By not pushing a currency, we avoid so many political
challenges of having to maintain a globally consistent currency.”
This decision strongly shaped the strategic goals of Hyperledger to build industrial applications of blockchain
technology and sharply separating it from the get-rich schemes usually evolving from currency based blockchains.
This might be more boring, but also more straightforward to the technology.
Further, a “charter” outlines the goals of Hyperledger, like a mission guide. According to it, the platform aims to
“create an enterprise-grade, open source distributed ledger framework and code base” and create, promote and
maintain an open infrastructure.
This is somehow telling, but somehow vague. It outlines some kind of program, but doesn’t answer the big,
important questions: What do all these world leading companies and leaders do at Hyperledger? What projects are
they pushing forward? Who participates?
Projects
The “umbrella strategy” of Hyperledger incubates and promotes a range of business blockchain technologies,
framework, libraries, interfaces, and application. Currently, Hyperledger is the host of the following projects:
Hyperledger Sawtooth: This is a modular blockchain suite developed by Intel, which uses a new consensus
algorithm called Proof of Elapsed Time (PoeT).
Hyperledger Iroha: Iroha is a project of a couple of Japanese companies to create an easy to incorporate
the framework for a blockchain.
Hyperledger Fabric: This project is lead by IBM. Fabric is a plug and plays implementation of blockchain
technology designed as a foundation to develop high-scaling blockchain applications with a flexible degree
of permissions.
Hyperledger Burrow: This project develops a permissible smart contract machine along the specification of
Ethereum.
Beside these framework projects, Hyperledger has several tool projects aiming to make the access to and
development of blockchains easier and more effective. This is Cello, a blockchain as-a-service deployment model,
Composer, a tool for building blockchain business networks, an Explorer to view, query and deploy transactions and
associated data on blockchains, and Indy, a collection of tools, libraries and further components for digital identities
rooted on blockchains.
Hyperledger obviously engages in a wide scope of non-monetary blockchain projects. But this rough view on these
projects must remain dissatisfying, as the short descriptions don’t go far beyond keywords. So we take a closer look
at the two most prominent projects: Sawtooth and Fabric. Both projects are created by large companies – Intel and
IBM – and given to Hyperledger as open source code. With Hyperledger the companies continue pushing their
blockchain projects forward, while everybody else is invited to contribute.
Intel’s Sawtooth
Sawtooth Lake is Intel’s modular blockchain suite. It is written in Python and designed for use cases in many fields
from IoT to Financials. The dominant characteristics of Sawtooth Lake are that it supports both permissioned and
permissionless application and deployments and that its uses a newly developed consensus algorithm called Proof of
Elapsed Time (PoET).
PoET uses new secure CPU instruction, which is more and more available in new processors like Intel builds. With
these instructions, PoET ensures a safe and random selection of a so-called “leader”. This can be compared with
Bitcoin mining, in which the miners compete for a one-time access to write the blockchain. Other than Bitcoin’s
proof algorithm, PoET doesn’t need specialized mining hardware.
To become a leader, every “validator” – which equals to a node or a miner – needs to use the secure CPU
instruction to request a wait time. The validator with the shortest wait time will be elected as a leader. Like every
good mining, algorithm PoET works like a lottery with the price to get write access to the blockchain.
Other than with cryptocurrencies there is no reward for the leader. It is just part of running the software. So there
will be no energy-burning competition like in cryptocurrencies. Every node simply can use its CPU – as long as it is
a new model and, maybe, from Intel – to participate in the leader selection for no costs. What is mining in Bitcoin,
is simply a non-intrusive part of the software in Sawtooth Lake.
Another innovation of Sawtooth Lake is the building and propagation of transactions. A client builds transactions
and submits it to the validators. This wrap the transactions they get inside of a batch and commit them to the state
altogether. This is a similar, but not identical process as when cryptocurrency miners wrap transactions to a block.
With this batching Sawtooth solves the problem of securely validating transactions which depend on each other.
To date, Sawtooth is tested in several applications. It is tested to record the journey of seafood from the ocean to the
table, using IoT sensors, and track ownership, possession, and parameters through the whole supply chain, from the
fisherman to the supermarket. The buyer can access a complete and trustless record of the whole live chain of the
seafood. This use case in supply chain and product history is increasingly discussed for Blockchains.
Sawtooth is also tested to streamline the process of transferring bonds. The developers created a user interface to
track and transfer bonds. With this users can manage a whole portfolio of bonds on the blockchain. Another use
case of Sawtooth currently tested are digital assets. The developers built a platform for managing digital asset
ownership on the Sawtooth blockchain, which could be able to manage a wide scope of digital assets. The
connecting dot between this application of Sawtooth seems to be the marketplace for digital assets of any kind
which is built in the blockchain and already has a graphical interface for users.
While these tests are ongoing and Sawtooths enjoys a wide industry interest, the project seems to get less traction
than IBM’s contribution to Hyperledger.
Fabric
Maybe the most interesting project in the Hyperledger family is IBM’s Fabric. Rather than a single blockchain
Fabric is a base for the development of blockchain based solutions with a modular architecture. With Fabric
different components of Blockchains, like consensus and membership services can become plug-and-play. Fabric is
designed to provide a framework with which enterprises can put together their own, individual blockchain network
that can quickly scale to more than 1,000 transactions per second.
What is Fabric and how does it work? The framework is implemented in Go. It is made for enabling consortium
blockchains with different degrees of permissions. Fabric heavily relies on a smart contract system called
Chaincode, which every peer of the networks runs in Docker containers. An overview of Fabric’s technology can be
found in the manual.
While not completely and generally permissioned, Fabric allows enterprises to make parts of the blockchain, if not
all, permissioned. Participants usually need to register to get the permission to join and issue transactions on a
Fabric based blockchain. To use resources more efficiently, Fabric has fewer nodes than a public chain and
computes data massively in parallel, which makes Fabric scale much better than public blockchains. Also its basic
architecture supports confidential data, giving its members more privacy as they find on a public blockchain.
Maybe most important is the separation between so-called “Endorsers” and “Consensus Nodes”. If you are familiar
with cryptocurrencies like Bitcoin you will recognize the separation between miners and nodes. The Endorsers have
the state, and build, validate and propagate transactions and chaincode, while the Consensus Nodes orders the
already validated transactions. While this separation has not been a concept of the first blockchain concept of
Satoshi Nakamoto, but became an unwished reality in most cryptocurrencies, Fabric is one of the first to make this
separation a design principle. This enables Fabric for example to implement a better division of labour, so that not
every peer of the network has to do every job.
While having no native currency, Fabric allows the user to define assets from client side and use them with the
Fabric Composer. Fabric’s Chaincode Smart Contracts framework is similar to Ethereum: Chaincode defines the
business logic of assets, the rules for reading and altering the so called state of the assets. Like Ethereum Fabric
maintains not a set of unspent outputs, as Bitcoin maintains, but the state of the blockchain which is not restricted to
transactional data.
Other than the public blockchains of cryptocurrencies Fabric allows participants to build a separate channel for their
assets and hence isolate and segregate transactions and a ledger. With this method, the chaincode needed to read and
alter the state of an asset will only be installed on peers involved in this certain business case. Like in good chat
programs Fabric’s blockchains allow the user to participate in both open and private interactions.
Beyond this IBM proposes an alternative design for public and permissionless blockchains. Fabric uses a public key
infrastructure to generate cryptographic certificates tied to organizations and users. So it is possible to restrict data
and channel access to certain actors.
Fabric’s strength seems to be the high grade of flexibility in permission and privacy while enabling high scalability
through a more advanced division of labour of network participants.
For IBM Fabric serves as a flagship project for blockchain development. The IT giant uses Fabric for a variety of its
own projects and for collaborations with several business partners.
In March 2017 IBM launched IBM Blockchain, a service that enables developers to “quickly build and host
security-rich production blockchain networks on the IBM Cloud.” With this move, IBM catches up with Microsoft,
which long integrated blockchains in its Azure Cloud.
However, while Microsoft is just a cloud host for several external blockchains, IBM heavily promotes its own
blockchain framework, Fabric, for a lot of use cases. For example, at the end of March, Natixis and Trafigure
partnered with IBM to use a blockchain based on Fabric for commodity trade finance for US crude oil transactions.
All major steps in a crude oil transaction are digitized on the blockchain, massively improving transparency,
efficiency, and security.
In April IBM announced several new blockchain projects based on Fabric: The company partnered with Sichuan
Heijia to build up a blockchain based supply chain platform for pharmaceutical procurements. In the same month,
IBM started to cooperate with Japan’s Mizuho Financial Group and Mizuho Bank to create a blockchain based
platform for trade financing. This projects aim to streamline trading operations and improve supply chain efficiency.
In another project disclosed in April 2017 IBM cooperates with the National University of Singapore to develop a
module on financial technology to improve the student’s education in this area. Finally, in May 2017, IBM was
chosen as a partner of TenneT, Sonnen and Vandebron to develop a blockchain for managing the electric grid in the
Netherlands and Germany.
While there is a lot of information available on Sawtooth and Fabric, there is less known about the other projects.
Maybe these projects first have to grow and mature to be a subject of media releases, tests and real world
application. But the best-known projects, Sawtooth and Fabric, are interesting and seem to be backed by strong IT
companies. It will be interesting to see if Hyperledgers succeeds in connecting these blockchains, for example by
developing tools which can be used with all Hyperledger blockchain frameworks.
While most other blockchain projects focus on cryptocurrencies and tokens, the projects around Hyperledger
demonstrate a strong potential to build the backbone of non-monetary, high scaling industrial applications of
blockchain technology. With interesting concepts and leaders in the technology behind, Hyperledge has not the
worst chances to win this prize.
Hyperledger Burrow v0.16
Linux
Master
Develop
Hyperledger Burrow is a permissioned Ethereum smart-contract blockchain node built with <3 by Monax.
It executes Ethereum smart contract code on a permissioned virtual machine. Burrow provides transaction
finality and high transaction throughput on a proof-of-stake Tendermint consensus engine. For smart
contract development most functionality is provided by monax chains, exposed through monax, the entry
point for the Monax Platform.
Table of Contents
What is burrow
Installation
For developers
Usage
Configuration
Contribute
License
Future work
What is Burrow ?
Hyperledger Burrow is a permissioned blockchain node that executes smart contract code following the
Ethereum specification. Burrow is built for a multi-chain universe with application specific optimization in
mind. Burrow as a node is constructed out of three main components; the consensus engine, the
permissioned Ethereum virtual machine and the rpc gateway. More specifically Burrow consists of the
following:
Consensus Engine: transactions are ordered and finalised with the Byzantine fault-tolerant Tendermint
protocol. The Tendermint protocol provides high transaction throughput over a set of known validators and
prevents the blockchain from forking.
Application Blockchain Interface (ABCI): The smart contract application interfaces with the consensus
engine over the ABCI. The ABCI allows for the consensus engine to remain agnostic from the smart contract
application.
Smart Contract Application: transactions are validated and applied to the application state in the order
that the consensus engine has finalised them. The application state consists of all accounts, the validator set
and the name registry. Accounts in Burrow have permissions and either contain smart contract code or
correspond to a public-private key pair. A transaction that calls on the smart contract code in a given
account will activate the execution of that account’s code in a permissioned virtual machine.
Permissioned Ethereum Virtual Machine: This virtual machine is built to observe the Ethereum operation
code specification and additionally asserts the correct permissions have been granted. Permissioning is
enforced through secure native functions and underlies all smart contract code. An arbitrary but finite
amount of gas is handed out for every execution to ensure a finite execution duration - “You don’t need
money to play, when you have permission to play”.
Application Binary Interface (ABI): transactions need to be formulated in a binary format that can be
processed by the blockchain node. Currently tooling provides functionality to compile, deploy and link
solidity smart contracts and formulate transactions to call smart contracts on the chain. For proof-of-
concept purposes we provide a monax-contracts.js library that automatically mirrors the smart contracts
deployed on the chain and to develop middleware solutions against the blockchain network. Future work
on the light client will be aware of the ABI to natively translate calls on the API into signed transactions that
can be broadcast on the network.
API Gateway: Burrow exposes REST and JSON-RPC endpoints to interact with the blockchain network and
the application state through broadcasting transactions, or querying the current state of the application.
Websockets allow to subscribe to events, which is particularly valuable as the consensus engine and smart
contract application can give unambiguously finalised results to transactions within one blocktime of about
one second.
Burrow has been architected with a longer term vision on security and data privacy from the outset:
Installation
burrow is intended to be used by the monax chains command via monax. Available commands such as make
| start | stop | logs | inspect | update are used for chain lifecycle management.
For Developers
Dependency management for Burrow is managed with glide, and you can build Burrow from source by
following
Install go
Ensure you have gmp installed (sudo apt-get install libgmp3-dev || brew install gmp)
and execute following commands in a terminal:
go get github.com/Masterminds/glide
go get -d github.com/hyperledger/burrow
REPO=$($GOPATH/src/github.com/hyperledger/burrow)
cd $REPO && glide install
cd $REPO/cmd/burrow && go install
To run burrow, just type $ burrow serve --work-dir <path to chain directory>, where the chain directory
needs to contain the configuration, genesis file, and private validator file as generated by monax chains
make.
This will start the node using the provided folder as working dir. If the path is omitted it defaults
to ~/.monax.
For a Vagrant file see monax-vagrant for drafts or soon this repo for Vagrant and Packer files.
Usage
Once the server has started, it will begin syncing up with the network. At that point you may begin using
it. The preferred way is through our javascript api, but it is possible to connect directly via HTTP or
websocket.
Configuration
A commented template config will be written as part of the monax chains make process and can be edited
prior to the monax chains start process.
Logging
Logging is highly configurable through the config.toml [logging] section. Each log line is a list of key-
value pairs that flows from the root sink through possible child sinks. Each sink can have an output, a
transform, and sinks that it outputs to. Below is a more involved example of than the one appearing in the
default generated config of what you can configure:
# This is a top level config section within the main Burrow config
[logging]
# All log lines are sent to the root sink from all sources
[logging.root_sink]
# We define two child sinks that each receive all log lines
[[logging.root_sink.sinks]]
# We send all output to stderr
[logging.root_sink.sinks.output]
output_type = "stderr"
[[logging.root_sink.sinks]]
# But for the second sink we define a transform that filters log lines from Tendermint's p2p
module
[logging.root_sink.sinks.transform]
transform_type = "filter"
filter_mode = "exclude_when_all_match"
[[logging.root_sink.sinks.transform.predicates]]
key_regex = "module"
value_regex = "p2p"
[[logging.root_sink.sinks.transform.predicates]]
key_regex = "captured_logging_source"
value_regex = "tendermint_log15"
# The child sinks of this filter transform sink are syslog and file and will omit log lines
originating from p2p
[[logging.root_sink.sinks.sinks]]
[logging.root_sink.sinks.sinks.output]
output_type = "syslog"
url = ""
tag = "Burrow-network"
[[logging.root_sink.sinks.sinks]]
[logging.root_sink.sinks.sinks.output]
output_type = "file"
path = "/var/log/burrow-network.log"
Contribute
We welcome all contributions and have submitted the code base to the Hyperledger project governance
during incubation phase. As an integral part of this effort we want to invite new contributors, not just to
maintain but also to steer the future direction of the code in an active and open process.
Future work
Some burrows marmots have already started digging to build the enterprise ecosystem applications of
the future are listed in docs/proposals. Marmots live in groups we welcome your help on these or other
improvement proposals. Please help us by joining the conversation on what features matter to you
SAWTOOTH Tutorial
Scenarios
Basic Cookie Market
In most markets, you will want the creation of Assets to be centrally controlled so that everyone can’t just make
infinite goods, similar to how the Federal Reserve controls how and when money is printed. Let’s build that Market
authority now.
1. The Market works like any other Participant, so we will start by generating a new WIF key.
2. Download the key, and then click Create Participant. You may want to rename the file something meaningful,
like “market.wif”.
3. Name the market “Market”, write a short description, and then click Submit.
4. The first thing a market needs is a currency, so click on the + button next to the Assets list.
5. We’re going to make both a new AssetType (currency), and a new Asset (usd). We will make both “restricted”,
since we do not want other participants making counterfeit currency. USD will also be “divisible”, since it is
possible to trade fractions of a dollar.
6. Now that dollars exist as a concept, we need to create some for the market. Wait for the transation to be
committed to the blockchain, and once USD appears on the sidebar, click the +next to the Holdings list.
Note
Waiting for the blockchain to commit will be a common experience throughout this scenario and won’t be
explicitly mentioned again. If you feel the need to check the status of recent transactions, you can do so by
clicking on the Block name in the menu bar.
7. We’re going to create a strategic reserve of $1,000,000, which we will later distribute to the other participants in
our market.
8. We’re going to use the pre-made reusable “token” asset to create our distribution offer, but first we’ll need
a Holding for that too.
9. Finally, we’ll create our offer to provision each participant with $1,000. Click the + Create Offerbutton in the
menu bar.
10. Set the offer to take in tokens and payout usd at a 1:1000 ratio. We only want this exchange to be possible once
per person, so set both the minimum and maximum input to 1, and limit it to Execute Once per Participant.
11. Our market is all set and ready to go! Select Sign Out from the Hi, Market dropdown, and let’s make a new
participant.
Making a Baker
Now we’re going to create Abby, an entrepeneur who will bake some cookies to sell on the market.
1. Follow the same steps as above to generate and save a new WIF key. Then fill out Abby’s info and
click Submit.
2. You can see that USD already exists in the list of Assets. Let’s add cookies. Click the + next to Assets.
3. We’ll make the cookie AssetType and chocolate chip cookie Asset similar to how we made USD, but this time
they will not be “restricted”, since almost anyone can come up with new recipes for cookies, or physically bake
new chocolate chip cookies.
4. Now that chocolate chip cookies are a thing, let’s bake a batch. Click the + next to Holdings, and make a
holding with 24 cookies.
5. The last thing we need to do before we can create a sell offer is to make a holding of US dollars to send our
payments to. We could create an empty one, but why not take advantage of that market provision? Start by
creating an authorization token by clicking the + next to Holdings.
6. Tokens are unrestricted, so we can create a holding prepopulated with one, and since they are not consumable,
one is all we need.
7. Select Dashboard from the Hi, Abby dropdown menu.
8. Click on Latest Open Offers
9. Click the Accept button to the right of the provisioning offer.
10. We can create a new savings account in the process of accepting the Market’s provisioning offer. We just have
to select New Holding from the Output Holding dropdown, and we’re good to go.
11. Finally we can create our offer to sell cookies. This will look similar to the provisioning offer the Market created
earlier, but we won’t limit how many times it can be executed. Let’s sell the cookies for $2 each.
12. We’re done with our baker Abby, so go ahead and Sign out.
Making a Buyer
Finally we will create Ben, a discerning cookiehead looking for the absolute best chocolate chip. He will take the
Market’s USD provision, and use it to purchase Abby’s cookies. You should be familiar with all the steps by now.
1. Generate and save a WIF key, and then create Ben’s account.
3. Use that token to accept the Market’s USD provisioning offer and create a USD holding (get there by clicking
on Dashboard > Latest Open Offers > Accept).
4. We’re ready buy some cookies! Return to the Dashboard and click on Latest Open Offers one more time. This
time though the offer we will be accepting is Abby’s.
1. First we need to log our Market back in. If you are still signed in as Ben, sign out and this time click Import
WIF, instead of generating a new one.
2. The easiest way to enter Market’s WIF key is to upload the market.wif file we generated earlier (you still have
that right?). Click Upload WIF File, select the file, and then click Submit.
3. Now that you are logged back in as Market, let’s create a new currency asset: Euros. Click the +to the right
of Assets, and fill out the form.
4. We’ll need a holding with a strategic reserve of €1,000,000 as well. Add the holding with the +to the right
of Holdings.
5. Finally we’ll create an offer to exchange USD for Euros. Click + Create Offer in the menu bar above. As of
this writing, the exchange rate was €0.96 to $1. A quirk of this UI is you can only enter whole integer amounts
even if the asset is divisible, but we can get around that by making our offer $100 for €96.
6. Now that we’ve expanded our Market to handle foreign currency, all that’s left to do is Sign out.
Baking Biscotti
We’re going to create a new participant, Claudio, who will bake some biscotti and put them on sale in our newly
international market.
1. Go through the steps to generate a new WIF key and create a new participant detailed above.
2. Once Claudio is provisioned, create a new biscotti asset just like we did Euros.
3. And just like Abby in the previous scenario, we will bake our first batch by creating a holding.
4. We’ll also create an empty savings account for Claudio to keep the Euros that are sure to be pouring in soon.
5. Finally, we’ll put the biscotti up for sale by creating an offer that will take €3 for 2 biscotti.
6. Claudio is all set, so let’s go ahead and Sign out.
Buying Biscotti
Almost finished. We’ll log back in as Ben who, always craving new cookie experiences, will purchase some biscotti
from Claudio.
1. Log Ben in by importing his WIF key just like we did with Market above.
2. Click on Latest Open Offers.
3. Click the Accept button to the right of Claudio’s biscotti offer.
4. Now we could have a problem. Claudio is asking for Euros, and we can see if we click on Initial Holding that
we don’t have any of those. But fear not, arbitrage to the rescue! Click on the + Offer button to right of the
initial holding dropdown. From the pop-up that appears, you can select the Market’s USD for Euro exchange
offer.
5. Now we are free to select our USD savings account as the initial holding, and route those dollars through the
Market’s exchange to our intended biscotti target, which we will keep in a new /jar holding.
Note
This exchange exposes some of the quirks of the Quantity field that may not be immediately obvious. It
represents the number of times the smallest possible integer representation of the initial exchange is going to be
executed. So for example, in this case our $100 -> €96exchange has been reduced to $25 -> €24 (the smallest
integer representation). That €24 buys you 16 biscotti, so by entering a 2 into the Quantity field, we will spend
$50, and receive 32 biscotti. It is generally best when making exchanges to double check the calculated holding
amounts before clicking Accept.
6. Click Accept and enjoy those sweet sweet digital biscotti.
Next Previous
TUTORIAL
Overview
Marketplace Navigator is a browser-based GUI designed to be used with the Sawtooth Lake Marketplace
transaction family. It allows users to easily register Participants, create and exchange Assets and Holdings,
and even view the current state of the blockchain.
Navigator Tasks
Account Creation and Setup
Creating a Participant
Signing in an Existing Participant
Creating an Asset
Creating a Holding
Creating an Offer
Accepting an Offer
Chaining Offers (Arbitrage)
Transfering Assets Directly
Creating a Participant
The first time you sign into Marketplace Navigator you will be prompted to either create or import a
“Wallet Import Format” (WIF) key. This is a unique cryptographic string used by the blockchain to
authorize transactions, as well as by Marketplace Navigator to confirm your identity and sign you in.
Note
1. Open Marketplace Navigator in your browser, or sign out of Marketplace Navigator if already signed
in. You should see this screen:
2. Click Generate WIF, and a key will be generated and saved to your browser’s local storage.
3. Before proceeding to account creation, you must save the generated key by:
Participants’ names must be unique. If you encounter a server error at this point, it could be caused by
using a name that has already been taken.
If participant creation was successful the provisioning screen should appear:
After several minutes, the participant is fully provisioned, and you will be brought to the user dashboard:
Note
Beyond this point, the directions all assume you are successfully signed in.
Creating an Asset
Assets are types of goods which can be exchanged on the marketplace. They can include anything from
US Dollars, to barrels of oil, to cookies. Assets are further organized into AssetTypes, such as currency or
baked goods. Any participant can create new assets and types, and many kinds of markets to be
approximated.
1. From the user dashboard, click on the + button to the right of the “Assets” heading:
2. Enter a Name for the asset. Like most names in Marketplace, it must begin with a “/” character, and
generally follows a naming convention similar to a computer directory. For example: “/currency/usd”.
This field can be left blank, but that will generate a long randomized identifier, and is generally not
recommended.
3. (Optional) Enter a Description.
4. Enter a Type by either:
Note
You may click Discard to close the Add Type pop up.
5. Use the checkboxes at the bottom to choose which options should apply to this asset:
Restricted - Only the creating participant will be able to create new Holdings of this asset with quantities
greater than zero.
Consumable - When spent, this asset is consumed. If disabled, it is effectively infinite.
Divisible - This asset can exist in fractional form. In other words, it will be possible to exchange half of one
(or less).
6. Click Submit.
Creating a Holding
Holdings are containers where actual quantities of specific Assets are held. Each may only hold one kind of
asset, and in order to execute Exchanges, participants must have holdings in both the assets they are
providing and receiving.
1. From the user dashboard, click on the + button to the right of the “Holdings” heading:
2. Enter a Name for the holding. Once again the name must begin with a “/”, and generally follows a
convention similar to computer directories, such as “/accounts/checking”. If left blank, a random
identifier will be generated for the holding.
3. (Optional) Enter a Description.
4. Select an Asset from the dropdown menu.
5. Enter a Count for your holding.
Note
If you are not the creator of the asset, and that asset is “restricted”, you can still create holdings for it,
but you must enter a count of zero.
6. Click Submit.
Creating an Offer
Offers are open offers of exchange, which any participant or multiple participants can accept. In order to
create an offer you must have Holdings in both the Asset you are providing and the one you expect to
receive in return, though the latter can be empty (i.e. have a count of zero).
1. Click on the Create Offer button in the top right of your screen.
2. Enter a Name for the offer. Once again the name must begin with a “/”, and generally follows a
convention similar to computer directories, such as “/orders/cookies”. If left blank, a random identifier
will be generated for the holding.
3. (Optional) Enter a Description.
4. Select the Input holding from the dropdown. This is where payments you receive will go, and those
payments will be of the kind of asset in the holding.
5. Enter the Amount of input asset you expect to receive.
6. Select an Output holding from the dropdown. This is where the payouts you are offering will come
from.
7. Enter an Amount for the output asset.
Note
Using the Amount fields, you are actually creating an exchange ratio, not a fixed sum. So setting
amounts of 50 and 100 is equivalent to 5 and 10, 1 and 2, and so on. There is currently no way to
create a fixed indivisible package like “$10 for half a dozen cookies”.
8. Enter a Minimum. This is the lowest quantity of the input asset that can be used to fulfill the offer.
9. Enter a Maximum, the highest quantity of an input that can be used.
10. Select how repeatable the offer should be:
Any - the offer can be fulfilled an unlimited number of times (or until the output holding is empty).
Execute Once - it is a one time offer, and will close after being fulfilled once.
Execute Once per Participant - Each participant in the marketplace may fulfill the offer once.
11. Click Submit.
Accepting an Offer
In order to accept an offer made by another participant, you must have Holdings for both the Assetyou
need to pay with, and the asset you expect to receive in return, though it is possible to create the latter as
part of the exchange process.
If you would like to store the received assets in a new holding, select New Holding from the
dropdown, and enter the name of the holding into the text field that appears. As usual, this name
must begin with a “/”.
5. Enter the Quantity of exchanges you would like to execute.
Note
In this case, Quantity refers not to the count of either asset being transfered, but to the smallest
integer expression of the exchange ratio the offer was originally set at. For example, if the offer was
originally an 80:100 exchange, the smallest integer expression would be 4:5. So a Quantity of 1 would
payout 4 of the input, and receive back 5 of the output.
6. Click Accept.
Chaining Offers (Arbitrage)
It is possible to chain together multiple offers using the + Offer buttons next to the initial
holdingand final holding dropdowns. This allows you to build a chain of exchanges which can include
assets you have no Holdings in. For example, it is possible to trade US Dollars for Euros for some
authentic Italian biscotti, even though you have no holding of Euros.
Click on either + Offer button, to bring up a dropdown of any available offers with the appropriate asset types.
Select an offer from the list to add it to the chain.
The initial + Offer adds offers to the beginning, and the latter adds them to the end.
After being added, an offer can be removed from the beginning or end with the - Offer button that appears.
3. From the Source dropdown, select a holding for the assets to originate from.
4. Select a Participant to whom you wish to transfer the asset. The default of Self will transfer assets
between your own holdings.
5. Select a Destination holding from the final dropdown. It will display only holdings that match the kind
of asset being transfered and belong to the participant selected.
6. Enter the Amount you would like to transfer.
7. Click Transfer.
Next Previous
Architecture Overview
What is the Sawtooth Lake Distributed Ledger?
The Sawtooth Lake Distributed Ledger is a software framework for constructing decentralized ledgers
with extensible transaction types. It is comparable to the blockchain ledger that underlies Bitcoin.
Sawtooth Lake uses a unique mechanism for reaching consensus on the validity of the ledger based on
trusted code running inside a hardware-protected Intel Software Guard Extensions (SGX) enclave.
One of the initial transaction families supported by Sawtooth Lake is the MarketPlace. The MarketPlace
Transaction Family establishes the concepts of participants, accounts, assets, holdings, liabilities, and
offers in a decentralized ledger to facilitate the exchange of digital assets. The Sawtooth Lake architecture
allows the definition of additional transaction families or the consumption of an existing asset-type
agnostic transaction family (like MarketPlace) to meet domain-specific needs.
Repository Structure
One repository contains all of the the code needed:
sawtooth-core
Contains fundamental classes used throughout the Sawtooth Lake project, as well as:
Core Architecture
The Sawtooth Lake Distributed Ledger consists of three major architectural layers: the Ledger layer, the
Journal layer, and the Communication Layer.
Ledgers
Ledgers are a conceptual semantic and data model layer for transaction types. Ledgers are described as a
‘conceptual’ layer because they are implemented as a specialization of existing base classes already
present in the Communication and Journal layers.
In addition to some in-built system ledgers (Endpoint Registry, and Integer Key Registry), implementing
new classes in the ledger layer allows for the creation of new transaction families. The MarketPlace
Transaction Family, located in the extensions directory of sawtooth-core, is a good example of how the
ledger layer can be extended.
Journals
A journal handles consensus on blocks of identifiers. Identifiers reference transactions, which are globally
replicated. In order to confirm blocks, nodes need a copy of the transaction. In this fashion, the journal
provides global consensus on block ordering, transaction ordering within blocks, and the content of
transactions.
Consensus Mechanisms
The implementation of PoET in Sawtooth Lake runs in a simulated enclave, not a true trusted execution
environment. For this reason, attestation that wait timers have been fairly generated is not possible. This
version of PoET is intended for experimental purposes and should not be used as the consensus
mechanism in any ‘production’ environment.
Transactions
A transaction is a set of updates to be applied atomically to a ledger. The transaction defines the data
model and representation. For example, in the IntegerKey Transaction Family (located in
ledger.transaction.integer_key in sawtooth-core), the IntegerKeyTransaction is defined as a list of zero or
more updates to key value pairs using the defined verbs ‘set’, ‘inc’, and ‘dec’. The associated
IntegerKeyTransactionMessage wraps the derived transaction object in a standard message object. There
is typically a message type for every transaction type.
Blocks
A block is a set of transactions to be applied to a ledger. Other than some specialized transaction block
implementations for the consensus mechanisms, new transaction block types are not typically created.
The expectation is that multiple transaction types will coexist on single transaction blocks of type
journal.transaction_block.TransactionBlock. There is typically a message type for every transaction block
type.
Communication
The gossip protocol enables communication between nodes. It includes protocol level connection
management and basic flow control on top of UDP. A Token Bucket [1] implementation is used to limit the
average rate of message transmission.
[1] https://en.wikipedia.org/wiki/Token_bucket
Peers in the gossip network are called Nodes. Nodes exchange Messages. Message handling upon arrival
is dispatched via EventHandlers associated with the journal.
Messages
Messages represent information to send or receive from peers over the gossip network. Messages are
serialized and deserialized using a standard wire format (either CBOR or JSON).
transaction messages
transaction block messages
journal transfer messages
debug messages (log data)
connection messages
shutdown messages
topology messages
Messages are used broadly across the architecture for both system communication (administrative
messages, consensus messages), and for transaction-type specific handling.
If specialized transaction stores are required, those can also be defined and added to the ledger during
initialization (via register_transaction_types).
def register_transaction_types(ledger)
Register message handlers for defined message types and add a transaction store to the ledger for the
transaction types.
class BasicTransactionMessage(transaction_message.TransactionMessage)
implement __init__
class BasicTransaction(transaction.Transaction)
implement __init__, __str__, is_valid, apply, and dump
Next Previous
Vagrant
Overview
Vagrant is a tool which installs and configures virtual development environments. It allows development
teams to easily specify and share consistent virtual machine configurations.
The dev tools directory (path ‘’sawtooth-core/tools’‘) of the sawtooth-core repository contains a Vagrant
configuration which is specifically tailored to Sawtooth development. A new developer with installed
copies of Vagrant and VirtualBox can clone the sawtooth-core repository and have a functional VM which
can run validators within a few minutes.
A quick introduction to using dev tools is available as a quickstart in this Developer’s Guide.
tools/
bootstrap.d/
guest-files/
plugins/
scripts/
tests/
win-bin/
Vagrantfile
Vagrantfile
Vagrantfile is the main configuration file for Vagrant. It is ruby code executed by Vagrant and is executed
every ime a vagrant command is executed.
bootstrap.d
The bootstrap.d directory contains a set of bash scripts which are executed in order during the provisioning
step of ‘vagrant up’. These scripts are always executed.
guest-files
The guest-files directory contains configuration files which are used by the bootstrap.d scripts.
There is also a local-env.sh script which contains environment specific variables for Sawtooth
development, such as PYTHONPATH.
plugins
The plugins directory contains bash scripts which can be easily configured to execute during the
provisioning step of ‘vagrant up’. These scripts run after bootstrap.d scripts.
scripts
This scripts directory contains scripts which are sometimes useful to the developer after provisioning has
been completed and the developer has a shell in the virtual machine. For example, there are scripts which
help build Ubuntu packages.
tests
The tests directory includes tests run within the Vagrant environment. These are in addition to the unit and
integration tests found in the tests directory of sawtooth-core, sawtooth-validator and sawtooth-mktplace.
win-bin
The win-bin directory includes scripts for running Sawtooth natively under Windows and is not used in the
Vagrant environment.
In the dev tools configuration a /project mount point is also defined which provides access to the
Sawtooth repositories.
Configuration Options
There is a rudimentary configuration system in place which can impact how the Vagrant environment is
provisioned.
conf-defaults.sh
conf-local.sh
conf-local.sh.example
The conf-local.sh file, which is not checked into the git repository, is the one that should be modified
locally. This file can be initialized by copying conf-local.sh.example to conf-local.sh.
The conf-default.sh file defines the defaults for configuration values which are not set.
START_TXNVALIDATOR
By default, this is set to ‘no’. If set to ‘yes’, then txnvalidator will be started with upstart or systemd. For this
option to work, INSTALL_TYPE must be set to ‘deb’.
PLUGINS
By default, set to “build_ubuntu_deps install_ubuntu_deps install_sphinx”. Specify a space-separated list of
plugins to run. The plugins are contained in the plugins directory.
build_ubuntu_deps
This plugin builds the debian packages for cbor, colorlog, and pybitcointools. They are placed in
/project/build/packages/.
install_latex
This plugin installs Latex, which is required for building a PDF of the documentation. This is disabled by
default because it takes a fairly long time to download.
install_ubuntu_deps
This plugin installs the debian packages built by build_ubuntu_deps.
install_sphinx
This plugin installs sphinx, which is required for building the sawtooth documentation.
Next Previous
Note that the authoritative log of transactions and the cached state of objects associated with the log can
be retrieved through the Distributed Ledger Web API.
Participant
A participant object refers to an organization or an individual. Conceptually, the participant object refers
to the “owner” of an asset. Participants can create assets (and asset types), own assets, offer to exchange
assets, and transfer ownership to another participant.
The current model for a participant is very simple: it is a means of capturing the information necessary to
authorize transactions on assets owned by the participant.
"Participant" :
{
"type" : "object",
"properties" :
{
"address" :
{
"type" : "string",
"format" : "ADDRESS",
"required" : true
},
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "object",
"required" : false
}
}
}
The properties of a Participant include:
a unique derivation of the verifying key (public key) for the transaction used to register the participant; the
address: address provides a means of verifying the identity of participants for future transaction verification and
authorization
a unique name for the participant chosen by the person or organization creating the participant, names are
name:
constructed from printable ascii characters with the exception of ‘/’
description: an optional property for describing in human readable form who or what the participant represents
Account
An account object represents a collection of holdings and liabilities with at most one holding for each
asset and at most one liability for each asset type. An account is useful primarily as a means of managing
asset aggregation.
"Account" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
}
}
}
The properties of a Account include:
a unique name for the object chosen by the person or organization creating the participant, names are
name:
constructed from printable ascii characters and must begin with ‘/’
description: an optional property for describing in human readable form who or what the object represents
creator: the identifier of the participant who registered the account object
AssetType
An AssetType is a descriptor for a class of Assets. The creator of an AssetType is granted the right to
create Assets of the type and assign them to owners within a Holding. If the Restricted flag is True (it is
True by default), then the creator of the AssetType is the only participant who can create Assets of that
type. This would be appropriate, for example, for controlling creation of private stock certificates. If the
Restricted flag is False, then any Participant can create Assets of that type and assign ownership to a
participant within a Holding. This would be appropriate for broad asset types like “brown eggs” where
many Participants are likely to create Assets of the type.
"AssetType" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
},
"restricted" :
{
"type" : "boolean",
"default" : true,
"required" : false
}
}
}
The properties of a AssetType include:
a unique name for the object chosen by the person or organization creating the participant, names are
name:
constructed from printable ascii characters and must begin with ‘/’
description: an optional property for describing in human readable form who or what the object represents
creator: the identifier of the participant who registered the account object
a flag to indicate whether the creator of the asset type (if the flag is True) or other participants (if the flag is
restricted:
False) can create assets of the type
Asset
An Asset is an instance of an Asset Type. It is intended to represent a “thing” to which value and
ownership can be ascribed. Assets may be strictly intrinsic to the MarketPlace such as instances of a
virtual currency or MarketPlace tokens. Alternatively, assets may provide a MarketPlace handle for digital
or physical objects that exist outside of the MarketPlace.
"Asset" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
},
"asset-type" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#AssetType",
"required" : true
},
"restricted" :
{
"type" : "boolean",
"default" : true,
"required" : false
},
"consumable" :
{
"type" : "boolean",
"default" : true,
"required" : false
},
"divisible" :
{
"type" : "boolean",
"default" : false,
"required" : false
}
}
}
The properties of a Asset include:
a unique name for the object chosen by the person or organization creating the participant, names are
name:
constructed from printable ascii characters and must begin with ‘/’
description: an optional property for describing in human readable form who or what the object represents
creator: the identifier of the participant who registered the account object
asset-type: the identifier of the asset type from which the asset was created
a flag to indicate whether the creator of the asset (if the flag is True) or other participants (if the flag is False)
restricted:
can create Holdings for the asset with non-zero counts
a flag to indicate whether assets are transferred (if the flag is True) or copied (if the flag is False); Holdings
consumable: with non-consumable assets always have an instance count of zero or one since a non-consumable asset can
be copied infinitely
divisible: a flag to indicate whether fractional portions of assets are acceptable (if the flag is True)
Holding
A Holding object represents ownership of a collection of asset instances and controls the right to transfer
assets to a new owner. Any participant can create an empty (i.e. the instance-count property is 0) holding
for any asset. An empty Holding represents a container into which assets may be transferred. To create a
holding with instance-count greater than 0, the creator of the holding must be the creator of the asset or
the asset must be non-restricted.
"Holding" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
},
"account" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Account",
"required" : true
},
"asset" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Asset",
"required" : true
},
"instance-count" :
{
"type" : integer,
"required" : true
}
}
}
The properties of a Holding include:
a unique name for the object chosen by the person or organization creating the participant, names are
name:
constructed from printable ascii characters and must begin with ‘/’
description: an optional property for describing in human readable form who or what the object represents
creator: the identifier of the participant who registered the account object
Liability
Like a Holding, a Liability represents ownership though in the case of a Liability ownership is of a debt or
financial obligation. Where a Holding captures ownership of specific asset instances, a Liability captures a
promise or guarantee for future ownership transfer of a specific kind of asset.
"Liability" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
},
"account" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Account",
"required" : true
},
"asset-type" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#AssetType",
"required" : true
},
"instance-count" :
{
"type" : integer,
"required" : true
},
"guarantor" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
}
}
}
The properties of a Liability include:
a unique name for the object chosen by the person or organization creating the participant, names are
name:
constructed from printable ascii characters and must begin with ‘/’
description: an optional property for describing in human readable form who or what the object represents
creator: the identifier of the participant who registered the account object
ExchangeOffer
An ExchangeOffer represents an offer to exchange assets or liabilities of one type for assets or liabilities
of another type. Assets or liabilities are received into an input holding or liability. The ratio expresses the
number of assets to be transferred out for every one that is transferred in.
"ExchangeOffer" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
},
"input" :
{
"type" : "string",
"format" : "IDENTIFIER",
"oneOf" : [
{ "$ref" : "#Liability"},
{ "$ref" : "#Holding" }
],
"required" : true
},
"output" :
{
"type" : "string",
"format" : "IDENTIFIER",
"oneOf" : [
{ "$ref" : "#Liability"},
{ "$ref" : "#Holding" }
],
"required" : true
},
"ratio" :
{
"type" : float,
"required" : true
},
"minimum" :
{
"type" : int,
"required" : false
},
"maximum" :
{
"type" : int,
"required" : false
},
"execution" :
{
"type" : "string",
"oneOf" : [ "ExecuteOnce", "ExecuteOncePerParticipant", "Any" ],
"required" : false
}
}
}
The properties of an ExchangeOffer include:
name: a unique name for the object chosen by the person or organization creating the participant, names are
constructed from printable ascii characters and must begin with ‘/’
description:
an optional property for describing in human readable form who or what the object represents
creator:
the identifier of the participant who registered the account object
input: a Holding or Liability into which “payment” is made, this defines the kind of asset that will be received
by the creator of the offer
a Holding or Liability from which goods will be transferred, this defines the kind of asset that will be
output:
given by the creator of the offer, the creator of the offer must be the same as the creator of the holding
or liability
ratio: the number of instances to transfer from the output holding for each instance deposited into the input
holding
minimum: the smallest number of acceptable instances that can be transferred into the input holding for the offer
to be valid
maximum: the largest number of acceptable instances that can be transferred into the input holding in one
transaction for the offer to be valid
a modifier that defines additional conditions for execution of the offer, it may have one of the
following values:
execution: ExecuteOncePerParticipant
SellOffer
A SellOffer is identical to an ExchangeOffer except that assets must be transferred out from a Holding.
"SellOffer" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string",
"required" : false
},
"description" :
{
"type" : "string",
"required" : false
},
"creator" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Participant",
"required" : true
},
"input" :
{
"type" : "string",
"format" : "IDENTIFIER",
"oneOf" : [
{ "$ref" : "#Liability"},
{ "$ref" : "#Holding" }
],
"required" : true
},
"output" :
{
"type" : "string",
"format" : "IDENTIFIER",
"$ref" : "#Holding",
"required" : true
},
"ratio" :
{
"type" : float,
"required" : true
},
"minimum" :
{
"type" : int,
"required" : false
},
"maximum" :
{
"type" : int,
"required" : false
},
"execution" :
{
"type" : "string",
"oneOf" : [ "ExecuteOnce", "ExecuteOncePerParticipant", "Any" ],
"required" : false
}
}
}
The properties of a SellOffer include:
name: a unique name for the object chosen by the person or organization creating the participant, names are
constructed from printable ascii characters and must begin with ‘/’
description:
an optional property for describing in human readable form who or what the object represents
creator:
the identifier of the participant who registered the account object
input: a Holding or Liability into which “payment” is made, this defines the kind of asset that will be received
by the creator of the offer
output: a Holding from which goods will be transferred, this defines the kind of asset that will be given by the
creator of the offer, the creator of the offer must be the same as the creator of the holding
ratio: the number of instances to transfer from the output holding for each instance deposited into the input
holding
minimum: the smallest number of acceptable instances that can be transferred into the input holding for the offer
to be valid
maximum: the largest number of acceptable instances that can be transferred into the input holding in one
transaction for the offer to be valid
a modifier that defines additional conditions for execution of the offer, it may have one of the
following values:
ExecuteOncePerParticipant:
The remainder of these instructions assume a vanilla Ubuntu 14.04 installation as a starting point. An easy
method to obtain such a machine is by creating one with vagrant:
Install Dependencies
Apply the latest Ubuntu updates:
vagrant@ubuntu $ cd $HOME/projects
vagrant@ubuntu $ wget https://pypi.python.org/packages/source/c/colorlog/colorlog-2.6.0.tar.gz
vagrant@ubuntu $ tar xvfz colorlog-2.6.0.tar.gz
vagrant@ubuntu $ cd colorlog-2.6.0
vagrant@ubuntu $ python setup.py --command-packages=stdeb.command bdist_deb
vagrant@ubuntu $ cp deb_dist/python-colorlog*.deb $HOME/packages/
pybitcointools
vagrant@ubuntu $ cd $HOME/projects
vagrant@ubuntu $ wget https://pypi.python.org/packages/source/p/pybitcointools/pybitcointools-1.1.15.tar.gz
vagrant@ubuntu $ tar xvfz pybitcointools-1.1.15.tar.gz
vagrant@ubuntu $ cd pybitcointools-1.1.15
vagrant@ubuntu $ python setup.py --command-packages=stdeb.command bdist_deb
vagrant@ubuntu $ cp deb_dist/python-pybitcointools*.deb $HOME/packages/
vagrant@ubuntu $ cd $HOME/projects/sawtooth-core
vagrant@ubuntu $ ./bin/package_validator
vagrant@ubuntu $ cp python-sawtooth-validator*.deb $HOME/packages/
vagrant@ubuntu $ cd $HOME
vagrant@ubuntu $ mv packages sawtoothlake-x.y.z-ubuntu-packages
vagrant@ubuntu $ tar cvfj sawtoothlake-x.y.z-ubuntu-packages.tar.bz2 sawtoothlake-x.y.z-ubuntu-packages
Note
The x.y.z in the above tar file name should be replaced with the version of the overall sawtoothlake
deliverable.
Next Previous
FAQ
Validators
How do I change the validator configuration?
$ cd /project/sawtooth-core
$ ./bin/txnvalidator -v --config validator/etc/single-node.js
Multiple config files can be overlaid, and all of the settings in the config file can be overridden on the
command line, but that’s beyond the scope of this answer.
TargetWaitTime The desired mean inter-block commit time across the network. While the default is 30
seconds, we recommend 5 seconds for development and experimenting.
InitialWaitTime This is only important when starting the first node which will initialize the ledger
(i.e. GenesisLedger is true). This will often be the case when testing. We recommend setting it to the same
value as TargetWaitTime.
Previous
Chaincode for Go developers, Part 1: Writing Blockchain
chaincode in Go for Hyperledger Fabric v0.6
Learn how to develop chaincode using Golang for a blockchain network based on Hyperledger Fabric v0.6. This
deep-dive tutorial covers the fundamentals, such as the APIs for interacting with the Fabric, as well as advanced
topics like data modeling, access control, and events. Abundant sample code demonstrates a home loan and
purchase contract process on blockchain.
Get a monthly roundup of the best free tools, training, and community resources to help you put
Blockchain to work. Current issue | Subscribe
In this tutorial, learn how to develop chaincode using Golang for a blockchain network based on Hyperledger Fabric
v0.6. I cover the fundamentals, such as the role of chaincode and the APIs for interacting with the underlying Fabric,
as well as advanced topics like data modeling, access control, and events. Abundant code examples demonstrate a
home loan and purchase contract process on blockchain. (See "Downloadable resources" at the end of this tutorial
to download the entire sample chaincode.)
This tutorial is the first of a series; follow-on tutorials will cover how to unit test your chaincode and develop client
applications that can invoke your deployed chaincode.
What is chaincode?
Try IBM Cloud for free
© Copyright IBM Corporation 2017 Trademarks Build your next app quickly and easily with IBM Cloud Lite. Your free account never expires, and you
get 256 MB of Cloud Foundry runtime memory, plus 2 GB with Kubernetes Clusters. Get all the details and find out how to get started.
Chaincode, also called the smart contract, is essentially the business logic that governs how the different entities or
parties in a blockchain network interact or transact with each other. Simply put, the chaincode is the encapsulation
of business network transactions in code. Invocations of the chaincode result in sets and gets of the ledger or world
state.
At the time of publishing this tutorial, Hyperledger supports writing chaincode in Golang or the Java™ language,
which eventually runs inside a docker container. Because chaincode support for Java is still in beta, I'll focus on Go in
this tutorial.
Follow the steps in the IBM Cloud documentation starting at "Setting up the development environment." When you
reach the section titled "Set up your development pipeline," stop there; you are now ready to start developing
chaincode in Go.
Chaincode structure
Let's take a close look at chaincode structure. As mentioned, the sample chaincode in Listing 1 and throughout
this tutorial, as well as the architecture discussed, strictly conform to the v0.6 preview of the Hyperledger
Fabric.
Line 4 of Listing 1 imports the shim package into your chaincode. The shim package provides APIs that let your
chaincode interact with the underlying blockchain network to access state variables, transaction context, caller
certificates and attributes, and to invoke other chaincodes, among other operations.
func main() {
err := shim.Start(new(SampleChaincode))
if err != nil {
fmt.Println("Could not start SampleChaincode")
} else {
fmt.Println("SampleChaincode successfully started") }
Main function
The starting point for any Go program is the main function, and hence it's used for bootstrapping/ starting the
chaincode. When the peer deploys its instance of the chaincode, the main function gets executed.
As shown in line 2 of Listing 2, the shim.Start(new(SampleChaincode)) line starts the chaincode and registers it
with the peer. You can verify this locally by running the code in your development environment, which will
produce the following error: [shim] CRIT : peer.address not configured, can't connect to peer. Listing 2.
Main()
func main() {
err := shim.Start(new(SampleChaincode))
if err != nil {
fmt.Println("Could not start SampleChaincode")
} else {
fmt.Println("SampleChaincode successfully started") }
The SampleChaincode is the struct that is required to implement the shim.Chaincode interface, which has three
methods — Init, Query, and Invoke — for it to be considered a valid Chaincode type by the shim package. Let's look
at each of the three methods.
Init method
The Init method is called when the chaincode is first deployed onto the blockchain network and will be executed by
each peer that deploys its own instance of the chaincode. This method can be used for any tasks related to
initialization, bootstrapping, or setup.
Listing 3. Init()
func (t *SampleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte,
error) { return nil, nil
}
Query method
The Query method is invoked whenever any read/get/query operation needs to be performed on the blockchain
state. Depending upon the complexity of the chaincode, this method can hold your read/get/query logic, or it could
be outsourced to separate methods that can be invoked from within the Query method.
The Query method is not intended to change the state of the underlying blockchain, and hence does not run within
a transactional context. If you try to modify the state of the blockchain within the Query method, an error will
complain about the lack of a transactional context. Also, because this method is only for reading the state of the
blockchain, its invocations are not recorded on the blockchain.
Listing 4. Query()
func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte,
error) { return nil, nil
}
Invoke method
The Invoke method is invoked whenever the state of the blockchain is to be modified. Simply put, all create,
update, and delete operations should be encapsulated within the Invoke method. Because this method will modify
the state of the blockchain, the blockchain Fabric code will automatically create a transaction context inside which
this method will get executed. All invocations of this method are recorded on the blockchain as transactions, which
ultimately get written into blocks.
Listing 5. Invoke()
func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte,
error) { return nil, nil
}
1. World state, which is stored in a key value store. This key value store is powered by the RocksDB. This key
value store takes in a byte array as the value, which can be used to store a serialized JSON structure.
Essentially this key value store can be used to store any custom data model/schema required by your smart
contract to function.
2. Blockchain, which consists of a series of blocks each containing a number of transactions. Each block
contains the hash of the world state and is also linked to the previous block. Blockchain is append-only.
Listing 6 shows how to create custom data models/schemas. It defines data models required for a home loan
application. The primary model is called LoanApplication, which in turn has primitive and complex data types,
namely Personal and Financial Info.
Since our key value store stores data as JSON, these data models would eventually need to be converted into a
JSON string. The annotation for each field, for example, json:"id" acts like metadata for the marshal/unmarshal
API, which will use these annotations to map each field with its corresponding json string equivalent
representation.
Listing 6. Code to create custom data models/schemas
//custom data models type
PersonalInfo struct {
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
DOB string `json:"DOB"`
Email string `json:"email"`
Mobile string `json:"mobile"`
}
On line 9, the loan application Id value, which would be used as the key to store the actual loan application object, is
retrieved.
On line 10, the actual loan application content is retrieved in the form of a JSON string. For example,
‘{"propertyId":"prop1","landId":"land1","permitId":"permit1","buyerId":"vojha24","personalInfo":
{"firstname":"Varun","lastname":"Ojha","dob":"dob","email":"varun@gmail.com","mobile":"99999999"},"finan
{"monthlySalary":10000,"otherExpenditure":0,"monthlyRent":1000,"monthlyLoanPayment":1000},"status":" 2:30pm"}’
Line 12 is where the stub.PutState method is invoked to store the loan application id and the actual loan application
JSON content as a key value pair into the blockchain ledger. Note that the value being stored in the key value store
must always be a byte array. Hence the loan application JSON string is first converted to a byte array before storing
it into the ledger.
if len(args) < 2 {
fmt.Println("Invalid number of args")
return nil, errors.New("Expected at least two arguments for loan application creation") }
On line 9, the loan application Id value, which would be used as the key to retrieve the actual loan application object
from the ledger, is retrieved.
Line 10 is where the stub.GetState method is invoked to retrieve the loan application JSON content in the form of a
byte array by passing in the loanApplicationId key. Note that the value being stored in the key value store must
always be a byte array. Hence the loan application JSON string is first converted to a byte array before storing it into
the ledger.
if len(args) < 1 {
fmt.Println("Invalid number of arguments")
return nil, errors.New("Missing loan application ID") }
Listing 9 shows how to marshal a struct into a JSON string byte array that can then be stored in the ledger. Line 2
creates an instance of the PersonalInfo object. Line 3 uses the json package to marshal the object into a JSON string
and return the byte array for the same.
The json package can be imported by including "encoding/json" in the import block at the top. This byte array can
then be stored in the ledger using the stub.PutState method demonstrated in Listing 7.
Listing 10 shows how to unmarshal a struct from a byte array into a populated struct. Line 1 fetches the
PersonalInfo JSON string bytes from the ledger using the associated key. Line 3 unmarshals the bytes retrieved in
line 1 into the PersonalInfo object referenced by the variable personalInfo.
Now you can access and modify the personalInfo object using the dot notation as shown in line 4.
• Enrollment certificate: The certificate authority in the membership services will issue an enrollment certificate
to a user that wants to transact on blockchain as a proof of identity.
• Transaction certificate: The transaction certificate is supposed to be used as a one-time token that is passed
along each invocation request of the chaincode by the invoker/invoking application. The transaction
certificates are mathematically derived from the parent enrollment certificate, and hence a theoretically
unlimited number of transaction certificates can be generated from the parent enrollment certificate. The
transaction certificate can be used to sign and encrypt the transaction data when it is stored in the blockchain.
This ensures that only the user with the transaction certificate or a regulator/auditor etc. who has the parent
certificate can actually view the contents of the transaction once they have been written.
• Attributes: Each transaction certificate can hold a number of user-defined attributes. These can be mentioned
as a part of the registration request to the certificate authority from the client application. Follow-on tutorials
in this series will deal with this in detail from the perspective of developing the client application.
Listing 11 shows how the attributes can be retrieved from the transaction certificate of the caller. As mentioned
earlier, the user or the client application will need to pass in the user’s certificate as a part of each chaincode
invocation request so as to authenticate with the target peer on the blockchain network. The HFC SDK takes care
of passing the certificate as a part of the request automatically.
The Invoke function at line 11 of Listing 11 has been modified to check for the input function name and delegate the
call to the appropriate handler function. In addition, the Invoke function also validates the access and role of the
caller who has sent the CreateLoanApplication invocation request. The Invoke function calls the custom
GetCertAttribute function to retrieve a particular attribute from the transaction certificate of the caller.
The GetCertAttribute function fetches the attribute value by passing in the attribute name on line 3.
Line 15 checks whether the caller has the role of a Bank Admin and can invoke the
CreateLoanApplication function. If the caller does not have the required role, an appropriate error is returned. In
this way, attribute-based access control can be implemented in the chaincode.
The ChaincodeStubInterface has some utility functions that deal with attributes, such as ReadCertAttribute,
VerifyAttribute, and VerifyAttributes. All of these methods rely on the
github.com/hyperledger/fabric/core/chaincode/shim/crypto/attr package to create and use the
AttributeHandlerImpl that handles attributes.
In the version of Hyperledger Fabric that is currently under development (v1.0), these utility functions have been
removed from the ChaincodeStubInterface. Hence in v1.0, the chaincode developer would need to use the
AttributeHandlerImpl directly to work with attributes.
}
return nil, nil
}
• Block events
• Chaincode events
• Rejection events
• Register events
The code in Listing 12 shows how to create and publish a custom event.
Lines 1-4 define a custom event object containing type and description fields.
The CreateLoanApplication function starts on line 6 and has been modified to include the event
creation on successful creation of loan application.
Line 23 creates the instance of the customEvent object and fills in appropriate event details.
Line 24 marshals the event object to a JSON string byte array as explained earlier.
Line 28 sets the custom event. The stub.SetEvent method takes two arguments: the event name and
payload. The client application can subscribe to the same event name/topic to receive events as and
when they are generated by the chaincode.
if len(args) < 2 {
fmt.Println("Invalid number of args")
return nil, errors.New("Expected at least two arguments for loan application creation") }
• CRITICAL
• ERROR
• WARNING
• NOTICE
• INFO
• DEBUG
//Log statements
myLogger.Info("Info Message")
myLogger.Critical("Critical Message")
myLogger.Warning("Warning Message")
myLogger.Error("Error Message")
myLogger.Notice("Notice Message")
myLogger.Debug("Debug Message") }
• Store all files/objects as base64-encoded strings. The client application would convert the
file/object into a base64-encoded string and send it as an input parameter to a chaincode
function. The chaincode in turn can store it as a byte array in the key/value store.
• Store the actual file/object contents outside of blockchain; for example, in IBM Cloud Object
Storage service. Store only the link/reference/ID of the file/object on blockchain along with the
hash of the file/object. Storing the hash ensures that any tampering with the file/object
outside of blockchain can be detected by concerned parties/entities.
How can I avoid disclosing private business logic/contract details to all peers
in the network?
This question came up in a supply chain scenario where an end consumer of the blockchain solution
was not comfortable sharing private business logic/contract information (such as different
negotiated rates with different vendors) in the smart contract visible to all peers. In v0.6, this
situation can be solved using external system integration.
The solution: The business logic/rules/contract that the peer wants to keep private can be run as
a set of business rules in an external application like a service. The chaincode itself has the ability
to make outbound calls. So the chaincode could make REST API calls, for example, to the business
rules/logic service and fetch the results, thus keeping the logic hidden from the actual chaincode.
It is possible to integrate with systems external to blockchain from within the chaincode. For
example, the chaincode can be used to talk to external databases, APIs, etc. But it is important to
make sure that interaction with these systems does not make the chaincode non-deterministic.
• The business rules service can be modified without knowledge of the remaining peers, since it
is running outside of blockchain. Depending on the type of business interaction among the
different participants in the blockchain network, this could lead to trust issues.
• The business rules service must be available to all peers in the blockchain network who will run
the smart contract/chaincode.
• The solution can lead to chaincode becoming non-deterministic. Chaincode MUST be
deterministic. In a nutshell, if the same function in the chaincode is invoked with the same
parameters by multiple parties, the results should be the same. For example, if you use a
timestamp or a counter in your chaincode functions that are tied to the response, invocations
of the chaincode by multiple peers will lead to different results. This will lead to an inconsistent
ledger state among the different peers in the blockchain network.
Remember that each invocation of the chaincode causes all the peers that are part of the
consensus network to invoke the chaincode on their local copies of the ledger.
Note: In v1.0 of the Hyperledger Fabric that is currently under development, this problem has been
solved organically via changes to the architecture itself.
Conclusion
This tutorial began with the fundamentals of chaincode and then dove into the building blocks and
different APIs available for performing important tasks in the chaincode, such as access control,
data modeling, and event management. Download the consolidated code snippets in the
SampleChaincode.go file.
Part 2 of this series covers test-driven development of chaincode. The final part will show how to
develop Node.js client applications that can talk to the blockchain network and complete the
development story.
Downloadable resources
Everyday applications can consume the data from business networks, providing end
users with simple and controlled access points.
You can use Hyperledger Composer to quickly model your current business network,
containing your existing assets and the transactions related to them; assets are
tangible or intangible goods, services, or property. As part of your business network
model, you define the transactions which can interact with assets. Business networks
also include the participants who interact with them, each of which can be associated
with a unique identity, across multiple business networks.
Participants can have their access to transactions restricted based on their role as
either a buyer, seller, or realtor. The realtor can then create an application to present
buyers and sellers with a simple user interface for viewing open listings and making
offers. This business network could also be integrated with existing inventory system,
adding new houses as assets and removing sold properties. Relevant other parties
can be registered as participants, for example a land registry might interact with a
buyer to transfer ownership of the land.
All transactions submitted through a business network are stored on the blockchain
ledger, and the current state of assets and participants are stored in the blockchain
state database. The blockchain distributes the ledger and the state database across a
set of peers and ensures that updates to the ledger and state database are consistent
across all peers using a consensus algorithm.
Connection Profiles
Hyperledger Composer uses Connection Profiles to define the system to connect to.
A connection profile is a JSON document the is part of a business network card.
These profiles are usually provded by the creator of the system they refer to and
should be used to create business network cards in order to be able to connect to
that system.
Assets
Assets are tangible or intangible goods, services, or property, and are stored in
registries. Assets can represent almost anything in a business network, for example, a
house for sale, the sale listing, the land registry certificate for that house, and the
insurance documents for that house may all be assets in one or more business
networks.
Assets must have a unique identifier, but other than that, they can contain whatever
properties you define. Assets may be related to other assets or participants.
Participants
Participants are members of a business network. They may own assets and submit
transactions. Participant types are modeled, and like assets, must have an identifier
and can have any other properties as required.
Transactions
Transactions are the mechanism by which participants interact with assets. This could
be as simple as a participant placing a bid on a asset in an auction, or an auctioneer
marking an auction closed, automatically transferring ownership of the asset to the
highest bidder.
Queries
Queries are used to return data about the blockchain world-state. Queries are
defined within a business network, and can include variable parameters for simple
customization. By using queries, data can be easily extracted from your blockchain
network. Queries are sent by using the Hyperledger Composer API.
Events
Events are defined in the business network definition in the same way as assets or
participants. Once events have been defined, they can be emitted by transaction
processor functions to indicate to external systems that something of importance has
happened to the ledger. Applications can subscribe to emitted events through
the composer-client API.
Access Control
Business networks may contain a set of access control rules. Access control rules
allow fine-grained control over what participants have access to what assets in the
business network and under what conditions. The access control language is rich
enough to capture sophisticated conditions declaratively, such as "only the owner of
a vehicle can transfer ownership of the vehicle". Externalizing access control from
transaction processor function logic makes it easier to inspect, debug, develop and
maintain.
Historian registry
Playground Tutorial
In this step by step tutorial we'll walk through setting up a business network, defining
our assets, participants and transactions, and testing our network by creating some
participants and an asset, and submitting transactions to change the ownership of
the asset from one to another. This tutorial is intended to act as an introduction to
Hyperledger Composer concepts using the online playground environment.
Copy
/**
*/
namespace org.acme.mynetwork
o String tradingSymbol
o String description
o String mainExchange
o Double quantity
o String firstName
o String lastName
transaction Trade {
This domain model defines a single asset type Commodity and single participant
type Trader and a single transaction type Trade that is used to modify the owner of
a commodity.
Copy
/**
* @transaction
*/
trade.commodity.owner = trade.newOwner;
While you can have multiple model or script files, you can only have one access
control file in any business network.
1. Ensure that you have the Trader tab selected on the left, and click Create New
Participant in the upper right.
2. What you can see is the data structure of a Trader participant. We want some easily
recognizable data, so delete the code that's there and paste the following:
Copy
"$class": "org.acme.mynetwork.Trader",
"tradeId": "TRADER1",
"firstName": "Jenny",
"lastName": "Jones"
Copy
"$class": "org.acme.mynetwork.Trader",
"tradeId": "TRADER2",
"firstName": "Amy",
"lastName": "Williams"
Make sure that both participants exist in the Trader view before moving on!
Copy
"$class": "org.acme.mynetwork.Trade",
"commodity": "resource:org.acme.mynetwork.Commodity#ABC",
"newOwner": "resource:org.acme.mynetwork.Trader#TRADER2"
4. Click Submit.
5. Check that our asset has changed ownership from TRADER1 to TRADER2 , by expanding
the data section for the asset. You should see that the owner is listed
as resource:org.acme.mynetwork.Trader#TRADER2 .
6. To view the full transaction history of our business network, click All Transactions on
the left. Here is a list of each transaction as they were submitted. You can see that
certain actions we performed using the UI, like creating the Trader participants and
the Commodity asset, are recorded as transactions, even though they're not defined
as transactions in our business network model. These transactions are known as
'System Transactions' and are common to all business networks, and defined in the
Hyperledger Composer Runtime.
This tutorial gives an overview of the techniques and resources available to apply to
your own use case.
Note: This tutorial was written against the latest Hyperledger Composer build on
Ubuntu Linux running with Hyperledger Fabric v1.1 where referenced below and also
tested for a Mac environment.
Prerequisites
Before beginning this tutorial:
The easiest way to get started is to use the Yeoman generator to create a skeleton
business network. This will create a directory containing all of the components of a
business network.
1. Create a skeleton business network using Yeoman. This command will require a
business network name, description, author name, author email address, license
selection and namespace.
Copy
yo hyperledger-composer:businessnetwork
2. Enter tutorial-network for the network name, and desired information for
description, author name, and author email.
3. Select Apache-2.0 as the license.
4. Select org.acme.mynetwork as the namespace.
The first document to update is the model ( .cto ) file. This file is written using
the Hyperledger Composer Modelling Language. The model file contains the
definitions of each class of asset, transaction, participant, and event. It implicitly
extends the Hyperledger Composer System Model described in the modelling
language documentation.
/**
*/
namespace org.acme.mynetwork
o String tradingSymbol
o String description
o String mainExchange
o Double quantity
o String tradeId
o String firstName
o String lastName
transaction Trade {
Copy
/**
* @transaction
*/
trade.commodity.owner = trade.newOwner;
await assetRegistry.update(trade.commodity);
Copy
/**
*/
rule Default {
participant: "ANY"
operation: ALL
resource: "org.acme.mynetwork.*"
action: ALLOW
}
rule SystemACL {
participant: "ANY"
operation: ALL
resource: "org.hyperledger.composer.system.**"
action: ALLOW
Copy
After the command has run, a business network archive file called tutorial-
network@0.0.1.bna has been created in the tutorial-network directory.
After the runtime has been installed, a business network can be deployed to the
peer. For best practice, a new identity should be created to administer the business
network after deployment. This identity is referred to as a network admin.
Copy
2. To deploy the business network, from the tutorial-network directory, run the
following command:
Copy
The composer network start command requires a business network card, as well as
the name of the admin identity for the business network, the file path of
the .bna and the name of the file to be created ready to import as a business
network card.
3. To import the network administrator identity as a usable business network card, run
the following command:
Copy
The composer card import command requires the filename specified in composer
network start to create a card.
4. To check that the business network has been deployed successfully, run the following
command to ping the network:
Copy
The composer network ping command requires a business network card to identify
the network to ping.
1. To create the REST API, navigate to the tutorial-network directory and run the
following command:
Copy
composer-rest-server
The generated API is connected to the deployed blockchain and business network.
This tutorial uses the tutorial-network business network developed and deployed in
the Developer-Tutorial.
Prerequisites
Before beginning this tutorial:
The model file must be updated to contain events and a new transaction.
Copy
event TradeNotification {
transaction RemoveHighQuantityCommodities {
event RemoveNotification {
}
3. Save the changes to your model.
Now that the domain model has been updated, we can write the additional business
logic that gets executed when a transaction is submitted for processing. In this
tutorial we have added events and queries to the business logic below.
Copy
/**
* @transaction
*/
trade.commodity.owner = trade.newOwner;
tradeNotification.commodity = trade.commodity;
emit(tradeNotification);
await assetRegistry.update(trade.commodity);
}
/**
* @transaction
*/
let removeNotification =
getFactory().newEvent('org.acme.mynetwork','RemoveNotification');
removeNotification.commodity = trade;
emit(removeNotification);
await assetRegistry.remove(trade);
The first function tradeCommodity will change the owner property on a commodity
(with a new owner Participant) on an incoming Trade transaction and emit a
Notification event to that effect. It then persists the modified Commodity back into
the asset registry which is used to store Commodity instances.
Copy
*/
query selectCommodities {
statement:
SELECT org.acme.mynetwork.Commodity
query selectCommoditiesByExchange {
statement:
SELECT org.acme.mynetwork.Commodity
WHERE (mainExchange==_$exchange)
query selectCommoditiesByOwner {
statement:
SELECT org.acme.mynetwork.Commodity
}
query selectCommoditiesWithHighQuantity {
statement:
SELECT org.acme.mynetwork.Commodity
Copy
1. Switch to the terminal, change directory to the folder containing the tutorial-
network.bna .
2. Run the following command to update the business network:
Copy
Copy
composer network ping -c admin@tutorial-network
Copy
composer-rest-server
Step Six: Test the REST APIs and create some data
Open a web browser and navigate to http://localhost:3000/explorer . You should see
the LoopBack API Explorer, allowing you to inspect and test the generated REST API.
We should be able to see that the REST Endpoint called 'Query' has been added and,
upon expanding, reveals the list of REST Query operations defined in the business
network tutorial-network
Before we proceed, we need to create some data, to demonstrate queries
adequately. Using the sample JSON data provided, create 3 Traders (Participants)and
some more Commodities (Assets) using the REST APIs.
1. First, click on 'Trader' in the REST Explorer, then click on the 'POST' method on
/Trader, then scroll down to the Parameter section - create the following Trader
instances, in turn:
Copy
"$class": "org.acme.mynetwork.Trader",
"tradeId": "TRADER1",
"firstName": "Jenny",
"lastName": "Jones"
2. Click 'Try it out' to create the Participant. The 'Response Code' (scroll down) should
be 200 (SUCCESS)
3. Create another trader by copying the following JSON:
Copy
"$class": "org.acme.mynetwork.Trader",
"tradeId": "TRADER2",
"firstName": "Jack",
"lastName": "Sock"
Copy
"$class": "org.acme.mynetwork.Trader",
"tradeId": "TRADER3",
"firstName": "Rainer",
"lastName": "Valens"
5. Now scroll up to the top and click on 'Commodity' object in the REST Explorer.
6. Click on the POST operation and scroll down to the Parameters section: In the same
way as above, create two Commodity Asset records (see below) for owners TRADER1
and TRADER2:
Copy
"$class": "org.acme.mynetwork.Commodity",
"tradingSymbol": "EMA",
"description": "Corn",
"mainExchange": "EURONEXT",
"quantity": 10,
"owner": "resource:org.acme.mynetwork.Trader#TRADER1"
Copy
"$class": "org.acme.mynetwork.Commodity",
"tradingSymbol": "CC",
"description": "Cocoa",
"mainExchange": "ICE",
"quantity": 80,
"owner": "resource:org.acme.mynetwork.Trader#TRADER2"
Now that we have assets and participants, we can try out some queries.
The simplest REST query we can try out first is our named query selectCommodities .
Expand the 'Query' REST Endpoint and you will see the named queries we defined in
our model.
These queries are now exposed as REST queries and for which a /GET operation is
generated, Note that the description of the query (that we defined in our model
definition) is shown on the right hand side.
1. Expand the selectCommodities query.
2. Click the 'Try it Out' button.
Let's select all Commodities by their Exchange - for example 'EURONEXT' main
exchange.
1. Expand query Endpoint 'selectCommoditiesByExchange' and scroll to the
'Parameters' section.
2. Enter 'EURONEXT' in the 'Exchange' parameter.
3. Click 'Try it Out'.
The results reveal that only those Commodities with an Exchange of 'EURONEXT' are
shown in the response body
Perform Transaction update using results from named Query
Finally, you will recall we had defined a simple query that filters Commodities with a
Quantity greater than 60 in our query file. Queries are very powerful, when used in
transaction functions, as using queries allows transaction logic to set up the set of
assets or participants to perform updates on, or for creating remove actions for
example.
First check for yourself how many Commodities are present (use the 'Commodity'
/GET operation) and you should see at least two Commodities, one of which (Cocoa)
has a quantity > 60.
Scroll down and you should see a transactionId which represents the 'remove'
invocation (itself a blockchain transaction) inside of the transaction processor
function and which will update the world state - the Response Code should be 200
Finally, let's verify our Commodities status. Return to the 'Commodity' REST
Operations and once again perform a /GET operation....'Try it Out'.
The results should show that the Commodity asset 'Cocoa' has now gone, ie only
those Commodity assets with a quantity <= 60 still remain, ie asset 'Corn' in our
example. The named query fed the transaction update (to remove high quantity
Commodities) and which was executed in business logic.
Congratulations!
Well done, you've now completed this tutorial and we hope you now have a much
better idea of the power of queries in Composer. You can start creating/building
your own queries (or modifying the existing queries and adding associated data to
this business network - note: you would need to re-deploy any query changes) to try
out!
This tutorial will demonstrate the steps that an administrator needs to take in order
to deploy a blockchain business network to an instance of Hyperledger Fabric for a
single organization, including how to generate the necessary Hyperledger Composer
configuration. A subsequent tutorial will demonstrate how to deploy a blockchain
business network to an instance of Hyperledger Fabric for multiple organizations.
During this tutorial, you may wish to refer to the Hyperledger Fabric documentation.
Prerequisites
1. Before you continue, ensure that you have followed the steps in installing a development
environment.
The tutorial will assume that you use the simple Hyperledger Fabric network
provided in the development environment. If you use your own Hyperledger Fabric
network, then you must map between the configuration detailed below and your
own configuration.
Copy
cd ~/fabric-tools
./stopFabric.sh
./teardownFabric.sh
export FABRIC_VERSION=hlfv11
./downloadFabric.sh
./startFabric.sh
2. Delete any business network cards that may exist in your wallet. It is safe to ignore
any errors that state that the business network cards cannot be found:
Copy
Copy
rm -fr ~/.composer
Configuration files
Copy
~/fabric-tools/fabric-scripts/hlfv11/composer/crypto-config.yaml
Copy
~/fabric-tools/fabric-scripts/hlfv11/composer/configtx.yaml
You can find more information about these configuration tools, what they do, and
how to use them by reading the Hyperledger Fabric documentation.
Organizations
Network components
The Hyperledger Fabric network is made up of several components:
The Hyperledger Fabric network components are running inside Docker containers.
When running Hyperledger Composer within a Docker container, the names above
(for example, peer0.org1.example.com ) can be used to interact with the Hyperledger
Fabric network.
This tutorial will run Hyperledger Composer commands on the Docker host machine,
rather than from inside the Docker network. This means that the Hyperledger
Composer commands must interact with the Hyperledger Fabric network
using localhost as the host name and the exposed container ports.
Users
The user Admin@org1.example.com has a set of certificates and private key files stored
in the directory:
Copy
~/fabric-tools/fabric-scripts/hlfv11/composer/crypto-
config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
You will use some of these files later on to interact with the Hyperledger Fabric
network.
In addition to the administrator, the CA (Certificate Authority) for Org1 has been
configured with a default user. This default user has an enrollment ID of admin and
an enrollment secret of adminpw . However, this user does not have permission to
deploy a blockchain business network.
Channel
Copy
"name": "fabric-network",
"x-type": "hlfv1",
"version": "1.0.0",
The name property in a connection profile gives a name to the Hyperledger Fabric
network, so we can reference it later on. In the connection profile you have just
created, the name is fabric-network . You can use any name you like for the
Hyperledger Fabric network.
The version number is the version of this connection profile format. Currently there is
only 1 version of 1.0.0 .
There is also an optional property x-commitTimeout which can also be specified with
defines how long Hyperledger Composer should wait for a submitted transaction to
be committed to your organization's peer before giving up waiting. The default if not
specified is 300 seconds .
3. We must specify the host names and ports of all of the peer nodes in the
Hyperledger Fabric network. There is only 1 peer and we give it a label
of peer0.org1.example.com .
Copy
"peers": {
"peer0.org1.example.com": {
"url": "grpc://localhost:7051",
"eventUrl": "grpc://localhost:7053"
},
Here, we have specified our single peer node peer0.org1.example.com (using the host
name localhost ), the request port 7051, and the event hub port 7053.
The peers array can contain multiple peer nodes. If you have multiple peer nodes,
you should add them all to the peers object.
4. We must specify the host name and port of the certificate authority (CA) in the
Hyperledger Fabric network that we want to use for enrolling existing users and
registering new users.
Copy
"certificateAuthorities": {
"ca.org1.example.com": {
"url": "http://localhost:7054",
"caName": "ca.org1.example.com"
},
Copy
"orderers": {
"orderer.example.com": {
"url": "grpc://localhost:7050"
},
Here, we have specified our single orderer node orderer.example.com (using the
hostname localhost ) and the orderer port 7050 and we also label this
as orderer.example.com .
The orderers object can contain multiple orderer nodes. If you have multiple orderer
nodes, you should add them all to the orderers object.
6. We now must specify all the organizations in the network. In this tutorial there is only
1 organization, Org1 .
Copy
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
},
Here we are describing the owners of the peers and who their certificate authority is
plus we also declare the MSP id that has been defined for this organisation. In this
tutorial it has been defined as Org1MSP .
7. We must specify the name of an existing channel. We will deploy our blockchain
business network into the channel composerchannel . This is defined in the channels
object.
Copy
"channels": {
"composerchannel": {
"orderers": [
"orderer.example.com"
],
"peers": {
"peer0.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"eventSource": true
},
Here we are defined the channel composerchannel and also the orderers and peers
that are part of that channel. We also specify the roles the peer will perform in this
channel. In this tutorial we have added the single orderer and single peer defined
earlier referenced using their labels. The peer will have the business network installed
so will be a transaction endorser, able to handle chaincode queries and also generate
events. The blockchain business network will be deployed to all of the specified peer
nodes. Once the blockchain business network has been deployed, the specified peer
nodes will be used for querying the blockchain business network, endorsing
transactions, and subscribing to events.
8. The final section this is required is the client section. This is used by client
applications (such as Hyperledger Composer) to know what organization it is
representing when interacting and also some extra optional timeouts.
Copy
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300",
"eventHub": "300",
"eventReg": "300"
},
"orderer": "300"
Here we are specifying that we are in Org1 . The timeouts are used to determine how
long to wait for a response when interacting with a peer or orderer and the values
are specified in seconds. If you don't specify anything then the default is 45 seconds .
Copy
"name": "fabric-network",
"x-type": "hlfv1",
"version": "1.0.0",
"peers": {
"peer0.org1.example.com": {
"url": "grpc://localhost:7051",
"eventUrl": "grpc://localhost:7053"
}
},
"certificateAuthorities": {
"ca.org1.example.com": {
"url": "http://localhost:7054",
"caName": "ca.org1.example.com"
},
"orderers": {
"orderer.example.com": {
"url": "grpc://localhost:7050"
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
},
"channels": {
"composerchannel": {
"orderers": [
"orderer.example.com"
],
"peers": {
"peer0.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"eventSource": true
},
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300",
"eventHub": "300",
"eventReg": "300"
},
"orderer": "300"
Step Four: Locating the certificate and private key for the
Hyperledger Fabric administrator
In order to deploy a blockchain business network to this Hyperledger Fabric network,
we must identify ourselves as an administrator with the permissions to perform this
operation. In this step, you locate the files required to identify yourself as an
administrator.
The administrator for our Hyperledger Fabric network is a user
called Admin@org1.example.com . The certificates and private key files for this user are
stored in the directory:
Copy
~/fabric-tools/fabric-scripts/hlfv11/composer/crypto-
config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
You must first locate the certificate file for this user. The certificate is the public part
of the identity. The certificate file can be found in the signcerts subdirectory and is
named Admin@org1.example.com-cert.pem . If you look at the contents of this file, then
you will find a PEM encoded certificate similar to the following:
Copy
-----BEGIN CERTIFICATE-----
MIICGjCCAcCgAwIBAgIRANuOnVN+yd/BGyoX7ioEklQwCgYIKoZIzj0EAwIwczEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh
Lm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwNjI2MTI0OTI2WhcNMjcwNjI0MTI0OTI2
WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWQWRtaW5Ab3JnMS5leGFtcGxlLmNvbTBZ
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABGu8KxBQ1GkxSTMVoLv7NXiYKWj5t6Dh
WRTJBHnLkWV7lRUfYaKAKFadSii5M7Z7ZpwD8NS7IsMdPR6Z4EyGgwKjTTBLMA4G
A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIBmrZau7BIB9
rRLkwKmqpmSecIaOOr0CF6Mi2J5H4aauMAoGCCqGSM49BAMCA0gAMEUCIQC4sKQ6
CEgqbTYe48az95W9/hnZ+7DI5eSnWUwV9vCd/gIgS5K6omNJydoFoEpaEIwM97uS
XVMHPa0iyC497vdNURA=
-----END CERTIFICATE-----
Next, you must locate the private key file for this user. The private key is used to sign
transactions as this identity. The private key file can be found in
the keystore subdirectory. The name of the private key file is a long hexadecimal
string, with a suffix of _sk , for
example 114aab0e76bf0c78308f89efc4b8c9423e31568da0c340ca187a9b17aa9a4457_sk . The
name will change every time the configuration is generated. If you look at the
contents of this file, then you will find a PEM encoded private key similar to the
following:
Copy
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6
ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg
4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC
Remember the path to both of these files, or copy them into the same directory as
the connection profile file connection.json that you created in the previous step. You
will need these files in the next step.
In this step you will create a business network card for the administrator to use to
deploy the blockchain business network to the Hyperledger Fabric network.
Run the composer card create command to create a business network card. You must
specify the path to all three files that you either created or located in the previous
steps:
Copy
Copy
-p connection.json
This is the path to the connection profile file that we created in step three.
Copy
-u PeerAdmin
Copy
-c Admin@org1.example.com-cert.pem
This is the path to the certificate file for the user Admin@org1.example.com that we
located in step four.
Copy
-k 114aab0e76bf0c78308f89efc4b8c9423e31568da0c340ca187a9b17aa9a4457_sk
This is the path to the private key file for the user Admin@org1.example.com that we
located in step four.
Copy
-r PeerAdmin -r ChannelAdmin
Here, we specify which roles the user has. This information is required so that
Hyperledger Composer knows which users are able to perform which operations. The
user Admin@org1.example.com is an administrator for the Hyperledger Fabric network,
and has the roles PeerAdmin (ability to install chaincode) and ChannelAdmin (ability to
instantiate chaincode).
Run the composer card import command to import the business network card into
the wallet:
Copy
Let's explore the options that we passed to the composer card import command.
Copy
-f PeerAdmin@fabric-network.card
This is the path to the business network card file that we created in step five.
You can now use this business network card by specifying the
name PeerAdmin@fabric-network . You are now all set to deploy the blockchain
business network to the Hyperledger Fabric network.
In this step, you will install the Hyperledger Composer runtime onto all of the
Hyperledger Fabric peer nodes. In Hyperledger Fabric terms, this is a chaincode
install operation.
Run the composer runtime install command to install the Hyperledger Composer
runtime onto all of the Hyperledger Fabric peer nodes that you specified in the
connection profile file you created in step three:
Copy
Let's explore the options that we passed to the composer runtime install command.
Copy
-c PeerAdmin@fabric-network
This is the name of the business network card that we imported into the wallet in
step six.
Copy
-n tutorial-network
You must install a copy of the Hyperledger Composer runtime for each blockchain
business network, and specify the name of the blockchain business network. Here we
specify the name of the blockchain business network that we are
deploying, tutorial-network .
Run the composer network start command to start the blockchain business network:
Copy
Let's explore the options that we passed to the composer network start command.
Copy
-c PeerAdmin@fabric-network
This is the name of the business network card that we imported into the wallet in
step six.
Copy
-a tutorial-network.bna
This is the path to the business network archive that contains the business network
definition for our blockchain business network called tutorial-network .
Copy
-A admin
When a blockchain business network is deployed, you must create at least one
participant who will be a blockchain business network administrator. This participant
is responsible for onboarding other participants into the blockchain business
network. Here, we are specifying that we want to create a single blockchain business
network administrator called admin .
Copy
-S adminpw
This specifies that our blockchain business network administrator admin will use an
enrollment secret of adminpw to request a certificate and private key from the CA
(Certificate Authority). When you specify this option, the name specified for the
business network administrator must be an existing enrollment ID for a user that is
already registered with the CA.
Now that our blockchain business network has been started, we can interact with it
using the business network card file admin@tutorial-network.card that was created.
Copy
You can now use this business network card by specifying the name admin@tutorial-
network . You are now all set to interact with the running blockchain business
network!
Copy
Conclusion
In this tutorial you have seen how to configure Hyperledger Composer with all of the
information required to connect to a Hyperledger Fabric network, and how to deploy
a blockchain business network to that Hyperledger Fabric network.
If you used the simple Hyperledger Fabric network provided in the development
environment, why not try building your own Hyperledger Fabric network by following
the Hyperledger Fabric documentation and see if you can successfully deploy a
blockchain business network to it?
It outlines the steps you need configure an Hyperledger Fabric based multi-
organisation blockchain network. The two-organisation blockchain network is based
on a sample network provided by Hyperledger Fabric. Furthermore, it describes the
steps to generate the necessary security artifacts and secure the network in either
organization.
It is recommended that you first follow the accompanying singie organization tutorial
first ; this tutorial demonstrates how to deploy a blockchain network to an instance
of Hyperledger Fabric for a single organization, and will explain some of the concepts
in more detail.
The {site.data.conrefs.hlf_full}} blockchain network (for two organizations) in this
tutorial is configured using docker containers, with both organizations' fabric
networks, on the same machine - obviously, in the real world, they'll be in separate IP
networks or domains, or secure Cloud environments.
The tutorial has colour-coded steps for convenience, to indicate 'which organization'
should follow a particular step or sequence - or indeed, if steps are needed for both
Orgs.
Prerequisites
If you have previously installed the Composer development environment, you will
need to first tear down the Hyperledger Fabric containers provided by the
development environment:
Copy
cd ~/fabric-tools
./stopFabric.sh
./teardownFabric.sh
Next, clone the following GitHub Fabric Samples repository using the command line
(do not use the samples from the Fabric site: as it is missing some changes that are
required for this tutorial)
Copy
We are using the Building Your First Network Fabric sample network for this multi-
org tutorial. We will refer to this Hyperledger Fabric network as the 'BYFN' (Building
Your First Network) network henceforth. If you choose to split your organisations
across separate physical machines or separate virtual machines running on different
IP networks, it is outside the scope of this particular tutorial.
Copy
cd fabric-samples
Copy
Copy
cd first-network
4. Next, start the BYFN network - additional flags (to the byfn.sh script below) must be
specified, as we're using CouchDB as the world state database (different to that
specified on the Fabric BYFN page) - we also want to start a Certificate Authority (CA)
for each organization.
5. Execute the following commands in sequence from the first-network directory:
Copy
./byfn.sh -m generate
./byfn.sh -m up -s couchdb -a
If the command works successfully, the first command will generate Fabric network /
security artifacts(see this link. Following the second command (above), the BYFN
network is started, and verify that you see the following output before proceeding:
Copy
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
Next, delete any 'old' business network cards that may exist in your wallet from
previous Fabric environments. It is safe to ignore any errors that state that the
business network cards cannot be found:
Copy
However any other types of failure could indicate you have cards in the card store
which are from an older version of Hyperledger Composer and you will then have to
delete your file system card store in your HOME directory as follows:
Copy
rm -fr $HOME/.composer
Step Two: Exploring the Hyperledger Fabric network
This step will explore the BFYN network configuration and components. The
configuration details are required to complete the subsequent steps.
Organizations
The BYFN network is made up of two organizations: Org1 and Org2 . The
organization Org1 uses the domain name org1.example.com . The Membership
Services Provider (MSP) for Org1 is called Org1MSP . The organization Org2 uses the
domain name org2.example.com . The MSP for Org2 is called Org2MSP . In this tutorial,
you will deploy a blockchain business network that both of the
organizations Org1 and Org2 can interact with.
Network components
These components are running inside Docker containers. When running Hyperledger
Composer within a Docker container, the names above (for
example, peer0.org1.example.com ) can be used to interact with the Hyperledger
Fabric network.
This tutorial will run Hyperledger Composer commands on the Docker host machine,
rather than from inside the Docker network. This means that the Hyperledger
Composer commands must interact with the Hyperledger Fabric network
using localhost as the host name and the exposed container ports.
All of the network components are secured using TLS to encrypt communications.
You will need the Certificate Authority (CA) certificates for all of the network
components in order to connect to those network components. The CA certificates
can be found in the directory containing the byfn.sh script.
Copy
crypto-
config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt
Copy
crypto-
config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
Copy
crypto-
config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
You will use these files later on to interact with the Hyperledger Fabric network.
Users
The user Admin@org1.example.com has a set of certificates and private key files stored
in the directory:
Copy
crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
The user Admin@org2.example.com has a set of certificates and private key files stored
in the directory:
Copy
crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
You will use some of these files later on to interact with the Hyperledger Fabric
network.
Copy
mkdir -p /tmp/composer/org1
mkdir -p /tmp/composer/org2
Channel
A channel named mychannel has been created. All four peer nodes -
peer0.org1.example.com , peer1.org1.example.com , peer0.org2.example.com ,
and peer1.org2.example.com have been joined to this channel.
Connection Profiles
We need a base connection profile that describes this fabric network which can then
be given to alice and bob to customize for their organization.
Copy
"name": "byfn-network",
"x-type": "hlfv1",
"version": "1.0.0",
"channels": {
"mychannel": {
"orderers": [
"orderer.example.com"
],
"peers": {
"peer0.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"eventSource": true
},
"peer1.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"eventSource": true
},
"peer0.org2.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"eventSource": true
},
"peer1.org2.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"eventSource": true
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com",
"peer1.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
},
"Org2": {
"mspid": "Org2MSP",
"peers": [
"peer0.org2.example.com",
"peer1.org2.example.com"
],
"certificateAuthorities": [
"ca.org2.example.com"
},
"orderers": {
"orderer.example.com": {
"url": "grpcs://localhost:7050",
"grpcOptions": {
"ssl-target-name-override": "orderer.example.com"
},
"tlsCACerts": {
"pem": "INSERT_ORDERER_CA_CERT"
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"eventUrl": "grpcs://localhost:7053",
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com"
},
"tlsCACerts": {
"pem": "INSERT_ORG1_CA_CERT"
},
"peer1.org1.example.com": {
"url": "grpcs://localhost:8051",
"eventUrl": "grpcs://localhost:8053",
"grpcOptions": {
"ssl-target-name-override": "peer1.org1.example.com"
},
"tlsCACerts": {
"pem": "INSERT_ORG1_CA_CERT"
},
"peer0.org2.example.com": {
"url": "grpcs://localhost:9051",
"eventUrl": "grpcs://localhost:9053",
"grpcOptions": {
"ssl-target-name-override": "peer0.org2.example.com"
},
"tlsCACerts": {
"pem": "INSERT_ORG2_CA_CERT"
},
"peer1.org2.example.com": {
"url": "grpcs://localhost:10051",
"eventUrl": "grpcs://localhost:10053",
"grpcOptions": {
"ssl-target-name-override": "peer1.org2.example.com"
},
"tlsCACerts": {
"pem": "INSERT_ORG2_CA_CERT"
},
"certificateAuthorities": {
"ca.org1.example.com": {
"url": "https://localhost:7054",
"caName": "ca-org1",
"httpOptions": {
"verify": false
},
"ca.org2.example.com": {
"url": "https://localhost:8054",
"caName": "ca-org2",
"httpOptions": {
"verify": false
}
}
Copy this base file (above) into a new file byfn-network.json under the new
directory /tmp/composer and save it.
Copy
Copy
In the same .json file - you need to replace all instances of the
text INSERT_ORG2_CA_CERT with the CA certificate for the peer nodes for Org2 : - use
the following command to convert the .pem file to something that can be embedded
into the above connection profile.
Copy
Copy the contents of the file /tmp/composer/org2/ca-org2.txt and replace the text
called INSERT_ORG2_CA_CERT . Once again, all on the same line.
Replace all instances of the text INSERT_ORDERER_CA_CERT with the CA certificate for
the orderer node: use the following command to convert the .pem file to something
that can be embedded into the above connection profile json file.
Copy
This connection profile now describes the fabric network setup, all the peers,
orderers and certificate authorities that are part of the network, it defines all the
organizations that are participating in the network and also defines the channel's on
this network. Hyperledger Composer can only interact with a single channel so only
one channel should be defined.
Copy
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300",
"eventHub": "300",
"eventReg": "300"
},
"orderer": "300"
},
Copy
...
"version": "1.0.0",
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300",
"eventHub": "300",
"eventReg": "300"
},
"orderer": "300"
},
"channel": {
...
Copy
...
"version": "1.0.0",
"client": {
"organization": "Org2",
"connection": {
"timeout": {
"peer": {
"endorser": "300",
"eventHub": "300",
"eventReg": "300"
},
"orderer": "300"
},
"channel": {
...
Step Five: Locating the certificate and private key for the
Hyperledger Fabric administrator for Org1
The administrator for our Hyperledger Fabric Org1 network is a user
called Admin@org1.example.com . The certificates and private key files for this user are
stored in the directory:
Copy
crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
You must first locate the certificate file for this user. The certificate is the public part
of the identity. The certificate file can be found in the signcerts subdirectory and is
named Admin@org1.example.com-cert.pem .
Next, you must locate the private key file for this user. The private key is used to sign
transactions as this identity. The private key file can be found in
the keystore subdirectory. The name of the private key file is a long hexadecimal
string, with a suffix of _sk , for
example: 78f2139bfcfc0edc7ada0801650ed785a11cfcdef3f9c36f3c8ca2ebfa00a59c_sk . The
name will change every time the configuration is generated, hence the wildcard
below.
Remember the path to both of these files - or copy them into the same directory as
the connection profile file /tmp/composer/org1/byfn-network-org1.json that you
created in 'Step Three'. You will need these files in the next steps.
Copy
export ORG1=crypto-
config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
cp -p $ORG1/signcerts/A*.pem /tmp/composer/org1
cp -p $ORG1/keystore/*_sk /tmp/composer/org1
Step Six: Locating the certificate and private key for the
Hyperledger Fabric administrator for Org2
The administrator for our Hyperledger Fabric network is a user
called Admin@org2.example.com . The certificates and private key files for this user are
stored in the directory:
Copy
crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
You must first locate the certificate file for this user. The certificate is the public part
of the identity. The certificate file can be found in the signcerts subdirectory and is
named Admin@org2.example.com-cert.pem .
Next, you must locate the private key file for this user. The private key is used to sign
transactions as this identity. The private key file can be found in
the keystore subdirectory. The name of the private key file is a long hexadecimal
string, with a suffix of _sk , for
example d4889cb2a32e167bf7aeced872a214673ee5976b63a94a6a4e61c135ca2f2dbb_sk . The
name will change every time the configuration is generated.
Remember the path to both of these files, or copy them into the same directory as
the connection profile file /tmp/composer/byfn-network-org2.json that you created in
step four. You will need these files in the next steps.
Copy
export ORG2=crypto-
config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
cp -p $ORG2/signcerts/A*.pem /tmp/composer/org2
cp -p $ORG2/keystore/*_sk /tmp/composer/org2
Run the composer card create command to create a business network card using the
connection profile for Org1 . You must specify the path to all three files that you
either created or located in the previous steps: (note: the sk file will differ.)
Copy
Copy
Copy
Copy
Copy
As you can see from the above, we are using a Composer business network name
called trade-network to test our multi-org environment. You will need a file trade-
network.bna (business network archive, from our sample networks) to do the test. If
you don't have this, just go to https://composer-playground.mybluemix.net/and
deploy the trade-network sample in the online Playground, then 'connect' to the
business network as 'admin', and finally export it to the current directory as trade-
network.bna . (Note: If you are planning on using a different network, such as the
Composer tutorial network tutorial-network as your business network, you would
need to use that name in the runtime install command above and thereafter, as the
business network name in this tutorial).
Copy
You can find more information on endorsement policies in the Hyperledger Fabric
documentation, in Endorsement policies.
Please note that the endorsement policies used for a business network must be in
the JSON format used by the Hyperledger Fabric Node.js SDK. This is a different
format to the simple endorsement policy format used by the Hyperledger Fabric CLI,
which you will see in the Hyperledger Fabric documentation.
Copy
"identities": [
"role": {
"name": "member",
"mspId": "Org1MSP"
},
"role": {
"name": "member",
"mspId": "Org2MSP"
}
],
"policy": {
"2-of": [
"signed-by": 0
},
"signed-by": 1
The endorsement policy you have just created states that both Org1 and Org2 must
endorse transactions in the business network before they can be committed to the
blockchain. If Org1 or Org2 do not endorse transactions, or disagree on the result of
a transaction, then the transaction will be rejected by the business network.
In our business network, the organizations Org1 and Org2 have equal rights. Each
organization will provide a business network administrator for the business network,
and those business network administrators will onboard the other participants in
their organizations. The business network administrator for Org1 will be Alice, and
the business network administrator for Org2 will be Bob.
When the business network is started, the certificates (the public part of the identity)
for all of the business network administrators must be passed to the organization
performing the commands to start the business network. After the business network
has been started, all of the business network administrators can use their identities to
interact with the business network.
Copy
The -u admin and the -s adminpw options to this command correspond to the default
user registered with the Hyperledger Fabric CA (Certificate Authority).
The certficates will be placed into a directory called alice in the current working
directory. There are three certificate files created, but only two are important. These
are admin-pub.pem , the certificate (including the public key), and admin-priv.pem , the
private key. Only the admin-pub.pem file is suitable for sharing with other
organizations. The admin-priv.pem file must be kept secret as it can be used to sign
transactions on behalf of the issuing organization.
Copy
The -u admin and the -s adminpw options to this command correspond to the default
user registered with the Hyperledger Fabric CA (Certificate Authority).
The certficates will be placed into a directory called bob in the current working
directory. There are three certificate files created, but only two are important. These
are admin-pub.pem , the certificate (including the public key), and admin-priv.pem , the
private key. Only the admin-pub.pem file is suitable for sharing with other
organizations. The admin-priv.pem file must be kept secret as it can be used to sign
transactions on behalf of the issuing organization.
Copy
Once this command completes, the business network will have been started. Both
Alice and Bob will be able to access the business network, start to set up the business
network, and onboard other participants from their respective organizations.
However, both Alice and Bob must create new business network cards with the
certificates that they created in the previous steps so that they can access the
business network.
Copy
Run the composer card import command to import the business network card that
you just created:
Copy
Copy
If the command completes successfully, then you should see the fully qualified
participant identifier org.hyperledger.composer.system.NetworkAdmin#alice in the
output from the command. You can now use this business network card to interact
with the blockchain business network and onboard other participants in your
organization.
Lets create a participant, issue an identity (mapped to that participant) and create an
asset on the blockchain network as that identity.
Run the composer participant add command below, copying it to the command line
to execute:
Copy
Next create the identity for trader1-org1 with the composer issue identity command
below:
Copy
Copy
Next we will create an asset - From the command line, submit a transaction to create
a Commodity asset, as participant jdoe (or alternatively, if you already have
Composer Playground installed, connect as jdoe@trade-network to trade-network to
create the asset 'EMA' - the JSON snippet is shown below ).
To create the asset using the CLI - copy the transaction submit sequence below - it
creates a Commodity asset for you:
Copy
Copy
"$class": "org.acme.trading.Commodity",
"tradingSymbol": "EMA",
"mainExchange": "EURONEXT",
"quantity": 10,
"owner": "resource:org.acme.trading.Trader#trader1-org1"
Finally, do a composer network list to confirm the generated artifacts in the business
network:
Copy
Copy
Copy
Run the composer network ping command to test the connection to the blockchain
business network:
Copy
If the command completes successfully, then you should see the fully qualified
participant identifier org.hyperledger.composer.system.NetworkAdmin#bob in the output
from the command. Let's onboard another Trader, this time for Org 2:
Run the composer participant add command below, copying it to the command line
to execute:
Copy
Next create the identity for trader2-org2 with the composer issue identity command
below:
Copy
Copy
Copy
Finally, do a composer network list as the Org 2 trader participant to confirm the
change of ownership on the asset:
Copy
Conclusion
In this tutorial you have seen how to configure a blockchain network based on
Hyperledger Composer in a multi-organizational setup. You've also learned how to
deploy a business network (such as our Commodities trading network) to that
blockchain network and perform some simple transactions as participants in each
organization, using identities that were issued by the Certificate of Authorities in
either organization.