Blockchain Mobility hackathon – the future of mobility is here

During 21-22.07.18 weekend, I had a pleasure to be a part of the Blockchain Mobility Hackathon in Munich, Germany. As the problem of flexible mobility service is existing in modern society, I would like to present you our idea of blockchain based pay as you go solution.

Blockchain mobility hackathon – Munich 2018

One picture is more than a thousand words :). Great event!

Team – the most important part

Our project was done by people, who met each other just before the hackathon. This is the best part and greatest challenge of hackathons – not only you meet the people but you work with them very closely for the next 48 hours. Our team consisted of 5 developers – Rafal Hofman, Dariusz Kowalczyk, Gabriel Zink, Jakob Niggel, Martin Berger. Only some of us have ever touched blockchain, none of us ever developed a mobile app. Big applause for my team members for the hard work!

By courtesy of Gudrun Muschalla (BMW AG)

As a reward, we got cool noise-canceling headphones from the Amadeus team :). Thank you!

MobiPay – the idea

Our project in one sentence?  Flexible, decentralized, pay as you go solution, that is currency agnostic and ready for the tokenized economy. Speaking in human language – imagine you jump on and off train, car, a bike with automatic payment carried out in the background on the blockchain, even when each provider is using different currency/token. Imagine your car provider use CarShare Token but for example, Bike provider use Munchen City Token. You as an end user, do not have to care about it. Just buy the tokens needed and travel without boundaries! Cool, isn’t it?

MobiPay concept

MobiPay – the tech

On the tech side, we have been using the following stuff:

  • a mobile app developed in Flutter framework presented on Android device
  • backend, consisting of HTTP and Websockets server in Node.js ( for both simulated service provider and mobile app client)
  • Ethereum PoA network with Parity Docker based node
  • Solidity smart contract – standard ERC20 implementation which we called EuroToken and one mobility platform contract

Also, we have integrated our app with perfectly prepared Amadeus API. Even after the hackathon, Amadeus team was curious about our feedback for further improvements. I encourage you to try it in your project. Who knows, maybe it will be the future of travel  :)?


MobiPay architecture

MobiPay – the present

On our GitHub repo, you can find different presentation steps of the app, with screenshots of what is happening on the app, blockchain or service provider simulation. We also consider the app to be quite good documented so you can start it on your own and play :).

MobiPay app
Blockchain view on the events and transactions

MobiPay – the future

Hopefully, our project will be worldwide blockchain based solution for the pay as you go mobility service 🙂

As we talked with Amadeus team, they are planning to develop their self-service API even more. As some parts of the app were mocked due to lack of reservation services, that would be cool to integrate those into the app when the opportunity comes. What is better than the fully integrated app real-life use case?

I hope that our project will inspire you to take part in hackathons and to think and change something in the present what may be the future :). It is good fun!


Solidity gotchas

As you are here, you probably already know what Solidity is. For those who don’t, – Solidity is a programming language used for development of Ethereum smart contracts. After compilation, bytecode can be deployed to given contract account and be used for interaction with other Ethereum accounts on the network.

Problems of Solidity

Solidity itself has one problem when you are newcomer from another programming language.  As smart contract code is executed on EVM, it means that eventually this code is executed on all nodes around the network (as this is a part of not only mining but also validation process). That is why Solidity is more low-level language that commonly used JavaScript, Java or C#. Also, this is what leads us to the first rule of Solidity:


KISS is a principle used in modern software development, having its origins in US Navy. Nothing refers better to smart contract development than this rule – “keep it simple, stupid”. When creating Smart Contracts for Ethereum mainnet use, one has to care about every single function or even declaration types. The more complicated is your contract, the more gas will be used to execute its methods. That means in the end,  its users will have to pay more. In smart contract, execute as least logic as you possibly can. Handling the rest of it in your backend environment will cost you much less trouble and you users much less money. As an example, we can just mention Solidity bytes32 and string  (String is a dynamically-sized byte array in Solidity!) – which one would you use to store a hash in it? The answer is bytes32, as it is equivalent to the single word in Solidity and consumes much less gas. String stores additional data about UTF-8 encoding and bytes32 is just Hex representation of it. Another example is making cryptographic operations outside Solidity as it is costly to do it inside it.

