Introduction

I have this book, called Beginning Ruby, written by Peter Cooper. It’s one of the first book I’ve bought about programming. I’ve read… 20 pages probably… For some reason, I barely started it. The book is getting old, in programming terms, but I feel like learning a little bit of Ruby, and I feel like it will get the job done to teach me the basics. I never used Ruby before, so I’m starting from scratch here.

Continue reading Learning Ruby: Playing with irb

Read more

Introduction

In this article, we will build a simple blockchain network with Hyperledger Fabric. Fabric allows us to build a private blockchain. There are no cryptocurrencies involved. After this, you will have a decent understanding of the different parts needed to start your own private blockchain. In this example, our network will be composed of 3 organisations. Each organisation will have two peers each.
Continue reading Your first Hyperledger Fabric network

Read more

Introduction

React Native allows you to write code for the iOS and Android platforms using the Javascript and React syntaxes. With this logic, you will want to re-use as much code as possible for both platforms. However, at one point, you will have to write code for a specific platform. In this article, we will see how React native makes this possible.

Continue reading React Native: Write code depending on the plateforms

Read more

Introduction

In my last two articles, I explored the Solidity language. This language is designed to work with the Ethereum Virtual machine (EVM). In this article, we will move past the language theory and use a test environment for our contract. With this, we will be able to understand better how Ethereum works.

The tools

In this first article, we will use truffle and ganache-cli. Truffle is a framework for Ethereum development. It allows you to create an test environment, write tests for your contracts and other things. In this article however, we will only use it to create a test environment.

ganache-cli will be used with truffle to create a fully functioning test environment. What we will do here won’t be quite like a real production blockchain, but it will allow us to see how things work.

Installing the tools

  • truffle: [sudo] npm install -g truffle
  • ganache-cli: [sudo] npm install -g ganache-cli

Getting things ready

First, we will initialize a new truffle project. To do this, create a new directory and inside it, run: truffle init.

You will now have several folders. First, open the truffle-config.js and paste this inside:

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
    // to customize your Truffle configuration!
    networks: {
        development: {
            host: '127.0.0.1',
            port: 7545,
            network_id: '*'
        }
    }
}

For Windows users, you will have to remove the truffle.js file to avoid conflicts. For others, you can keep both and put this code in truffle.js, or do like a Windows user, doesn’t matter.

This file indicates that our development network will be running on localhost:7545.

Next, in the contracts folder, create a new DeveloperFactory.sol file. This is where our contract will be written. Put the following inside:


