When we arrived at Ippon USA for our summer internship, we had little knowledge about blockchains. The goal of this article is to give you the basic tools one can use to build a decentralized application, and some tips about the language we used: Solidity. Of course our list is not exhaustive, and is just here to offer you a peek at Ethereum development.
Let’s start with the definition from Wikipedia:
A blockchain, originally block chain, is a growing list of records, called blocks, which are linked using cryptography. Blockchains which are readable by the public are widely used by cryptocurrencies. Private blockchains have been proposed for business use.
To put it in layman’s terms, a blockchain is simply a transaction record that is decentralized. It means anybody can store and run a copy of the blockchain (becoming a "node”) and therefore read it.
There is not a single blockchain, but different ones for different purposes. The Bitcoin blockchain is the most famous one of all, but there is also the widely popular Ethereum blockchain which we use, and many others. These are public, but you can as easily create a private blockchain, which won’t be available to everyone.
As on a classic ledger, you can only add data to a blockchain. To add new pages to the ledger or new blocks to a blockchain "miners” have to solve complicated and costly algorithm problems. Your transaction will be validated after a few blocks have been mined. This is why transactions cost a fee to reward miners.
Finally, security is a major asset of blockchains, with the help of high-end cryptography and the distributed network effect.
During our internship we worked on the Ethereum blockchain using the Ethereum environment. Proposed by Vitalik Buterin in 2013 (at 19 years old!), it is an open-source public and blockchain-based distributed computing platform and operating system featuring smart contract (scripting) functionality.
What you need to understand is that like the Bitcoin Blockchain, it has a cryptocurrency: Ether (ETH) and you can handle transactions with it. However it is also possible to deploy "smart contracts” which enable you to build decentralized applications. These contracts can be any kind of script which can handle storage, logic, transactions and call from other contracts.
A contract can be a decentralized exchange for instance (Etherdelta), a casino game, or just a token. They are run on the Ethereum Virtual Machine, and are written in a Turing complete language. Naturally, it allows a new range of possibilities for blockchain development. Before being compiled to bytecode for the EVM.
Smart contracts are developed in high-level languages created for Ethereum, the most common one being Solidity. Although bearing similarities to Java and C, Solidity is its own peculiar identity, and is a fascinating development environment.
You may have encountered a lot of applications and "tokens” (cryptocurrencies running on Ethereum): OmiseGO, BNB (Binance Token), CryptoKitties are some examples. The tokens of the Ethereum Blockchain can be traded and bought like other currencies, however they are different from Ether which is the only way to pay "gas fees” and reward miners.
Yes, we are still talking about blockchain development, gas is actually a fee you have to pay to miners for each transaction. A transaction can be anything, you can call a contract, send any ETH to a wallet, trade tokens... We’ll be expanding on this subject later.
If you have already used Coinbase or similar exchanges, you may know that your cryptos are stored on a wallet, represented by a public key or address and secured by a private key. To be clear, a user is represented by an address (his public key), and the same goes for a Smart Contract or even a Transaction hash, the only difference is that users have private keys which contracts do not have. For instance, here is the address of the deployed DAI contract:
0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
But what is DAI? Don’t worry, this is just a teaser...
This all seems really interesting, and you can’t wait to dive in. But first let’s give you a tour of the different tools and techniques to develop on Ethereum. We may have lied a bit about the fact that there is "a Ethereum blockchain”. There are actually several! The "mainnet”, is the only one that really matters, and where all the "real” money circulates.
However, you cannot develop a smart contract and then just launch it on the mainnet. Well you could, but it is not free, and a contract on the mainnet will be there until Doomsday, its code forever unalterable. Developers use "testnets” which grant you free ether to test and faster mining time. Here is a list of tools that can help you get connected and develop:
Perfect, you know the different Ethereum blockchains and how to connect yourself and your applications to them. Now you just need to actually code and deploy them. You can code as you would other project using an environment such as Visual Studio Code which has .sol
extensions (for Solidity, or directly use Remix. It has several major uses. Its compiler will directly say if you smart contract can work and all the possible warnings attached to it. After, you can deploy your contract on the Ethereum net you want using one of the web3.js solutions aforementioned. But it doesn’t stop there! You can directly interact with the deployed contracts with simple buttons to call the different functions, and you will receive all the informations needed about the results or the transactions in the Remix console.
If you made it this far, you are really interested on how the Ethereum blockchain works, or you want to get to it and develop in Solidity! There is a lot to know about Solidity: although it was made with a really high-level appearance close to Java, the aforementioned specifics of blockchain and smart contracts differentiate it a lot. A lot of trial and error was necessary for us and do not hesitate to ask for help on StackExchange or all your favorite communities, Ethereum development is very active.
The basic idea is that a contract is a complete package, containing state variables, functions, functions modifiers, events, struct types, and enum types. You can also inherit from other contracts. It looks really similar to a Java class, it even also has a constructor if you want to initialize some variables. You can also easily access to the transaction attributes :
A function, if it changes any state variable, will cost gas fees to the user or contract calling it.
pragma solidity ^0.4.0;
contract SimpleMarket {
function sell() public onlySeller { // Function
// ...
}
}
You can add a function modifier to a function, which is basically code common to all functions using it. A general case if having a "onlyAdmin” modifier as below. We’ll explain the "require” later!
modifier onlySeller() { // Modifier
require(msg.sender == seller, "Only seller can call this.");
_;
}
The last word of the list that should have been alien to you is event, which is something that will be "fired” by the contract when it appears in the code, and will be logged inside the transactions using your contract.
contract SimpleMarket {
event HighestSell(address seller, uint amount); // Event
function sell() public {
// ...
emit HighestSell(msg.sender, msg.value); // Triggering event
}
}
The types used in Solidity are pretty much the ones you know and are fairly close to C. String are dynamic arrays of characters, and as such can be tricky to manage. But you may be surprised to not see float, as they do not exist. You will need to be cautious and use multipliers! The types developers seem to affectionate the most are uint256 as they offer the largest numbers (2^256 integers), and addresses, as they are used for most objects such as accounts and contracts.
uint256 i = 42;
address x = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
Another fun thing to manage close to C is of course the storage. Objects do not always behave the way you want them to and you need to remember that everything has a price on a blockchain.
You have to know if the object you are defining in your function needs to be "memory” (stored temporarily) or "storage” (knowing that it will be stored in the blockchain). For example, a dynamic array has to be storage, so you may need to find a way to know the exact number of object it should need.
Other oddities may include structures not being able to be defined recursively, or more importantly, all state variables being initialized to their default value. This means that a boolean will be automatically false, and also that a mapping (Solidity’s widely used equivalent of a hashmap) will be initialized for every key at the byte 0. This means that you cannot iterate on the keys!
LinkedList.Data storage list;
uint256[] memory _parts;
Complex storage structures can be useful, such as the Linked List we needed to implement. By using a mapping from a uint id to a Node structure (with the data we want, the information by which it will be sorted, and the id of the next Node) and keeping the id of the head of the list, we could make an easily sortable list where we can add and delete nodes.
One of the burdens of Solidity is how to code a secure smart contract. Writing a contract that behaves as you expect is quite easy, however making sure it won’t later act strangely is harder. Solidity is a constantly evolving language, but can still fall short of being a secure language for creating decentralized applications.
One of the tools provided by Solidity is for Error handling. You will probably want to have quite a few "Require” functions used throughout your code, as they will "Revert” (which means cancelling the execution of the transaction and revert back any gas used to the sender) when you need them to. They can be used to check users balance before transfers for instance.
Now let’s go over a few problems or considerations you may encounter while coding in Solidity (well, that we have encountered or seen in solidity hacking challenges). A lot of them are really specific to the way blockchain works.
The most common and biggest problem to check out is the classic reentrancy problem. For example, you do not want a user to be able to call two times a function (or two different functions) that will give them tokens before depleting their balance!
contract Fund {
/// Mapping of ether shares of the contract.
mapping(address => uint) shares;
/// Withdraw your share.
function withdraw() public {
/// Sending the shares beforing depleting!
if (msg.sender.send(shares[msg.sender]))
shares[msg.sender] = 0;
}
}
Close to this problem and more specific to blockchain, is the fact that every transaction being public, a malicious user could see a transaction he’s interested in, and before it is mined, do the exact same transaction but with way more gas, making his transaction be processed faster!
If the code of a soon-to-be-deployed app is public, why not do more, and precompute its future address to send ETH to it before, allowing unexpected events? You can precompute a lot actually, and doing random functions in your code that use block number or timestamp (the time a block is mined) is not safe as it is pretty easy to figure out!
pragma solidity ^0.4.18;
contract CoinFlip {
uint256 public consecutiveWins;
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
function CoinFlip() public {
consecutiveWins = 0;
}
function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(block.blockhash(block.number-1));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
}
Be very cautious when you call other contracts, because they could hide data to execute, or use the call stack limit depth or gas to halt the execution where they want it to.
However, do not be fooled thinking the risks can only come from malicious users, since Solidity may behave in ways you would not expect: overflow and underflow errors are legion in Solidity, nonexistent float type means your division will always be rounded...
There is a special function that exists in a contract to address the need for floating point. It does not have a name, and will be executed when no other appropriate function is found. It is called the fallback function, and can be used for quite a few interesting hacking tricks. However as we found out, you can not close it up completely, "just to be sure”, as you need to have a payable fallback function if you want it to receive ETH from another contract!
function() public payable { //Fairly open now!
}
Security in Solidity, as in every language, is a difficult system of checks and balances between features and protection.
A classic game of increasingly difficult solidity hacking challenges. It gets extremely tough!
A coding contest that highlights a lot of mistakes or malicious attacks possible in Solidity. There’s lot of exemples to check out on GitHub!
A collection of "best practices" in the Ethereum development world by Consensys, a major actor in the Ethereum market.
We hope this short introduction to Ethereum development has helped you. We also would like to sincerely thank the entire team of Ippon USA who hosted two French interns in Washington DC: our mentor Chris Lumpkin, our co-workers Dagmawi Mengistu, Priya Rajanna and Matt Reed, who all welcomed us and showed us a priceless glimpse of the American melting pot culture.