Gas usage

When using your own, private blockchain, it does not mean you don’t have to worry about gas usage. You can set its value to 0, but still, each block has got a gas limit. Imagine we have a loop, that is based on internal storage of Smart Contract. When adding some data to storage, the loop will execute more and more operations, consuming more and more “free” gas. At some point, the gas limit will be exceeded and no other operations will be able to proceed – our contract will be blocked. Remedy? If not necessary, avoid loops in your contract, especially those based on storage values.


Let’s image you create a loop like this in your Smart Contract, where a is some array of length 1000.

for (var i = 0; i < a.length; i ++)

How many times will it be executed?

The answer is forever ( until it runs out of gas ;)). var is Solidity is equivalent to uint8, which means that it can only store values up to 255. To avoid it from happening, make sure that you execute following instead, where uint is equivalent to uint256

for (uint i = 0; i < a.length; i ++)

Tx.origin vs msg. sender

In Solidity, you can easily determine who is an entity that committed a transaction. When you come across examples on the internet, you can see that both tx.origin and msg.sender are used. Both have the same purpose – determine the sender of the transaction. Never use tx.origin. Msg.sender will always provide direct sender of the message (including contract). Tx.origin will provide the user address who send the message, but it does not take contract addresses into account.  Assume you are interacting with malicious contract, without your knowledge. Then, malicious contract passes your call (with its changes) to the original contract. When using msg.sender attack is compromised as msg.sender indicates malicious contract address. When using tx.origin, your address will be exposed as the sender of the message!

Returning array of strings, returning struct

This is not possible in Solidity (at this moment). Remeber that string is a dynamically-sized array so returning array of dynamic arrays is not possible. Also, it is not possible to return Solidity internal “structs” in your backend. There is, however, a simple workaround, when using structs in mappings. Simply mark your mapping as public. Then, when getting results from your mapping, struct will be returned as an array.

Comparing strings

It is not possible to compare strings in Solidity. There are two hacks for it:

  1. Compare strings hashes. This is a simple way to do it inside your contract, but note that hashing functions use lot of gas
  2. Use this string utils contract

Iterating through mappings, deleting from array or mappings

You cannot iterate through mappings. Mapping is simply keccak hash of your key pointing to some storage value. Remeber that even when you did not initialize some key in your mapping, it is still pointing to 0 equivalent of your value (so if you have a mapping of (address =>bool), 0 equivalent is false.

When deleting some value from mappings or array, note that array is not going to automatically become smaller – deleting simply sets all included values to their 0 equivalent.


Surely when developing smart contract at the beginning, a developer can say that Solidity language is hard to work with. However, when going deeper inside it, one can understand the reason for its construction and hopefully accept and like it.

How to create your own Blockchain?

What is the best way of learning if not creating something on your own? So to learn a blockchain just create one by yourself!


Ethereum mainnet is working on the basis of Proof of Work consensus engine. How does it work is a topic for another blog post :). This time we will concentrate on private blockchain working on the basis of Proof of Authority consensus engine.

In Proof of Authority, some nodes act as authorities. Only those entities are able to issue and confirm new blocks – they are trusted by the rest of the network.


To start your Blockchain network, you need to have Ethereum client. Our choice will be Parity. To download it, when using MacOs, first install homebrew by executing

/usr/bin/ruby -e "$(curl -fsSL"

The proceed with Parity installation

brew tap paritytech/paritytech
brew install parity --stable

When using Linux, download Parity from here using the following command

wget wget

then execute

sudo dpkg -i parity_1.7.9_amd64.deb