pragma solidity ^0.4.18; contract DeveloperFactory { // Let's create a Developer! event NewDeveloper(uint devId, string name, uint age); uint maxAge = 100; uint minAge = 5; struct Developer { string name; uint id; uint age; } Developer[] public developers; mapping (uint => address) public devToOwner; mapping (address => uint) public ownerDevCount; function _createDeveloper( string _name, uint _id, uint _age ) private{ uint id = developers.push( Developer( _name, _id, _age ) ) - 1; ownerDevCount[msg.sender]++; devToOwner[id] = msg.sender; NewDeveloper(id, _name, _age); } function _generateRandomId( string _str ) private pure returns (uint){ uint rand = uint(keccak256(_str)); return rand; } function createRandomDeveloper( string _name, uint _age ) public payable { require(_age > minAge); require(_age < maxAge); require(msg.value == 5000000000000000000); uint randId = _generateRandomId( _name ); _createDeveloper(_name, randId, _age ); } function getAllDevelopers() public view returns (uint) { return developers.length; } }

If you want to know what is happening here in more details, I covered it in my first and second article about Solidity. But, in short, this contract can be called to create a Developer struct with a name and an age. In our example, creating a new Developer will require 5 ether or ( 5000000000000000000 wei, the lowest denomination possible in Ethereum ).

Next, go inside the migrations folder and create a file called 2_deploy_contracts.js:

const DeveloperFactory = artifacts.require('./DeveloperFactory.sol')

module.exports = function(deployer){
    deployer.deploy(DeveloperFactory)
}

In this file, we import our contract and deploy it to our blockchain.

Launching our test environment

Open a new terminal window and run ganache-cli -p 7545. This will run ganache-cli on port 7545 ( the same we specified in our truffle-config.js file ) and create some accounts for us. Each account will have 100 ether by default. You should see something like this in your console:


Available Accounts ================== (0) 0x473c0be352f997aa0b194786c27d26e29a3f75b1 (1) 0x9657290da5570b17a03198f490b0a2d7eea84ecf (2) 0x516c0e0152d7b85facb7e3da2d30f67e42a80ca9 (3) 0xf81be8bbe99d2302b85f7cb0f60103c435ae703b (4) 0xcfacf5ac5567cfdd70ee5a8a9fe4bf7f74d80b02 (5) 0x623e18e34b2de07933fe179862f038230cc69012 (6) 0xd7100dbc1d6f72777ae2a6f5d95c4b8d71f7ce07 (7) 0x7f40df6c6042888a37124821130910e77051b1cf (8) 0x26a2c2be1f31571f289b7fb60e41f31f7c57a5be (9) 0x08a945825a28166466987d5fc77b016fe3d80aa5

Of course, the accounts’ addresses will be different for you, but you will get 10 accounts to play with.

Now, go back to your first terminal window. Make sure you are inside the folder you created for the truffle project and run: truffle compile, then run truffle migrate --network development. This will compile our code in a language that the Ethereum Virtual Machine (EVM) can understand. Here, ganache will emulate the EVM.

If everything went well, your terminal should have shown this:

truffle migrate --network development
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xc83617394674cd65f751ff9c05438e16339414ccf1e1662ba66479d79335af13
  Migrations: 0xe982e78028e0dfcbdb135e7a3c1e1ed3d98e36e5
Saving successful migration to network...
  ... 0x78bdff98e4dac310de4650048a0856075a460bed9de0c4d4ea879ea399d142c4
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying DeveloperFactory...
  ... 0x0a314c5ed99c772019ea358ac98e002a1442e26903122528d705bf3ff7ed02ed
  DeveloperFactory: 0xc34cc3e53850673db1dea31d267ea1738edc629f
Saving successful migration to network...
  ... 0x95a3cd861f067cdbe8c96f13477526eacd2a7936662f31724e1354922af49664
Saving artifacts...

Notice in the ganache-cli output that our contract has been instantiated:

Transaction: 0xc83617394674cd65f751ff9c05438e16339414ccf1e1662ba66479d79335af13
  Contract created: 0xe982e78028e0dfcbdb135e7a3c1e1ed3d98e36e5
  Gas usage: 269607
  Block Number: 1
  Block Time: Thu May 03 2018 21:04:55 GMT+0200 (CEST)

Console and playing around

Now, in the same terminal window you ran the truffle commands, run truffle console --network development. This will launch the truffle console and allow you to interact with our blockchain. We will use the Web3 Javascript API to make it easier. First, let’s take one of the accounts and put it in a variable:

account = web3.eth.accounts[4]

Next, let’s run the following command:

DeveloperFactory.deployed().then(inst => {Factory = inst})

This will assign a contract’s instance inside the Factory variable. Let’s make sure our account has 100 ether:

truffle(development)> web3.fromWei(web3.eth.getBalance(account).toNumber())
'100'
truffle(development)>

The method getBalance will return a BigNumber type. toNumber() will give us the account’s balance in Wei. We convert it in ether with fromWei().

  • Creating a Developer

Alright, so now we are going to call the function createRandomDeveloper. As you can see, this function takes two parameters, a string _name and a uint _age. Because we also require 5 ether to call this function, we will need to specify this in our function call:

truffle(development)> Factory.createRandomDeveloper('Damien', 26, {from: account, value: web3.toWei(5, "ether")})

Factory is our contract instance. We give three parameters to our function. Damien is the _name, 26 is the _age. The third is an object with a key *from* to know which account is calling it, and a key *value* that specify the value sent by the account. Here, the *from* value is *account*, the variable we created earlier. We are converting 5 ether to Wei to match the required value in our contract.

Your terminal should show something like this:

{ tx: '0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e',
  receipt:
   { transactionHash: '0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e',
     transactionIndex: 0,
     blockHash: '0x3ef1c41cbc79d65c1282a86da3a68120a5c069709a6a5bd3e206ed85d9c270c5',
     blockNumber: 5,
     gasUsed: 148160,
     cumulativeGasUsed: 148160,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e',
       blockHash: '0x3ef1c41cbc79d65c1282a86da3a68120a5c069709a6a5bd3e206ed85d9c270c5',
       blockNumber: 5,
       address: '0x033711f6fd408b10cc94a21a3e8c20f0e75a4615',
       type: 'mined',
       event: 'NewDeveloper',
       args: [Object] } ] }
