📜 ⬆️ ⬇️

Dive into Ethereum

Today, Ethereum has become one of the most recognizable brands in the blockchain sphere, having come closest in popularity (and capitalization) to Bitcoin. But due to the lack of a “full-fledged” Russian-speaking guide, domestic developers still do not really understand what kind of animal it is and how to work with it. Therefore, in this article I tried to cover as much as possible all aspects of the development of smart contracts under Ethereum.


I will tell you about the development tools, the programming language itself, the process of adding a UI and many more interesting things. In the end, we get a regular business card site, but under the hood it will work on Ethereum smart contracts. Anyone interested - please under the cat.


preview



Content



Introduction to Ethereum


This article is not intended for those who are not at all familiar with Ethereum (or blockchain technology in general), so there will not be explanations of basic things like blocks , transactions or contracts . I mean that you are at least a little aware of what is happening. Otherwise, look through the articles from the list below, and then come back :)



More links to interesting articles can be found at the end.


PS I work under Ubuntu 16.04, so the whole process of installation, development and deployment will be described under this OS. Nevertheless, all the tools used are cross-platform (most likely, not tested), so if you wish, you can experiment on other OSs.


Instruments


Geth


Work with Ethereum is possible through a huge number of clients, some of which are terminal-based, part of the GUI, and there are several hybrid solutions. A sort of standard is [Geth] (), which is developed by the Ethereum team. I already wrote about him in previous articles , but just in case I repeat.


The client is written in Go, installed in the standard way :


sudo apt-get install software-properties-common sudo add-apt-repository -y ppa:ethereum/ethereum sudo apt-get update sudo apt-get install ethereum 

Geth itself does not have a GUI, but working with it from the terminal is quite nice. This describes the entire set of command line arguments, but I will describe some of the most popular ones.


Here is the command that I most often use in my work: $ geth --dev --rpc --rpcaddr "0.0.0.0" --rpcapi "admin,debug,miner,shh,txpool,personal,eth,net,web3" console



Parity


