Create and deploy your first permissioned blockchain in minutes

This tutorial requires two server nodes. If you have not done so already, please download and install MultiChain Community or Enterprise Demo on each server. Note that one section of this guide applies to MultiChain Enterprise only.

1. Creating a blockchain (required)

First we will create a new blockchain named chain1. On the first server, run this command:

multichain-util create chain1

If you are using Windows, first open a DOS command line in the directory where you installed the MultiChain executables. You can do this by navigating to that directory in the Windows Explorer, then typing cmd in the address bar at the top.

There are many blockchain parameters that can be modified, but we’ll leave them on their default settings. Now initialize the blockchain, including creating the genesis block:

multichaind chain1 -daemon

You should be told that the server has started and then after a few seconds, that the genesis block was found. You should also be given the node address that others can use to connect to this chain.

Copy and paste the node address here:

2. Connecting to the blockchain (required)

Now we’ll connect to this blockchain from elsewhere. On the second server, run the following:


You should be told that the blockchain was successfully initialized, but you do not have permission to connect. You should also be shown a message containing an address in this node’s wallet.

Copy and paste the wallet address here:

Back on the first server, add connection permissions for this address:

multichain-cli chain1 grant connect

Now try reconnecting again from the second server:

multichaind chain1 -daemon

You should be shown a message that the node was started, and it should display this second node’s address.

3. Some commands in interactive mode (required)

Before we proceed, let’s enter interactive mode so we can issue commands without typing multichain-cli chain1 every time. On both servers:

multichain-cli chain1

If you are using Windows, interactive mode is not yet available, so all commands in this guide should be preceded by multichain-cli chain1. You will also need to open another DOS command line in the directory where you installed the MultiChain executables.

Now that the blockchain is working on two nodes, you can run the commands in this section on either or both. To get general information:


See a list of all available commands:


For each node, get a list of connected peers:


If you are using MultiChain Enterprise, you should see that the connection between the peers is encrypted.

4. Introduction to streams (optional)

Now let’s create a stream, which can be used for general data storage and retrieval. If you are only interested in assets and tokens, you should skip this section. On the first server:

create stream stream1 '{"restrict":"write"}'

If you are using Windows, you need to use a different form of quoting on the command line. Run this instead:
create stream stream1 "{\"restrict\":\"write\"}"

The {"restrict":"write"} means the stream can only be written to by those with explicit permissions. Let’s see its permissions:

listpermissions stream1.*

So for now, only the first server has the ability to write to the stream, as well as administrate it. Let’s publish some JSON to it, with key1:

publish stream1 key1 '{"json":{"name":"John Doe","city":"London"}}'

On Windows command line:
publish stream1 key1 "{\"json\":{\"name\":\"John Doe\",\"city\":\"London\"}}"

The txid of the stream item is returned. Now let’s see that the stream is visible on another node. On the second server:


(The root stream is created in the blockchain by default.) Now we want the second server to subscribe to the stream, then view its contents:

subscribe stream1
liststreamitems stream1

Now we want the second server to be allowed to publish to the stream. On the first server:

grant send
grant stream1.write

Note that the address needs both general send permissions for the blockchain, as well as permission to write to this specific stream. Now let’s publish a couple of items from the second server:

publish stream1 key2 '{"json":{"name":"Jane Smith","city":"Paris"}}'
publish stream1 '["key1","key2"]' '{"json":{"city":"New York"}}'

On Windows command line:
publish stream1 key2 "{\"json\":{\"name\":\"Jane Smith\",\"city\":\"Paris\"}}"
publish stream1 "[\"key1\",\"key2\"]" "{\"json\":{\"city\":\"New York\"}}"

Note that streams are very flexible: an item can have more than one key, and a key can be used for more than one item. In addition, stream items can be in JSON, text or binary formats, and it’s possible to publish multiple stream items atomically in a single transaction.

Now let’s list the stream’s contents in many different ways. Back on the first server:

subscribe stream1
liststreamitems stream1 (should show three items)
liststreamkeys stream1 (two keys)
liststreamkeyitems stream1 key1 (two items with this key)
liststreampublishers stream1 (two publishers)
liststreampublisheritems stream1 (two items by this publisher)

JSON stream items can also be combined together, taking the most recent value for each field within:

getstreamkeysummary stream1 key1 jsonobjectmerge
getstreamkeysummary stream1 key2 jsonobjectmerge

We can also run some queries to search for items with combinations of keys and/or publishers:

liststreamqueryitems stream1 '{"keys":["key1","key2"]}' (one item with both keys)
liststreamqueryitems stream1 '{"key":"key1","publisher":""}' (one with publisher and key)

On Windows command line:
liststreamqueryitems stream1 "{\"keys\":[\"key1\",\"key2\"]}"
liststreamqueryitems stream1 "{\"key\":\"key1\",\"publisher\":\"\"}"

Many other options for stream querying and merging are available, as described in the API documentation.

5. Enterprise streams (optional)

In this section we’ll look at some streams features which are only available in MultiChain Enterprise, for which a free demo is available. If you are not using MultiChain Enterprise, you should skip this section.

Let’s begin by creating a stream with read and write restrictions. On the first server:

create stream stream2 '{"restrict":"read,write"}'

On Windows command line:
create stream stream2 "{\"restrict\":\"read,write\"}"

Now let’s take a look at this stream on the second server:

liststreams stream2

Note how the stream automatically disallows on-chain data, so that read permissions can be enforced. Now try subscribing on the second server:

subscribe stream2

You should see an error preventing this node from subscribing. Let’s fix this, using the first server:


Now let’s try subscribing again on the second server:

subscribe stream2

Let’s publish some items into the stream. On the first server:

publish stream2 id_123456 '{"json":{"source":"Singapore","destination":"Los Angeles"}}' offchain
publish stream2 id_234567 '{"json":{"source":"Rotterdam","destination":"New York"}}' offchain

On Windows command line:
publish stream2 id_123456 "{\"json\":{\"source\":\"Singapore\",\"destination\":\"Los Angeles\"}}" offchain
publish stream2 id_234567 "{\"json\":{\"source\":\"Rotterdam\",\"destination\":\"New York\"}}" offchain

Note how the items must be published off-chain. Now let’s view the data on the second server:

liststreamitems stream2

The off-chain data for these items was retrieved by the second node at the instant they were seen. Now let’s say the first server also wants to subscribe to this stream, but only needs to list items by key using global blockchain ordering. In MultiChain Enterprise, it can save time and space for large scale data applications using a partial subscription. On the first server:

subscribe stream2 true retrieve,keys
liststreams stream2

Note all the indexes which are switched off (indexes can be added or removed later using the subscribe and trimsubscribe commands, but the basic items index is always available). Let’s see how the stream can be queried:

liststreamitems stream2
liststreamkeyitems stream2 id_123456
liststreamkeyitems stream2 id_123456 false 10 -10 true (local ordering)
liststreampublisheritems stream2
getstreamkeysummary stream2 id_123456 jsonobjectmerge
getstreampublishersummary stream2 jsonobjectmerge

Finally let’s remove read permissions from the second server and publish a new item. On the first server:

publish stream2 id_345678 '{"json":{"source":"Antwerp","destination":"Hong Kong"}}' offchain

On Windows command line:
publish stream2 id_345678 "{\"json\":{\"source\":\"Antwerp\",\"destination\":\"Hong Kong\"}}" offchain

Now let’s view the stream items on the second server:

liststreamitems stream2

Note how the key and publisher are visible for the last item, but the data itself is not. This is because the node no longer has read permissions for this stream and cannot retrieve the off-chain data from any other node. To comply with privacy regulations, MultiChain Enterprise can also purge its local copy of any off-chain data. On the second server:

purgestreamitems stream2 all
liststreamitems stream2