truffle(development)>

The transaction has been successful. There are a lot of informations here. We can see that the event ‘NewDeveloper’ has been fired, as expected. We have the transaction’s hash, the block hash, the gas used… Let’s check our account’s balance now:

truffle(development)> web3.fromWei(web3.eth.getBalance(account).toNumber())
'94.985184'

Notice that it isn’t 95 ether. This is because when you interact with a contract, you also have to pay additional ether to run a transaction. We have in our transaction informations the cumulativeGasUsed ( 148160 ). This means that 148160 Wei have been used to complete this transaction. We need to multiply this by the gasPrice. Each transaction has a gasPrice. We can retrieve it with the transactionHash, and multiply it by the cumulativeGasUsed to get the transaction’s cost in ether:

truffle(development)> web3.eth.getTransaction('0xa3792da93311fdf60054f8a30e7624dd385ccf36cc639881eeb25308ddad5e0e').gasPrice.toNumber() * 148160
14816000000000000
truffle(development)> web3.fromWei(14816000000000000)
'0.014816'
truffle(development)> 100 - 0.014816
99.985184

And we are able to calculate our balance this way! We can also make sure that our contract’s balance is 5 ether:

truffle(development)> web3.fromWei(web3.eth.getBalance('0x033711f6fd408b10cc94a21a3e8c20f0e75a4615').toNumber())
'5'

You will get your contract’s address in the transaction’s logs field address above. Finally, what would happen if we didn’t sent 5 ether to our contract? Let’s get a new account:

truffle(development)> account1 = web3.eth.accounts[9]
'0x5e273389dba808789a27cb792faaf31429c8de8c'
truffle(development)> web3.fromWei(web3.eth.getBalance(account1).toNumber())
'100'

Now, let’s call our createRandomDeveloper function:

truffle(development)> Factory.createRandomDeveloper('Johnny', 43, {from: account1, value: web3.toWei(10, "ether")})
Error: VM Exception while processing transaction: revert
    at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:41484:16)

truffle(development)> web3.fromWei(web3.eth.getBalance(account1).toNumber())
'99.9976828'

We get an error. But, the gas used to start the transaction is lost anyway! You can see that the account’s balance is not 100 ether anymore.

Conclusion

In the next article, we will explore something close to a real environment, by using geth and mist. I hope this article gave you a better understanding at how you could get started with Ethereum development.

Have fun!

Read more

Introduction

In my last article, we got started with Solidity by creating a simple contract and exploring some simple structures and concepts. We will pick up where we left off.

Mappings

After struct and arrays, we can also store data in mappings. Mappings are a key-value store. For example:

mapping(uint => string) public keyUintStringValue;
mapping(address => uint) public addressToUint;

Here, we have two public mappings. The first one has a uint key and a string value. The second has an address key and a uint value.

Addresses

The Ethereum blockchain is made up of addresses. Each account has an unique address. It takes the following form: 0x0cE440255306E921F41612C46F1v6df9Cc969183. Each address has a certain amount of Ether, which is the cryptocurrency used on the blockchain, and can receive or send Ether to other addresses.

With that in mind, let’s create a new mapping for our DeveloperFactory:

pragma solidity ^0.4.22;

contract DeveloperFactory {

    event NewDeveloper(uint devId, string name, uint age);

    uint maxAge = 100;
    uint minAge = 5;

    struct Developer {
        string name;
        uint id;
        uint age;
    }

    Developer[] public developers;

    mapping (address => uint) public ownerDevCount;
    mapping (uint => address) public devToOwner;

    function _createDeveloper( string _name, uint _id, uint _age ) private{
        uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
        NewDeveloper(id, _name, _age);
    }

    function _generateRandomId( string _str ) private pure returns (uint){
        uint rand = uint(keccak256(_str));
        return rand;
    }

    function createRandomDeveloper( string _name, uint _age ) public view {
        require(_age > minAge);
        require(_age < maxAge);
        uint randId = _generateRandomId( _name );
        _createDeveloper(_name, randId, _age );
    }
}