When finished with above commands, type  parity in your terminal. This will start Parity node, connected with main Ethereum blockchain, starting to sync with it.

Private Blockchain

You can start your blockchain in different chains. One of them is Ethereum Foundation blockchain, which is the main one. Another one can be Kovan, which is
the test equivalent of mainnet . You can also choose Ethereum Classic chain. Why Ethereum consist of two chains? This is a question for the separate blog post :).

All above are public chains. To create your first, private node simply execute

parity --chain dev

Voilla, your node is starting, you have just created your first private blockchain!

Ok, now we need to get serious. When you want to start your private Blockchain, different than development node, you need to specify its “chain” specification.

In PoA, some nodes act as authorities. It means that they are some entities who are trusted to issue new blocks and validate the network.

In your chain, you can either list the validators or issue a special smart contract, that contains the list of validators. As the second option adds some flexibility, we will use it. By using validation contract, you can add or remove validators even after the chain is deployed! This is not the case with standard validators list.

What we will do, is use Parity sample AdminList contract. Idea is that one of the authorities is an Admin who is able to add new authorities to the network.

First, before chain deployment, a contract needs to be provided with admin address. To start with, we need some account that will be a validator (authority).

To create admin account, start Parity in development mode with JSON-RPC protocol method calling enabled

parity --chain dev --jsonrpc-apis all

You need to create your admin account that will validate the blocks. Execute following in another terminal window (making sure you have cUrl installed)

curl --data '{"jsonrpc":"2.0","method":"parity_newAccountFromPhrase","params":["this is such a great tutorial", "superSecretPassword"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545

First parameter is a recovery phrase of the account the second one is your password. Account address is deterministic so the answer you will get is probably


How our validation Smart Contract code will look like?

pragma solidity ^0.4.8;

// Some addresses are admins.
// Admin can add or remove another admin or a validator.