Data is no longer available on this node for any items in this stream. For more control, MultiChain Enterprise can also subscribe to a stream without retrieving off-chain data automatically, and then selectively retrieve data using the retrievestreamitems command.

6. Advanced streams (optional)

Now let’s look at some other streams features, which are available in both MultiChain Community and MultiChain Enterprise. If you are only interested in assets and tokens, you should skip this section.

First we’ll build up a large binary object and publish it off-chain (with on-chain hashes verifying its contents). On the first server:


Copy and paste the returned identifier here:

Data can be added to the binary cache using the appendbinarycache command with the data in hexadecimal:

appendbinarycache 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

This can be run multiple times, and each time the cache’s total size will be returned. But if you’re using Linux, you can also pipe raw binary data directly to the cache via its file. Open a new Linux command line on the first server and enter the following to add 512 MB of random data:

head -c 536870912 < /dev/urandom >> ~/.multichain/chain1/cache/

This may take a minute or so. Now back in the MultiChain command line, enter the following (this may also take a short while):

publish stream1 key3 '{"cache":""}' offchain

On Windows command line:
publish stream1 key3 "{\"cache\":\"\"}" offchain

Copy and paste the displayed transaction ID:

Now on the second server, issue this command:

liststreamkeyitems stream1 key3

You should see the new item listed. If you created a large item on Linux, it should display with "available" : false because all of the off-chain data has not yet arrived. In that case, keep running this to watch the data come in:


Once the chunk queue is empty, the item’s data should be available and you can view its first kilobyte in hexadecimal:

liststreamkeyitems stream1 key3
gettxoutdata 0 1024

Finally let’s take a quick look at stream filters, which allow custom validation rules to be defined for stream items. Run the following to find the address which has admin permissions for the stream:

listpermissions stream1.admin

Copy and paste the address here:

Now let’s create a new stream filter which requires items to be in JSON format with a state element containing a two-letter code. On the first server:

create streamfilter filter1 '{}' 'function filterstreamitem() { var item=getfilterstreamitem(); if (!( && && ( return "JSON required with two letter state field"; }'

On Windows command line:
create streamfilter filter1 "{}" "function filterstreamitem() { var item=getfilterstreamitem(); if (!( && && ( return \"JSON required with two letter state field\"; }"

Now let’s view the filter and activate it on our stream. Still on the first server:

getfiltercode filter1
approvefrom filter1 '{"for":"stream1","approve":true}'
liststreams stream1 true

On Windows command line:
approvefrom filter1 "{\"for\":\"stream1\",\"approve\":true}"

You should see that the filter is now listed for this stream. Now let’s attempt to publish some items in the stream and see what the filter allows. On the second server:

publish stream1 key4 '{"text":"hello world"}' (text data)
publish stream1 key4 '{"json":{}}' (empty JSON)
publish stream1 key4 '{"json":{"city":"Tokyo"}}' (no state field)
publish stream1 key4 '{"json":{"state":"New York"}}' (invalid state field)
publish stream1 key4 '{"json":{"state":"NY"}}' (success!)

On Windows command line:
publish stream1 key4 "{\"text\":\"hello world\"}"
publish stream1 key4 "{\"json\":{}}"
publish stream1 key4 "{\"json\":{\"city\":\"Tokyo\"}}"
publish stream1 key4 "{\"json\":{\"state\":\"New York\"}}"
publish stream1 key4 "{\"json\":{\"state\":\"NY\"}}"

Because of the stream filter, only the final line is accepted. Stream filters are also applied at read time for extra security against compromised nodes.

7. Assets and Tokens (optional)

Now we are going to create a new asset and send it between nodes. First let’s get the address that has the permission to create assets:

listpermissions issue

Copy and paste the displayed address here:

Now we’ll create a new asset with 1000 units, each of which can be subdivided into 100 parts. On the first server:

issue asset1 1000 0.01

On both servers, verify that the asset named asset1 is listed:


Now check the asset balances on each server. The first should show a balance of 1000, and the second should show no assets at all:


On the first server, now try sending 100 units of the asset to the second server’s wallet:

sendasset asset1 100

You should see an error that the address does not have receive permissions. So it’s time to add receive permissions:

grant receive

Now try sending the asset again, and it should go through:

sendasset asset1 100

Now check the asset balances on each server, including transactions with zero confirmations. They should be 900 and 100 respectively:

gettotalbalances 0

You can also view the transaction on each node and see how it affected their balances:

listwallettransactions 1

Next, we’re going to create a non-fungible asset, for which individual units of the asset are tracked separately. On the first server:

issue '{"name":"nfts1","open":true,"fungible":false}' 0

On Windows command line:
issue "{\"name\":\"nfts1\",\"open\":true,\"fungible\":false}" 0

We passed 0 because, for non-fungible assets, no units can be issued at the time of asset creation. Now let’s look at the asset named nfts1:

listassets nfts1

Note that it is labelled as "fungible" : false. Let’s issue a couple of tokens for this asset. On the first server:

issuetoken nfts1 token1 1 0 '{"hash":"144f10d820af5a51","author":"John Smith"}'
issuetoken nfts1 token2 1 0 '{"hash":"96a027f0c0736c03","author":"Mary Jones"}'

On Windows command line:
issuetoken nfts1 token1 1 0 "{\"hash\":\"144f10d820af5a51\",\"author\":\"John Smith\"}"
issuetoken nfts1 token2 1 0 "{\"hash\":\"96a027f0c0736c03\",\"author\":\"Mary Jones\"}"

Here, we issued two unique tokens with 1 unit each, naming them token1 and token2 respectively. Each token is also associated with some JSON metadata providing a content hash and author name. (Using other APIs, it’s possible to embed up to 64 MB of data directly in the transaction that creates a token, or reference up to 1 GB of off-chain data using a stream item.)

Let’s view the issuances performed for this asset so far:

listassetissues nfts1 true

You should see the first issuance of no units, in which the asset was created, followed by the two token issuances. Now let’s check the token balances:


And now let’s send token2 from the first server to the second server:

send '{"nfts1":{"token":"token2","qty":1}}'

On Windows command line:
send "{\"nfts1\":{\"token\":\"token2\",\"qty\":1}}"

Now let’s check the token balances, including unconfirmed transactions, to see that the token has moved. On both servers:

gettokenbalances * * 0

This is just a taste of MultiChain’s asset and token functionality. Depending on the parameters provided during creation, assets can also be closed and/or reopened for issuance, have asset-specific send/receive permissions, as well as limits set on the quantity per issuance and in total.

8. Round-robin consensus (optional)

In this section we’ll start collaborative block validation between the nodes. Note that, in the case of a permissioned MultiChain blockchain, consensus is based on block signatures and a customizable round-robin consensus scheme, rather than proof-of-work as in bitcoin.

On the first server, run:

grant mine

(Even though the permission is called mine note that there is no real “mining” taking place, in the sense of proof-of-work.) On the second server, check that two permitted block validators are listed:

listpermissions mine

Run this on both servers to maximize the degree of validator randomness:

setruntimeparam miningturnover 1

Now wait for a couple of minutes, so that a few blocks are added. (This assumes you left the block time on the default of 15 seconds.) On either server, check the creators of the last few blocks:

listblocks -10

The address of the validator of each block is in the miner field of each element of the response.

Note that this tutorial uses only two validator nodes and the low default value for the mining-diversity blockchain parameter. So each block can be created by either node, and the chain is not secure. A secure chain would use more validator nodes and/or a higher value for this parameter.

9. Now go explore…

Congratulations – you have finished the first tutorial! Now you try any of the other tutorials, create blockchains with different parameters or explore the available API commands. You can also install Explorer 2 or the Web Demo to see a graphical interface for your blockchain.

Finally, you may want to subscribe below for updates. And if you have any questions or problems, please ask in the developer Q&A or contact us.

10. Get product updates (one email per month max)