In the first mapping, we will keep track of the number of devs each account ( address ) created. In the second, we will keep track of the owners for each dev.

msg.sender

Each contract is passive, they don’t do anything until someone triggers them. msg.sender is a global variable that allows us to know which address is responsible for the triggering. It could be a account or another smart contract.

With that information, we can update our mappings appropriately. In the _createDeveloper function, we will increase the ownerDevCount for this particular address. In the devToOwner mapping, we will indicate that the newly created developer is owned by the msg.sender address.

pragma solidity ^0.4.22;

contract DeveloperFactory {

    event NewDeveloper(uint devId, string name, uint age);

    uint maxAge = 100;
    uint minAge = 5;

    struct Developer {
        string name;
        uint id;
        uint age;
    }

    Developer[] public developers;

    mapping (address => uint) public ownerDevCount;
    mapping (uint => address) public devToOwner;

    function _createDeveloper( string _name, uint _id, uint _age ) private{
        uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
        ownerDevCount[msg.sender]++;
        devToOwner[id] = msg.sender;
        NewDeveloper(id, _name, _age);
    }

    function _generateRandomId( string _str ) private pure returns (uint){
        uint rand = uint(keccak256(_str));
        return rand;
    }

    function createRandomDeveloper( string _name, uint _age ) public view {
        require(_age > minAge);
        require(_age < maxAge);
        uint randId = _generateRandomId( _name );
        _createDeveloper(_name, randId, _age );
    }
}

Notice the ++ notation to increase the ownerDevCount[msg.sender], just live Javascript!

Inheritance and import

Contracts can inherit from other contracts. If you open a new file call DeveloperLearning.sol, you can make it inherit from DeveloperFactory.sol:

pragma solidity ^0.4.22;

import "./DeveloperFactory.sol";

contract DeveloperLearning is DeveloperFactory {
    // I have now access to DeveloperFactory functions
}

Notice how we imported the DeveloperFactory contract ( assuming it was in the same folder ). To declare inheritance, we use the keyword is.

payable

In order for a contract to receive ether, we need to have the payable keyword to a function. The amount sent will be accessible in the global variable msg.value. So we could make sure that a certain amount of ether is sent to the contract before the creation of a developer:

pragma solidity ^0.4.22;

contract DeveloperFactory {

    event NewDeveloper(uint devId, string name, uint age);

    uint maxAge = 100;
    uint minAge = 5;

    struct Developer {
        string name;
        uint id;
        uint age;
    }

    Developer[] public developers;

    mapping (address => uint) public ownerDevCount;
    mapping (uint => address) public devToOwner;

    function _createDeveloper( string _name, uint _id, uint _age ) private{
        uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
        ownerDevCount[msg.sender]++;
        devToOwner[id] = msg.sender;
        NewDeveloper(id, _name, _age);
    }

    function _generateRandomId( string _str ) private pure returns (uint){
        uint rand = uint(keccak256(_str));
        return rand;
    }

    function createRandomDeveloper( string _name, uint _age ) public payable {
        require(_age > minAge);
        require(_age < maxAge);
        require(msg.value == 5);
        uint randId = _generateRandomId( _name );
        _createDeveloper(_name, randId, _age );
    }
}

Memory and Storage

In Solidity, there are two places where variables are stored: in storage or in memory. A variable stored in memory is temporary, it exists while the function is used, then it is discarded. A variable stored in storage exists permanently on the blockchain. Most of the time, you don’t have to worry about where to store your variables, as Solidity handles it for you.

For example, state variables ( maxAge, minAge, Developer ), declared outside of functions, are stored in storage. Variables like randId, id, rand are stored in memory.

But, in some cases, you want to explicitly declare where to store certain variables. Solidity allows you to do that with memory and storage keywords.

Read more