contract AdminList {
event ValidatorsChanged(bytes32 indexed parent_hash, uint256 indexed nonce, address[] new_set);
event Report(address indexed reporter, address indexed reported, bool indexed malicious);

/// Admin status.
mapping(address => bool) public isAdmin;
/// Last block at which the validator set was altered.
uint public lastTransitionBlock;
/// Number of blocks at which the validators were changed.
uint256 public transitionNonce;
// Current list of addresses entitled to participate in the consensus.
address[] public validatorsList;
// Tracker validator indices.
mapping(address => uint) validatorIndex;

// Each validator is initially supported by all others.
function AdminList() {
isAdmin[0x0013632dfb5759bed171abd94057894b80c07304] = true;

for (uint i = 0; i < validatorsList.length; i++) {
address validator = validatorsList[i];
validatorIndex[validator] = i;

// Called on every block to update node validator list.
function getValidators() constant returns (address[]) {
return validatorsList;

function logTransition() private {
ValidatorsChanged(block.blockhash(block.number - 1), transitionNonce, validatorsList);

function incrementTransitionNonce() private on_new_block {
lastTransitionBlock = block.number;
transitionNonce += 1;


// Add a validator.
function addValidator(address validator) only_admin {
validatorIndex[validator] = validatorsList.length;

// Remove a validator.
function removeValidator(address validator) only_admin {
uint removedIndex = validatorIndex[validator];
// Can not remove the last validator.
uint lastIndex = validatorsList.length-1;
address lastValidator = validatorsList[lastIndex];
// Override the removed validator with the last one.
validatorsList[removedIndex] = lastValidator;
// Update the index of the last validator.
validatorIndex[lastValidator] = removedIndex;
delete validatorsList[lastIndex];
// Reset validator status.
validatorIndex[validator] = 0;

// Add an admin.
function addAdmin(address admin) only_admin {
isAdmin[admin] = true;

// Remove an admin.
function removeAdmin(address admin) only_admin {
isAdmin[admin] = false;


// Called when a validator should be removed.
function reportMalicious(address validator) only_admin {
Report(msg.sender, validator, true);

// Report that a validator has misbehaved in a benign way.
function reportBenign(address validator) only_admin {
Report(msg.sender, validator, false);


modifier only_admin() {
if (!isAdmin[msg.sender]) throw; _;

modifier on_new_block() {
if (block.number > lastTransitionBlock) _;

// Fallback function throws when called.
function() payable {


This is nearly the same as the code provided by Parity. Only change can note, that the address we have generated, was placed inside isAdmin mapping and pushed inside validatorsList.

Now, you have to compile your code. You can use truffle framework, solc or one of the online IDE-compilers.

After compilation, bytecode of our validation smart contract looks like this :


Now, when we have our contract ready, we can move to chain specification.

Chain specification

Our sample chain definition will look like this

"name": "myfirstblockchain",
"engine": {
"authorityRound": {
"params": {
"gasLimitBoundDivisor": "0x400",
"stepDuration": "5",
"validators": { "safeContract": "0x0000000000000000000000000000000000000010" }
"params": {
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2222"
"genesis": {
"seal": {
"authorityRound": {
"step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"difficulty": "0x20000",
"gasLimit": "0x5B8D80"
"accounts": {
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0x0013632dfb5759bed171abd94057894b80c07304": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
"0x0000000000000000000000000000000000000010": { "balance": "1", "constructor" : "606060405234156200001057600080fd5b60008060016000807213632dfb5759bed171abd94057894b80c0730473ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600380548060010182816200007d9190620002a8565b916000526020600020900160007213632dfb5759bed171abd94057894b80c07304909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600091505b600380549050821015620001a0576003828154811015156200010257fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555062000192620001a86401000000000262000a82176401000000009004565b8180600101925050620000e4565b5050620002ff565b620001c6620002826401000000000262000b44176401000000009004565b6002546001430340600019167f47e91f47ccfdcb578564e1af55da55c5e5d33403372fe68e4fed3dfd385764a16003604051808060200182810382528381815481526020019150805480156200027257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831162000227575b50509250505060405180910390a3565b600154431115620002a6574360018190555060016002600082825401925050819055505b565b815481835581811511620002d257818360005260206000209182019101620002d19190620002d7565b5b505050565b620002fc91905b80821115620002f8576000816000905550600101620002de565b5090565b90565b610c26806200030f6000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063170f9291146100b45780631785f53c1461011757806324d7806c14610150578063303e98e5146101a15780633d296efe146101ca57806340a141ff146101f35780634d238c8e1461022c5780637048027514610265578063b7ab4db51461029e578063bfc708a014610308578063fd6e1b5014610341575b600080fd5b34156100bf57600080fd5b6100d5600480803590602001909190505061037a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561012257600080fd5b61014e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506103b9565b005b341561015b57600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061046a565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461048a565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b6101dd610490565b6040518082815260200191505060405180910390f35b34156101fe57600080fd5b61022a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610496565b005b341561023757600080fd5b610263600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106bf565b005b341561027057600080fd5b61029c600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506107cd565b005b34156102a957600080fd5b6102b161087e565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156102f45780820151818401526020810190506102d9565b505050509050019250505060405180910390f35b341561031357600080fd5b61033f600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610912565b005b341561034c57600080fd5b610378600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506109ca565b005b60038181548110151561038957fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151561041057600080fd5b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b60025481565b60015481565b60008060008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156104f257600080fd5b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549250600160038054905003915060038281548110151561054e57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060038481548110151561058c57fe5b906000526020600020900160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060038281548110151561062857fe5b906000526020600020900160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600380548091906001900361066b9190610b69565b506000600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506106b9610a82565b50505050565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151561071657600080fd5b600380549050600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600380548060010182816107739190610b95565b9160005260206000209001600083909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506107ca610a82565b50565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151561082457600080fd5b60016000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b610886610bc1565b600380548060200260200160405190810160405280929190818152602001828054801561090857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116108be575b5050505050905090565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151561096957600080fd5b600115158173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f32c78b6140c46745a46e88cd883707d70dbd2f06d13dd76fe5f499c01290da4f60405160405180910390a450565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610a2157600080fd5b600015158173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f32c78b6140c46745a46e88cd883707d70dbd2f06d13dd76fe5f499c01290da4f60405160405180910390a450565b610a8a610b44565b6002546001430340600019167f47e91f47ccfdcb578564e1af55da55c5e5d33403372fe68e4fed3dfd385764a1600360405180806020018281038252838181548152602001915080548015610b3457602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610aea575b50509250505060405180910390a3565b600154431115610b67574360018190555060016002600082825401925050819055505b565b815481835581811511610b9057818360005260206000209182019101610b8f9190610bd5565b5b505050565b815481835581811511610bbc57818360005260206000209182019101610bbb9190610bd5565b5b505050565b602060405190810160405280600081525090565b610bf791905b80821115610bf3576000816000905550600101610bdb565b5090565b905600a165627a7a72305820a8ebbe55ad842d706116a4bd1720d6184444513036fd36f6278804d5800483af0029" }



What parameters are the most important for you to understand?

  • engine – we will use Proof of Authority consensus engine. Each authority will have given time to issue a new block. As per stepDuration, blocks will be issued every 5 seconds. Validators consist are listed in and managed by validation contract, which is located under address `0x0000000000000000000000000000000000000010`. gasLimitBoundDivisor has standard value.
  • params – two first parameters are to be kept default. NetworkID is to be changed when you are creating your own network, to avoid collisions. At this moment, you can leave this parameter as it is.
  •  genesis – this is a description of data that will be put to genesis block. Please note that difficulty is not so important for us, as we are operating on Proof of Authority, not Proof of Work consensus.
  • accounts – accounts that come with genesis block. First four of them are to be able to use Solidity as a programming language, the last one is a compiled validation contract, that we created before (which consist created account admin details). Also, our admin account address is there – we top it up with lots of ether :).
    If you are interested about the rest of parameters, you can read about those here and here

Starting up the nodes

Ok, so we have nearly all that we need to start a private PoA blockchain. Follow to the folder, where you Parity node stores blockchain information. For MacOs it will be

~/Library/Application\ Support/io.parity.ethereum

For Linux


From now on, all commands are to be executed in those folders (to simplify the commands and avoid adding paths to chain spec and password files).

Then, create a file called myfirstblockchain.json
and put our chain spec in it.

Now you can start your network by executing

parity --chain myfirstblockchain.json --jsonrpc-apis all

Congratulations! You just started your node in PoA private blockchain!

Still, it will not work correctly. There is no authority account stored in your chain data. What you need to do, is either move the account details, that you created before in development chain to your “myfirstblockchain” chain key folder or recreate the same account on this particular private blockchain. We will choose option two, to make it simple.

Make sure you are running Parity with your chain spec ( with above command), and in new terminal window, execute

curl --data '{"jsonrpc":"2.0","method":"parity_newAccountFromPhrase","params":["this is such a great tutorial", "superSecretPassword"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545

This will result in


That means your account was recreated on your private blockchain. As we said, this command is deterministic so same address is given ( remember, it is already stored in your chain spec and validation contract)

That means your account was recreated on your private blockchain. Now, shut the Parity node down. To allow the authority node to issue new blocks, he needs to be supplied with the password, in order to use authority account private key automatically.

What you need to do, is to in your Parity blockchain data folder, create file “secretPassword.pwds” and put your account password inside it (superSecretPassword). It may seem not really secure, but the idea is that as soon as the authority machine is compromised, it should not be an authority anymore. So more secure password storage does not give us anything more in this particular point.

Ok, so we are nearly at the end. Now we need to start out first Parity node. In your Parity data files folder, execute the following command

parity --chain myfirstblockchain.json --port 30300 --jsonrpc-port 8450 --ui-port 8180 --ws-port 8540 --jsonrpc-apis all --ui-no-validation --gasprice 0 --engine-signer 0x0013632dfb5759bed171abd94057894b80c07304 --password secretPassword.pwds

What it will do, is start your Parity node using provided chain spec. UI, RPC, WebSockets will have ports specified by you (8180,8450,8540), Parity will discover other nodes on port 30300. UI will provide no validation (development mode only!). Gas is for free!

What last two commands do, is provide information for node who is the PoA engine block signer and the path to file with his password.

Ok, we have our node started! Most probably you will encounter “Bad instruction fd” error. This is due to Parity updated their validation contract interface. As it comes to development environment is fine, but for real case we would suggest using
majority list contract which is up to date, not causing any errors. The problem is that it is combined with libraries, so the user needs to know how to add compiled library to validation contract node – this is out of scope for this tutorial.

Ok, now it is time to start the second node. To do this execute following in new terminal window

parity --chain myfirstblockchain.json -d /tmp/parity0 --port 30301 --jsonrpc-port 8451 --ui-port 8181 --ws-port 8541 --jsonrpc-apis all --ui-no-validation

So this Parity node instance will use temporary data folder. Also please note that SAME chain spec needs to be used for all nodes in the network, that are to be connected to the private blockchain! Engine signer data is not needed as this node will not issue new blocks.

You have two Parity nodes running. Your own private blockchain is up :)! Now you need to connect them.

When starting, each Parity node has its enode address listed (as Public node URL).

This is used to discover other nodes on the network. You can use curl and RPC  to connect new nodes by executing

curl --data '{"jsonrpc":"2.0","method":"parity_addReservedPeer","params":["ENODEADDRESS"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8541

By changing the ENODEADDRESS and RPC port accordingly. This has to be done for each node!

For me, two commands are to be executed

curl --data '{"jsonrpc":"2.0","method":"parity_addReservedPeer","params":["enode://6aa5a05298287fd1985df3cdcecb99a28f7b52248ff682ef45b6401574b5c1af8c5a7296c9433af9002a96e9b90c7e0f7d6b48c6002419f30ecbd27c951e49be@"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8450
curl --data '{"jsonrpc":"2.0","method":"parity_addReservedPeer","params":["enode://21def0a911d822e759285a082e6073afdbac3b9d3b74a08a72f6efd3074ac2e961d3a6c68da9559f6e98c24eb019407a89159ab533763f495d5d66d15c14155f@"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8451

For both requests, you should see the following response {"jsonrpc":"2.0","result":true,"id":0}.

In logs, you will see 1 node connected.

Now, two local Parity nodes, working in PoA consensus system are connected and ready to work.

Executing the transaction

Now you can proceed to the UIs to execute Ether transfer. We will transfer Ether from one account, located on node 1 to another located on node 2. Note that Parity accounts are stored separately on each node but Blockchain public addresses are available on both. You can, for example, restore an account from the second node on the first one.

UI for the first Parity node is located under

UI for the second node can be found underhttp://

It may happen that UI will query you for authorization token. To generate it for first authority node, execute

curl --data '{"method":"signer_generateAuthorizationToken","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8450

Copy the result to the browser.

For the second node, command would be

curl --data '{"method":"signer_generateAuthorizationToken","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8451

When proceeding to status tab, you will see details about other node connected.

Now, what we can do is create an account on node 2 (that is not supposed to issue block as it is not authority), and try to send him some founds from node1.

On node2 UI, follow the tutorial and create your new account.

Grab its address.

Now, follow to UI 1, and enter the authority account.

Transfer money to account from UI 2. Unlock the account with “superSecretPassword”

After a moment, you will get confirmation that was transaction was mined! You can go to Signer tab to see it


Now proceed to UI 2 and check out that your account is rich now 🙂

Congratulations! You have just executed your first Ether transfer transaction on your private blockchain! Now you can use it for test development of your application or anything you want. Code created in this post is available here.