Geth is pretty good, but lately it is increasingly possible to meet another client - Parity, written in Rust. Its main difference from Geth is the built-in web interface, in my opinion, the most convenient among all currently existing. Installation:


 sudo <(curl https://get.parity.io -Lk) 

After the download is complete, run parity in the console and at localhost: 8180 you can find the wallet itself.


parity


Another plus: Parity is faster than its competitors. At least the authors say so, but I feel this is true, especially in terms of blockchain synchronization.


The only caveat is that there is no parity console. But you can easily use Geth for these purposes:


 $ parity --geth # Run parity in Geth mode $ geth attach console # Attach Geth to the PArity node (Do it in another window) 

TestRPC


This tool, unlike the previous ones, will be useful only to developers. It allows one team testrpc to raise a private blockchain with the RPC protocol enabled, a dozen pre-created accounts with eters on the account, a working miner, and so on. The entire list is here . In fact, testrpc is the same geth --dev --rpc ... , only this time you do not need to spend time on creating accounts, turning on / off the miner and other routine actions.


Installation - npm install -g ethereumjs-testrpc .


testrpc


Mist


The most popular wallet for Ethereum, although in fact it can do a lot more. Here's a great article where step by step explains the whole process of working with Mist. Download the latest version from the releases page . In addition to working with the wallet, there is the possibility of working with contracts.


mist


Remix


The most popular IDE for developing contracts. It works in a browser at ethereum.imtqy.com/browser-solidity/ , supports a huge number of functions:



There is no autocompletion, which is very sad.


remix


Cosmo


Another IDE for developing smart contracts, written in Meteor, works out of the box. To begin, open a new terminal and bring up the node with the RPC interface enabled geth --rpc --rpcapi="db,eth,net,web3,personal" --rpcport "8545" --rpcaddr "127.0.0.1" --rpccorsdomain "localhost" console . After that you can run the IDE itself:


 $ git clone http://github.com/SilentCicero/meteor-dapp-cosmo.git $ cd meteor-dapp-cosmo/app $ meteor 

Then open localhost: 3000 and you can start working:


cosmo_screenshot


Etheratom


The latest tool for today to accelerate the development of smart contracts. This is a plugin for the Atom editor, installed using apm install atom-ethereum-interface . Stuck comfortable, I use it myself. Allows you to work with JS EVM or connect to the node via RPC. Compiles the contract for CTRL + ALT + C , deplot to the network on CTRL + ALT + S Well, it provides a good interface for working with the contract itself.


atom_ethereum


If you don’t need such featured functionality inside the editor, then for Atom there is a separate plug-in with syntax highlighting of Solidity - language-ethereum . The latter is essentially a plugin for Sublime text , only converted to work in Atom.


Solidity


You may have heard that it is possible to write contracts not only for Solidity, but also in other languages, for example Serpent (looks like Python). But the last committee in the develop ethereum / serpent branch was about six months ago, so, apparently, the language, alas, is deprecated.


Therefore, we will write only on Solidity. So far, the language is at a relatively early stage of development, so there are no complex structures or unique abstractions in it. Therefore, I don’t see any reason to talk about it separately - anyone with experience in programming can write freely on it after 20 minutes of reading the documentation . In case you have no such experience, below I commented in some detail on the entire contract code.


For self-study there are some very good examples with the most detailed descriptions:



Once again I will note (excellent!) The documentation of the language, in some places even translated into Russian.


Create a business card contract


It's time to create our contract. In the end, this will be a business card application on which we will place the “summary” itself:



First step


First, create a contract template and a constructor function . It should be called as well as the contract itself and is called only once - when the contract is loaded into the blockchain. We will use it to initialize a single variable - address owner . As you probably already guessed, the address of the person who uploaded the contract to the network will be recorded in it. And it will be used to implement the functions of the administrator of the contract, but more on that later.


 pragma solidity ^0.4.0; contract EthereumCV is Structures { address owner; // ===================== // ==== CONSTRUCTOR ==== // ===================== function EthereumCV() { owner = msg.sender; } } 

Basic information


The next step is to add the ability to specify basic information about the author - name, mail, address, and so on. For this we will use the most common mapping , which must be announced at the beginning of the contract:


 address owner; mapping (string => string) basic_data; 

In order to be able to “receive” this data from a contract, we will create the following function:


 function getBasicData (string arg) constant returns (string) { return basic_data[arg]; } 

Everything is simple here, one need only mention the constant modifier - it can (and should) be used for those functions that do not change the state of the application. The main advantage of such functions (sic!) Is that they can be used as ordinary functions.


Administration


Now you should think about filling your resume with content. In the simplest case, we could get by with a function like


 function setBasicData (string key, string value) { basic_data[key] = value; } 

But in this case, if desired, anyone could change, for example, our name by calling setBasicData("name", "New Name") . Fortunately, there is a way to stop any such attempts in just one line:


 function setBasicData (string key, string value) { if (msg.sender != owner) { throw; } basic_data[key] = value; } 

Since we will have to use a similar construction more than once (for example, when adding a new project), it is worth creating a special modifier :


 modifier onlyOwner() { if (msg.sender != owner) { throw; } _; // Will be replaced with function body } // Now you can use it with any function function setBasicData (string key, string value) onlyOwner() { basic_data[key] = value; } 

If desired, you can use other methods of authorization, for example by password. The hash will be stored in the contract and compared with the one entered at each function call. But it is clear that this method is not so safe, since no one has canceled the rainbow tables and dictionary attacks. On the other hand, our method is also not perfect, because if you lose access to the owner address, you will not be able to edit anything.


Modularity


The next step is to create several structures for project description, education, skills, and publications. Everything is simple here, the structures are described just like in C. But instead of describing them in the current contract, we will move them into a separate library (in a new file). In this way, we will be able to avoid huge code sheets and structure our project.


To do this, in the same directory, create a new file structures.sol and the Structures library. And inside it we will describe each of the structures:


 pragma solidity ^0.4.0; library Structures { struct Project { string name; string link; string description; } struct Education { string name; string speciality; int32 year_start; int32 year_finish; } struct Publication { string name; string link; string language; } struct Skill { string name; int32 level; } } 

Now you only need to import the resulting file.


 pragma solidity ^0.4.0; import "./structures.sol"; contract EthereumCV { mapping (string => string) basic_data; address owner; Structures.Project[] public projects; Structures.Education[] public educations; Structures.Skill[] public skills; Structures.Publication[] public publications; // ... } 

The most savvy have already guessed that the notation Structures.Project[] projects means the creation of a dynamic array with elements of the Project type. But with the public modifier is more difficult. In essence, it replaces us with writing functions like get_project(int position) { return projects[position]; } get_project(int position) { return projects[position]; } - the compiler itself will create such a function. It will be called as well as a variable, in our case - projects .


You may ask why we did not write mapping (string => string) public basic_data at the very beginning, but instead created this function ourselves? The reason is simple - the public so far does not know how to work with variables for which the key is the dynamic data type ( string is this type).


 Unimplemented feature (/src/libsolidity/codegen/ExpressionCompiler.cpp:105): Accessors for mapping with dynamically-sized keys not yet implemented. 

To do this, declare basic_data such as mapping (bytes32 => string) .


BTW Just in case, I note that in addition to the local file, Remix can import .sol files using a link to Github and even using the Swarm protocol (this is something like distributed storage for Ethereum, more here )


Load and delete data


I think many of you have already guessed how to implement the work with new data. I will show on the example of the list of publications, in other cases everything is the same:


 function editPublication (bool operation, string name, string link, string language) onlyOwner() { if (operation) { publications.push(Structures.Publication(name, link, language)); } else { delete publications[publications.length - 1]; } } 

Using the operation parameter, we got rid of writing a separate function to delete the last publication (crutch, but we are just learning). Although it should be noted that this way of getting rid of an element in an array is actually not entirely correct. The element itself will of course be deleted, but an empty space will remain in place of the index. In our case, this is not fatal (we will check the emptiness of individual elements on the client side), but, generally speaking, we should not forget about it. Moreover, it is not that difficult to move the entire array and reduce the length counter.


We give the data


As I said, the public modifier in the Project[] public projects provided us with a function that returns the project projects[i] by index i . But we do not know how many projects we have, and here there are two ways. The first is to iterate over i until we get an error about a non-existent element. The second is to write a separate function that will return us the size of the projects . I will go the second way, a little later I will say why:


 function getSize(string arg) constant returns (uint) { if (sha3(arg) == sha3("projects")) { return projects.length; } if (sha3(arg) == sha3("educations")) { return educations.length; } if (sha3(arg) == sha3("publications")) { return quotes.length; } if (sha3(arg) == sha3("skills")) { return skills.length; } throw; } 

Note that we cannot compare the two strings in the usual way 'aaa' == 'bbb' . The reason is the same, string is a dynamic data type, working with them is quite painful. So it remains to either compare hashes or use the function for character-by-character comparisons. In this case, you can use the popular library stringUtils.sol , it has such a function.


Depla


In different development environments, the compilation process and deployment is different, of course, so I will limit Remix as the most popular.


First, of course, fill in all the code (the final version can be found in the project repository ). Next, in the Select execution environment drop-down list, select Javascript VM - for now let's test the contract on the JS blockchain emulator, and later we will learn how to work with the present. If everything is in order with the contract, then the Create button will be available to you - click and see:


remix_create


Now, when the contract is filled in the blockchain (its emulation, but not the essence), we can try to call some function and see what happens. For example, you can save an email in the contract - to do this, find the function setBasicData , fill in the field and click the button with the name of the function:


remix_set_basic_data


The function returns nothing, so result: 0x . Now you can request an email from the contract: look for the getBasicData function and try:


remix_get_basic_data


With the rest of the functions I suggest you to experiment yourself.


Add UI


Below I will tell you about the most common way to add UI to your contract. It allows using JS and HTML to create interfaces of any complexity, it is enough to have access to the work node of Ethereum (or its analogs).


Web3.js


This is the Ethereum compatible JavaScript API implements the Generic JSON RPC spec. Js and as a meteor.js package.

This is a JS library that allows you to use the Ethereum API using regular JS. In fact, with its help, you simply connect the node and you get something like the geth console in the browser. Installed via npm or bower :


 $ sudo npm install web3 $ bower install web3 

Here is an example of working with web3 through node.js (run testrpc or any other node with an RPC interface):


 $ node > var Web3 = require('web3'); > var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); > web3.eth.accounts [ '0x5f7aaf2199f95e1b991cb7961c49be5df1050d86', '0x1c0131b72fa0f67ac9c46c5f4bd8fa483d7553c3', '0x10de59faaea051b7ea889011a2d8a560a75805a7', '0x56e71613ff0fb6a9486555325dc6bec8e6a88c78', '0x40155a39d232a0bdb98ee9f721340197af3170c5', '0x4b9f184b2527a3605ec8d62dca22edb4b240bbda', '0x117a6be09f6e5fbbd373f7f460c8a74a0800c92c', '0x111f9a2920cbf81e4236225fcbe17c8b329bacd7', '0x01b4bfbca90cbfad6d6d2a80ee9540645c7bd55a', '0x71be5d7d2a53597ef73d90fd558df23c37f3aac1' ] > 

The same, only from the browser JS console (do not forget about <script src="path_to/web3.js"></script> )


browser_js_web3


That is, at this moment we can start the node, synchronize it with the current chain, and it remains only to impose our application. But there are two subtle points: first, you need to synchronize the Ethereum blockchain, and you probably have not done it yet.


The second caveat - RPC does not have any built-in authorization mechanism, so anyone can find out the address of your node from the JS source code and use it for your own pleasure. Here, of course, you can write some wrapper on Nginx with the simplest HTTP basic auth, but this is some other time.


Metamask


So now we will use the Metamask plugin (alas, only for Chrome). In fact, this is the layer between the node and the browser, which allows you to use web3 in the browser, but without its node. Metamask works very simply - it embeds web3.js on every page, which automatically connects to Metamask RPC servers. After that you can use Ethereum to its fullest.


After installing the plug-in, select Testnet in the upper left corner and get a few ethers on the Metamask tap . At this point, you should get something like this (of course, with a clean history):


metamask_ready


Deploy with Metamask


With Metamask, signing a contract into a network is as easy as in the case of JS EVM. To do this, open Remix again and in the Select execution environment list select Injected Web3 (most likely it is automatically selected). After that, click Create and see the pop-up window:


metamask_popup


A little later, the inscription Waiting for transaction to be mined.. changes to the information about the published contract - this means that he got into the blockchain. You can find out the address of the contract by opening Metamask and clicking on the form entry:


metamask_info


However, now, if you want, for example, to call the function editProject(...) , then you also have to confirm the transaction and wait until it is zamynaena in the block.


Example


Now it's up to you - you need to learn how to get data from a contract through Web3. To do this, first, you need to learn how to determine if web3 is present on the page:


 window.addEventListener('load', function() { // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (typeof web3 !== 'undefined') { // Use Mist/MetaMask's provider console.log("Web3 detected!"); window.web3 = new Web3(web3.currentProvider); // Now you can start your app & access web3 freely: startApp() } else { alert('Please use Chrome, install Metamask and then try again!') } }) 

Inside startApp() I defined all the logic of working with a contract, thereby avoiding false positives and errors.


 function startApp() { var address = { "3" : "0xf11398265f766b8941549c865d948ae0ac734561" // Ropsten } var current_network = web3.version.network; // abi initialized ealier, in abi.js var contract = web3.eth.contract(abi).at(address[current_network]); console.log("Contract initialized successfully") contract.getBasicData("name", function(error, data) { console.log(data); }); contract.getBasicData("email", function(error, data) { console.log(data); }); contract.getSize("skills", function(error, data) { var skills_size = data["c"][0]; for (var i = 0; i < skills_size; ++i) { contract.skills(i, function(error, data) { // Don't forget to check blank elements! if (data[0]) { console.log(data[0], data[1]["c"][0]); } }) } }) } 

js_logs


Total


Now that you have figured out everything, you can take on the layout and JS. I used Vue.js and Spectre.css , for visualization of the skills added by Google Charts . The result can be seen on pavlovdog.imtqy.com :


cv


Instead of conclusion


You just saw how you can quickly create an application that directly uses blockchain technology. Although in the pursuit of simplicity (after all, this is an educational article), I made some simplifications that should not be admitted in a good way.


For example, we use someone’s gateway (I’m talking about Metamask), instead of working with our node. This is convenient, but the blockchain technology in the first place - decentralization and the absence of intermediaries. We don’t have all this - we trust the guys from Metamask.


Another, not so critical problem - we forgot about the cost of the deployment of contracts and transactions to them. In practice, it is worth thinking ten times before using string instead of bytes , because such things primarily affect the costs when working with a contract. Again, in the example I used Testnet , so we did not spend any money, but when working with Main net you should not be so wasteful.


In any case, I hope that the article turned out to be useful, if you have questions - ask in the comments or email me.


Links



')

Source: https://habr.com/ru/post/327236/


All Articles