Chapter 3. The Ethereum platform

This chapter covers

  • Interacting with Ethereum through the Ethereum wallet
  • Understanding the characteristics of Ethereum smart contracts
  • Interacting with Ethereum through the Go Ethereum (geth) client
  • Understanding and managing accounts

The previous chapter introduced Dapps and the underlying concepts and technologies, among which is Ethereum. In this chapter, I’ll cover Ethereum in much greater depth, so you’ll get the foundation you need to develop Dapps on this platform effectively. I’ll begin by presenting the Ethereum wallet, a UI tool you’ll use to start interacting with the Ethereum P2P network by transferring some Ether, the Ethereum cryptocurrency. Then you’ll get a wide overview of smart contracts, the key technology that Ethereum introduced.

After learning about Go Ethereum, one of the many clients available on the platform, and once you understand the purpose of accounts, you’ll move to the next level and start interacting with the Ethereum network through Go Ethereum in several ways: with commands entered into the operating system shell, with instructions entered into the Go Ethereum console, and with HTTP requests. At that point, you should have acquired enough familiarity with the platform to progress with confidence through the rest of the book. It’ll be a dense but rewarding chapter. Let’s get started.

3.1. Connecting to Ethereum through the wallet

The Ethereum network offers two main graphical user interfaces:

  • Mist—A browser for Ethereum Dapps
  • Ethereum wallet—A specific version of Mist with a single Dapp bundled in it

You’ll learn about Mist in a later chapter. For the moment, we’ll focus on the Ethereum wallet. The main purpose of the wallet is to store, receive, and transfer Ether, the Ethereum cryptocurrency. It’s similar to a Bitcoin wallet, if you’ve ever handled bitcoins, and you’ll initially use it to transfer Ether so that you can start to interact with the platform in the simplest way. It’s also a useful tool to learn how to deploy smart contracts and interact with them on one of the public Ethereum networks.

3.1.1. Getting started with the Ethereum wallet

When you open the download page (https://github.com/ethereum/mist/releases), you’ll find various versions of Mist and the Ethereum wallet. Pick the version of the Ethereum wallet corresponding to your operating system and download the related zip file. (I’ve picked Ethereum-Wallet-win64-0-11-1.zip.) After unzipping it, you can run the executable Ethereum Wallet.exe directly. The first time you launch it, it’ll default to the main network. In this chapter, you’ll work against the public test Ropsten network instead. To select it, you must pick it from the top menu, as shown in figure 3.1: Develop > Network > Ropsten. You also can select the Ropsten network through the Alt+Ctrl+2 shortcut.

Figure 3.1. Choosing the test Ropsten network from the Develop > Network > Ropsten menu option or through the Alt+Ctrl+2 shortcut

After you select the Ropsten network, the wallet will start to synchronize with the related blockchain. By default, the synchronization mode is Light, which, as you saw in the previous chapter, downloads the current state trie from a peer full node, so you don’t have to wait long (minutes). This will allow you to get up and running quickly. But if you want to perform write operations, such as transferring Ether or deploying smart contracts, which is what you’ll be doing, you must get a full copy of the blockchain—you can choose between Fast and Full. (Go back to the previous chapter if you don’t remember how these sync modes work.) Here’s a rough estimate of what to expect when you’re synchronizing the Ropsten blockchain locally:

  • Fast—Uses roughly 1 GB of disk space and takes two to four hours
  • Full—Uses roughly 100 GB of disk space and can take up to a day or two

Once you’re synchronized, you’ll be able to see synchronization details at the top of the screen, including the name of the network you’re connected to, the latest block number, and the number of seconds passed since receiving the last block, as shown in figure 3.2.

Figure 3.2. You can see synchronization details, including the name of the network and the latest block number, at the top of the screen.

Warning

To perform the operations I’ll cover in this chapter and the next, you must choose Fast or Full synchronization; otherwise, you won’t be able to transfer Ether or deploy a contract through the wallet. To be able to execute a transaction, you must have a full local copy of the blockchain. If the wallet appears unresponsive after a while and you don’t notice any progress in the synchronization, it might be because the wallet hasn’t managed to connect to any peer nodes. In that case, close it down and try to synchronize the Ropsten blockchain through the geth client. If you need to do this, read about geth in section 3.3, and then synchronize it to Ropsten as explained in chapter 8, section 8.1.

Figure 3.3. Accounts overview screen. You can create an account by clicking Add Account.

At this point, you’re ready to create accounts. Click the Wallets tab, which will bring you to the Accounts Overview screen, and then click the Add Account button, which has a plus symbol next to it, as you can see in figure 3.3.

You’ll see a small dialog box asking for a strong password. (Make sure you stretch the dialog from the bottom-right corner until you see the OK button.) After entering a password (twice), you’ll be reminded to back up your keyfiles (more on this later) and password.

Warning

Manage your passwords carefully. If you forget your password, you won’t be able to click any “I Forgot My Password” button. Losing your password means losing the Ether stored in the account. This isn’t a major problem when pointing to a test network, because Ether has no value there. But, especially when moving to the production network, you should get into the habit of choosing a strong password and keeping a copy of it somewhere secure. Better safe than sorry!

Note

If you’re using the Ethereum wallet for Mac OS or LINUX, the interface is slightly different, screenshots won’t match what you see, and my descriptions might not work to the letter. Also, the default network shown might be different. But you should be able to find alternative ways to perform the operations I describe.

After the wallet has generated the account, on the Accounts Overview screen you’ll see Account 1 with the related hexadecimal address and a balance of zero Ether. I’ll cover accounts in more detail later; for now, create one more account in the same way, and you now should see two accounts on the screen, as shown in figure 3.4. Now that you have a couple of accounts (feel free to create more), you can try out some common operations with the wallet.

Figure 3.4. Account details shown on the Accounts Overview screen after their creation

3.1.2. Performing common operations with the wallet

With a balance of zero Ether (the Ethereum cryptocurrency) on all your accounts, you won’t be able to go too far, because as you’ll learn, to execute transactions on the network, you must pay transaction costs in Ether. Because it isn’t possible to buy Ether in the test network, you’ll have to generate it somehow. One way is through mining.

Mining

Mining is the process through which new transactions get consolidated into blocks of the blockchain. Many participants in the Ethereum network run special mining nodes through which they hope to be rewarded in Ether tokens and be compensated for the computational power they provide to the network. Although mining Ether in the real public network is challenging and requires specialized hardware based on advanced GPU chipsets, it’s easy to generate Ether in the test network with “plain CPU” mining through the wallet menu:

Develop > Start Mining (Testnet only)

Note

The menu option Develop > Start Mining will appear only after the blockchain has been entirely synchronized in Fast or Full mode.

The CPU of your machine will get busy, and after a few minutes you should have accumulated enough Ether to get going.

If for any reason mining is taking too long, an alternative way to fund your Ropsten accounts is through the so-called faucet. The following URL can send your addresses free test Ether: http://faucet.ropsten.be:3001/donate/<destinationaddress>, for example, http://faucet.ropsten.be:3001/donate/0x8713Cb74c7DB911f2056C8DD2bA5036-7-eeEa11D0. After a few seconds, your destination address should receive 1 Ether, as you can see in figure 3.5. You can check the status of the Ether transfer from the faucet by entering your address in the text box at the top of the Ropsten Etherscan webpage: https://ropsten.etherscan.io/. If faucet.ropsten.be isn’t working as expected or you keep getting gray-listed, try https://faucet.kyber.network/. Alternatively, try Google ropsten faucet.

Figure 3.5. Account balances after using the faucet facility

Transferring Ether

Now you can try to move some Ether between accounts. It’s easy. First, go to the Send screen. Select the source (Account 1) and target account addresses (copy the address of Account 2 from the Accounts Overview screen), then select the amount of Ether you want to transfer—for example, 0.5 Ether. Finally, after deciding on a transaction fee, click Send Transaction. Don’t worry too much about this for now; we’ll examine transaction fees later.

You’ll be prompted to enter a password, as shown in figure 3.6. Enter the password of the source account (Account 1) to digitally sign the transaction and subsequently prove that the account owner is sending it, and then click Send Transaction. You’ve now completed your first Ether transaction!

Figure 3.6. Password entry screen for moving Ether between accounts. You’re required to enter the password of the sending account when transferring Ether with the Ethereum wallet, to digitally sign the transaction and consequently prove it’s genuinely the account owner who’s sending the Ether.

To check the status of the transaction, go back to the Accounts Overview screen and click Latest Transactions at the bottom of the screen. Clicking on the related link will allow you to drill down into further details, such as those shown in the screenshot in figure 3.7.

Figure 3.7. Summary transaction information from the Transactions panel of the Accounts Overview screen

You can get a better idea of how your transaction has contributed to the Ropsten blockchain by checking it on Etherscan, a website reporting the real-time evolution of the Ethereum blockchain. Use this URL to access the test network: https://ropsten.etherscan.io/. You’ll be able to get detailed block and transaction information.

Now that you’ve acquired some familiarity with Ethereum, it’s time to learn more about one of the greatest innovations that this platform introduced: smart contracts. Once you grasp how smart contracts work, you’ll be able to make further progress on SimpleCoin, the cryptocurrency you started to build in the previous chapter.

3.2. Smart contracts: The brain of Dapps

As I described in chapter 1, an Ethereum smart contract, or simply contract, is a software artifact containing business rules and a state. It’s written in a high-level language such as Solidity, compiled into EVM bytecode, deployed onto the Ethereum network, and stored on its blockchain against a specific account generated at deployment.

As shown in figure 3.8, a contract receives transaction messages from a user account (or from other contracts) and executes its logic on the Ethereum Virtual Machine (EVM). This might optionally involve sending messages to other contracts, reading state from the blockchain, or writing state to the blockchain (specifically from/to the State Merkle-Patricia trie). The account sending the message to the contract gets charged (in Ether) by the successful mining node for computation and network resources consumed during the processing of the requested operation. The amount of such computation and resources is calculated in a unit called gas, as you’ll see in section 3.2.3, so it’s common to say that a transaction consumes a certain amount of gas (rather than resources).

Figure 3.8. An Ethereum contract receives a transaction message from a user account. Its logic is executed on the Ethereum Virtual Machine (EVM); then the successful miner calculates the cost for the computational and network resources used, in a unit called gas, and charges the user account in Ether.

If you want to understand smart contracts, how they get instantiated by users and by other contracts, and especially how they get executed, you need to go in greater detail through various concepts I’ve only touched on so far:

  • Accounts
  • Ether and gas
  • Transaction messages
  • The Ethereum Virtual Machine

I’ll start by telling you more about the various types of accounts.

3.2.1. Accounts

You’ve already come across the concept of accounts a few times. Accounts are available in two types:

  • Externally owned accounts (EOA) (or simply External Accounts)—These are also known informally as user accounts. They’re publicly identifiable from their public key, but they can only be operated by knowing the private key. If you buy some Ether, you’d store it in this type of account. Also, you’d start a transaction against a smart contract from an EOA.
  • Contract accounts—These are the accounts that contracts are executed under. The account address is generated at deployment time, and it identifies the location of the contract in the blockchain.

Both EOAs and contract accounts hold data in the form of a key-value store and an Ether balance. Table 3.1 compares the main properties of EOAs and contract accounts.

Table 3.1. Comparison between an EOA and a Contract Account

Property

Externally owned account

Contract account

Has Ether balance Yes Yes
Can start transaction message Yes No
Can start call message No Yes
Has code No Yes

3.2.2. Ether

I’ve mentioned Ether casually a few times, so it’s probably time you learned more about it. Ether is the cryptocurrency that the Ethereum blockchain supports. Its main purpose is to represent monetary value for services and goods traded over the platform.

Ether is also used to pay for transaction fees. These are, as mentioned in section 3.2 and covered more in section 3.2.3, calculated in a unit called gas, which measures computational resources that a transaction consumes. But these fees are settled in Ether (calculated from the price of a unit of gas, expressed in Ether). Miners charge transaction fees to get compensated for the computational power they provide the network while appending new transaction blocks to the blockchain.

Ether comes in various denominations, which are all defined, as you can see in table 3.2, as a multiple of Wei, the smallest Ether denomination.

Table 3.2. Ether denominations and values in Wei

Unit

Wei value

Wei

Wei 1 Wei 1
Kwei (Babbage) 1e3 Wei 1,000
Mwei (Lovelace) 1e6 Wei 1,000,000
Gwei (Shannon) 1e9 Wei 1,000,000,000
Microether (Szabo) 1e12 Wei 1,000,000,000,000
Milliether (Finney) 1e15 Wei 1,000,000,000,000,000
Ether 1e18 Wei 1,000,000,000,000,000,000

Figure 3.9 summarizes the Ether lifecycle, which goes through the following steps:

  1. Minting Ether
  2. Transferring Ether
  3. Storing Ether
  4. Exchanging Ether
Figure 3.9. The Ether lifecycle. Ether is minted by miner nodes into miner user accounts. Then it’s transferred to EOAs (also known as user accounts). From there, it can be stored on various wallets. Ultimately, it can be converted to real currency, such as USD, EUR, YEN, GBP, and others, through cryptocurrency exchanges.

Minting Ether

If you’re unfamiliar with cryptocurrencies, you must be wondering how Ether is minted and exchanged. Ether is generated through the mining process, during which miners compete to group and append transactions into new blockchain blocks, as I discussed in section 1.1.2. When successful, a miner gets rewarded with a certain number of Ether coins. Blocks are added to the Ethereum blockchain every 15 seconds or so, and the money supply increases accordingly.

Transferring Ether

Once Ether has been generated, it’s allocated to the miner’s external account. Miners can then transfer Ether to other external accounts or contract accounts, either through the Ethereum wallet or programmatically, as you’ll see later.

Exchanging Ether

Because Ether is valuable, it doesn’t generally get transferred for free between accounts. It’s often transferred in return for goods and services traded through smart contracts, but also in return for conventional currency, such as US dollars, euros, pounds, yen, and so on. Although it’s possible to buy Ether from individual owners and pay them an agreed amount of conventional currency, it’s more effective to handle such transactions using cryptocurrency exchanges. Two main types of exchanges are available: centralized, such as Kraken, Coinbase, and Coinsquare, and decentralized, such as EtherEx. Each exchange is generally biased toward a specific real-world currency.

Storing Ether

Once someone acquires Ether, whether through mining, smart contract trading, or exchange-based trading, it’s allocated to an account. You can manage accounts using many methods, each with a different trade-off between convenience and security. The most convenient one is generally through desktop or online wallets, which allow you to transfer Ether easily. The most secure one is through cold or paper storage, which means generating the private key offline and holding it literally on a piece of paper. Hardware wallets present another high-security option and are conceptually similar to paper wallets because they can be considered offline. The main difference is that the account owner stores the private key on a small electronic device similar to a USB key. Table 3.3 summarizes the different options.

Table 3.3. Wallet types and their characteristics

Wallet type

Convenience

Security

Examples

Desktop wallet High High Ethereum wallet, Exodus
Mobile wallet High Low Jaxx
Online wallet High Medium MyEtherWallet, Coinbase, Kraken
Hardware wallet Medium Very high Trezor, Ledger Nano, KeepKey
Paper storage Low Very high EthAddress

I’ve mentioned that transaction fees are charged in Ether but calculated in a unit called gas. Let’s see what gas is and how it’s related to transaction costs.

3.2.3. Gas

Gas is the unit of measure for transaction fees charged on the Ethereum platform. The amount of gas used to complete a transaction depends on the amount of computational resources that the EVM spends while running the transaction. Specifically, it depends on the exact low-level EVM instructions that have been executed during the transaction. Table 3.4 gives an idea of the amount of gas charged for the most common EVM operations.

Table 3.4. Gas cost for simple EVM operations

Operation

EVM op code

Gas cost

Addition, subtraction ADD, SUB 3
Multiplication, division MUL, DIV 5
Comparison LT, GT, SLT, SGT 3
Load word from memory MLOAD 3
Store word to memory MSTORE 3
Load word from storage SLOAD 200
Storing word into storage SSTORE >5000
Contract creation CREATE 32000

The main reason the execution of a transaction is charged in units of gas, and indirectly in units of computational work, is to prevent denial of service (DoS) attacks by unscrupulous participants who might want to disrupt the network. To launch a DoS attack, a malicious participant would have to spam the network with a high number of transactions, each performing a large amount of computational work; for instance, an infinite loop. The amount of gas corresponding to this work would be high, and it would have to be paid in a correspondingly high amount of Ether—it’s unlikely anyone would pay to disrupt a service!

Most smart contract development IDEs give an idea of the total amount of gas required to complete a transaction. For example, in the screenshot in figure 3.10, you can see a gas estimate for the execution of the transfer function of the SimpleCoin contract from the last section of chapter 1, obtained by clicking the Details button on the output panel.

Figure 3.10. Transaction costs for the execution of the SimpleCoin transfer function

Transaction fee costs are calculated according to this formula: transaction fees (in Ether) = number of units of gas consumed * price per unit of gas (in Ether). Let’s break it down:

  • The EVM determines the number of units of gas consumed while running the transaction, and that depends on the computational cost of the code being run during the transaction.
  • The sender of the transaction decides the price of a unit of gas (in Ether). The higher it is, the more likely it is that miners will include the transaction in the block they’re processing. Miners prioritize transactions that are likely to pay high fees, so if a transaction is expected to consume a relatively low amount of gas, the sender will have to set a relatively high gas price to guarantee quick processing.
  • The transaction sender sets a limit for the maximum amount of gas that a transaction should consume. This protects the sender from higher-than-expected transaction costs due to execution of the code in a way different from what was intended; for instance, if the developer introduces a bug that causes an infinite loop. Such limits should be relatively close to the estimated amount of gas needed to complete the transaction.

While a transaction is being executed, the EVM consumes its gas. Two outcomes are possible at the end of the transaction:

  1. The transaction completes successfully. In this case, the unused gas is returned to the sender.
  2. The amount of gas available ends before the completion of the transaction. In this case, the EVM throws an end of gas exception, and the transaction is rolled back.

You might be wondering who pockets the transaction fee. Given either of the two transaction outcomes, the miner who has processed the transaction receives the fee. For the first outcome, they earn the fee by including the transaction in a new block that has been successfully appended to the blockchain. For the second outcome, even though the EVM throws an exception, the miner still charges the gas in Ether, and they collect the related transaction fee as usual. In short, a successful miner is rewarded by minting new Ether and getting transaction fees from the transaction senders. In the early stages of the Ethereum platform, most of a miner’s profits came from minting.

3.2.4. Calls and transactions

Accounts interact with each other through two types of messages: calls and transactions.

Calls

A call is sent through a message that doesn’t get stored on the blockchain and whose execution has the following characteristics:

  • It can only perform read-only operations, which don’t alter the state of the blockchain.
  • It doesn’t consume any gas, and consequently, it’s free.
  • It’s processed synchronously.
  • It immediately returns a return value.
  • It doesn’t allow transferring Ether to the contract account.

Typical calls are direct invocations of contract member variables, including mappings, and invocations of so-called constant functions, which don’t alter contract state. You performed calls, for example, when you checked account balances of SimpleCoin, the basic cryptocurrency you started to build at the end of chapter 1.

Transactions

A transaction, which I introduced to you in the Dapp dynamic view in chapter 1, is sent through a message that gets serialized and stored on the blockchain during the mining process. It contains the following fields:

  • Sender address
  • Recipient address
  • Value—Amount of Ether to be transferred (in Wei), in case the message is being used to transfer Ether (optional)
  • Data—Input parameters, in case the message is being used as a function call (optional)
  • StartGas—Maximum amount of gas to be used for the execution of the message. If this limit is exceeded, the EVM throws an exception and rolls back the state of the message.
  • Digital signature—Proves the identity of the transaction sender
  • GasPrice—The price of a unit of gas (expressed in Ether) the transaction initiator is willing to pay, as discussed in the gas section

You executed transactions when you performed SimpleCoin transfers. The execution of a transaction has the following characteristics:

  • It can perform write operations, which alter the state of the blockchain.
  • It consumes gas, which must be paid for in Ether.
  • It’s processed asynchronously: it gets executed through mining and then gets appended on a new blockchain block, which gets broadcast throughout the network.
  • It immediately returns a transaction ID, but not a return value.
  • It allows transferring Ether to the contract account. (The Ether transfer becomes part of the transaction itself.)

By now you know contracts are executed on the EVM on each node of the Ethereum network. I’ll provide a quick overview of how the EVM works.

3.2.5. The Ethereum Virtual Machine

The Ethereum Virtual Machine (EVM) is a stack-based abstract computing machine, similar in purpose to the Java virtual machine (JVM) and to the .NET Common Language Runtime (CLR). It enables a computer to run an Ethereum application and has two memory areas:

  • Volatile memory, or simply memory. This is a word-addressed byte array, which gets allocated to a contract at every message call. Reads access 256-bit words, whereas writes can be performed on a width of 8 or 256 bits.
  • Storage. This is a key-value store where both key and value have a width of 256 bits. Storage is allocated to each account and is persisted on the blockchain. A contract account can access only its own storage.

EVM opcodes cover operations including Boolean, bitwise, and arithmetic comparisons and jumps (both conditional and unconditional). These are the main opcodes handling contract creation and calls:

  • CREATE—This performs the creation of a new contract instance.
  • CALL—A contract sends a message to itself or other contracts through this operator.
  • DELEGATECALL—This operator allows the calling contract to send a message to an external contract but execute the related code in the context of the caller. This operator is especially useful for the creation of libraries of shared code that multiple contracts can access.

The EVM is completely sandboxed: a contract can’t access network or filesystem resources. It can only access other contracts. A more in-depth explanation of the EVM is outside the scope of this book. The best reference for understanding its design is Gavin Wood’s so-called Yellow Paper: http://gavwood.com/paper.pdf.

At this point, you’ve consolidated your knowledge on smart contracts. Now it’s time to take a step further and connect to the Ethereum network through a proper client: the Go Ethereum client.

3.3. Connecting to Ethereum with geth

Before you start installing a client, I’d like to give you a more detailed overview of the Ethereum network, which I started introducing in chapter 1. It’ll help you understand the wider context that a client fits in.

You already know the Ethereum network is a peer-to-peer (P2P) network, which means there’s no central master or server node coordinating them. Consequently, all nodes are clients to each other. Nodes are designed to work and communicate with each other in exactly the same way, according to a predefined protocol called Wire, described in the Yellow Paper. This means all nodes must be able to append new transaction blocks to the blockchain (if mining is activated) and verify them while blocks get propagated throughout the network.

From an implementation point of view, the network contains two broad categories of nodes:

  • Miners—They process the latest transactions and consolidate them into the blockchain in exchange for transaction fees and a mining reward (in Ether) if they manage to execute the consensus algorithm successfully. In that case, they propagate the blocks they’ve consolidated onto the blockchain to other peers of the network. Because these nodes generate new blocks, they’re considered producers (although they’re technically also still consumers).
  • Full nodes—They mainly verify the validity of the blocks they’ve received from neighboring peers and keep propagating them to the rest of the network. Therefore, they’re considered consumers.

Mining nodes run on clients optimized for processing transactions, generating blocks, and executing the Proof of Work algorithm efficiently, to get rewarded relatively frequently. Mining implementations, such as ethminer, have been written in C++ and use GPU libraries such as NVIDIA’s CUDA. Consequently, they run on GPU hardware that can deliver superior performance.

On the other hand, full nodes don’t have performance requirements, so standard clients have been implemented in various languages. Table 3.5 summarizes the main client implementations available to date, ordered by popularity, as reported in Ethernodes (https://ethernodes.org/network/1).

Table 3.5. Ethereum client implementations by language

Client

Language

Go Ethereum (geth) Go
Parity Rust
Cpp-ethereum (eth) C++
Ethereum(J) Java
Pyethapp Python
ethereumjs-lib JavaScript
ruby-ethereum Ruby
ethereumH Haskell

Each client comes with a console, and some of them also include a graphical browser or a wallet. While working with this book, you’ll use Go Ethereum, also known as geth, which is the most popular client, installed on over 70% of the network nodes.

3.3.1. Getting started with geth

The download page for the Go Ethereum website, https://ethereum.github.io/go-ethereum/downloads/, shows releases for all major operating systems: Android, iOS, Linux, MacOS, and Windows. Various installation formats are available for some of the supported operating systems. For example, for Windows, you can choose between the 32- and 64-bit version and whether to download only the executable (Archive option) or the full installer (Installer option). I’ve picked the 64-bit Geth & Tools 1.8.13 archive.

Once you’ve installed or uncompressed the relevant file, you can run the geth executable. If you have the Ethereum wallet open, close it before starting geth, because they use the same port number! If you run geth with no parameters, it’ll start to synchronize in Full mode with the public production network, also known as MAINNET, as shown in the screenshot in figure 3.11.

Figure 3.11. geth synchronizing with the MAINNET network at startup

After geth has synchronized the full blockchain (this could take from hours to days, depending on your hardware and internet connection), the console will start to slow down and show blocks being added to the blockchain in real time.

Note

As for the wallet, you can synchronize geth in Light or Fast mode—for example, C:program filesgeth>geth –-syncmode "light"—if you prefer to get up and running more quickly (in minutes as opposed to hours or even days) and don’t mind not having downloaded the full blockchain locally.

You can interact with geth in two ways:

  • Through the user-friendly geth interactive JavaScript console
  • Through low-level JSON-RPC calls over HTTP

I’ll present both techniques to you. Let’s start with the simpler tool: the interactive JavaScript console.

3.3.2. A first look at the geth interactive console

geth comes with an interactive console that accepts JavaScript instructions. It implicitly references Web3.js, a JavaScript implementation of Web3, the official high-level library for interacting with Ethereum clients. This console is similar in purpose to read-eval-print loop (REPL) consoles for programming language IDEs. I’ll cover Web3 extensively in the next few chapters. For the moment, let’s get a quick feel for it.

First, open the interactive console. You’ve got two possible ways to start it up:

  • If no geth clients are running on the same machine, run the geth executable with the console command:
    C:program filesgeth> geth console 
  • If a geth client is already running on the machine, attach to a running geth process with the attach command:
    C:program filesgeth> geth attach ipc:\.pipegeth.ipc

You have a running geth process, so you’ll go for the second option.

Note

In this book, I’m assuming you use Windows, as over 60% of the nodes of the Ethereum network run on this operating system. Consequently, I’ll show shell commands with a Windows command prompt format. Also note that after successful execution of instructions in the console, you might see undefined right before or after the correct results. You can ignore it.

Displaying version information

First of all, you can query the console for version information. A Web3 object named web3 is implicitly instantiated when opening the console, so you can access version information in this way by typing

> web3.version

and you’ll see something like

{
  api: "0.20.1",
  ethereum: "0x3f",
  network: "1",
  node: "Geth/v1.8.13-stable-225171a4/windows-amd64/go1.10.3",
  ...

As you can see, the version property is an object that contains many subproperties. If you want, you can be specific and query an individual property of the version object:

> web3.version.api

and you’ll see something like

"0.20.1"

Because the console accepts JavaScript instructions, it’s possible to assign the values of Web3 properties and subproperties to variables and then display them through the console object:

> var apiVersion = web3.version.api
> var nodeVersion = web3.version.node
> console.log('Api version: ' + apiVersion)
> console.log('Node version: ' + nodeVersion)
Checking connectivity

You can get some client connectivity information from the web3.net object. (You can omit the web3 namespace because it’s implicitly referenced.) If you type

> net

you’ll see something like

{
  listening: true,
  peerCount: 2,
  version: "3",
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}

As for the version object, you can directly access individual properties of the net object as follows:

> console.log('this geth instance is listening for network connections : ' +
     web3.net.listening)
> console.log('number of peers connected to this geth instance: ' +
     web3.net.peerCount)

If you want to get more detailed information about your node, you can use the web3.admin object and call

> admin.nodeInfo

and you’ll see something like

{
  enode: "enode://90946319e42ef4d4670c1d7...,
  id: "90946319e42ef4d467...,
  ip: "::",
  listenAddr: "[::]:30303",
  name: "Geth/v1.8.13-stable-225171a4/windows-amd64/go1.10.3",
  ...

The peers property gives you detailed information about the peers you’re connected to:

> admin.peers

will yield something like

 [{
    caps: ["eth/62", "eth/63"],
    id: "0b64924d478abaf6900ffe...,
    name: "Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1",
    network: {
      localAddress: "192.168.1.108:53557",
      remoteAddress: "136.144.129.222:30303"
    },
...
Accessing the blockchain

The web3.eth object retrieves real-time information about the client and the blockchain. Look at the console of the geth process currently running. You should see how new blocks are getting appended to the blockchain in real time. Take note of the block number of a recently appended block, and then switch back to the JavaScript console.

You can get the most recent block number through the eth.blockNumber property:

> var latestBlockNum = eth.blockNumber
> console.log('Latest block #: ' + latestBlockNumber)

Then you can display summary information about this block by calling

> eth.getBlock(latestBlockNum)

and you’ll see something like

{
  difficulty: 64344784,
  extraData: "0xd7830106078467657...,
  gasLimit: 4723091,
  gasUsed: 262264,
  hash: "0x8196edb66315b460f0bd4b9bdfa884...,
  nonce: "0x2ac78a350ec95787",
  number: 1732206,
...

You also can drill down at transaction level. You can get the first transaction stored in the latest block in this way:

> eth.getTransactionFromBlock(latestBlockNum, 0)

You’ll see something like

{
  blockHash: "0x8196edb66315b460f0bd4b9bdfa88...,
  blockNumber: 1732206,

  from: "0x392fd4954de442bb6c4d57f1923b4708642d3408",
  gas: 210000,
  gasPrice: 120000000000,
  hash: "0x4eb5ae8d7b7919f92d1dd02fcc407d6...",
...

I encourage you to have a look at the content of the whole eth object:

> eth
Performing Ether conversions

The Web3 API offers some useful functions to convert any Ether denomination from/to Wei. You can convert a Wei amount to a specific denomination:

> var amountInWei = 12000000
> var amountInSzabo = web3.fromWei(amountInWei, 'szabo')
> console.log(amountInWei + ' Wei is equivalent to '  + amountInSzabo + '
     szabo')
12000000 Wei is equivalent to 0.000012 szabo

And you can convert a specific denomination into Wei:

> var amountInEther = 12
> var amountInWei = web3.toWei(amountInEther, 'Ether')
> console.log(amountInEther + ' Ether is equivalent to '  + amountInWei + '
      Wei')
12 Ether is equivalent to 12000000000000000000 Wei

3.3.3. A first look at JSON-RPC

Now that you’ve learned the basics of the JavaScript console, you can try to interact with geth by performing a few JSON-RPC calls. geth offers a remote procedure call (RPC) interface that allows you to access node functionality and blockchain data to a much finer degree of control than that offered by the Web3 API. In fact, Web3 is built on top of the RPC layer, which is the lowest level API exposed by the Ethereum platform, as shown in figure 3.12.

Figure 3.12. Comparison between accessing geth through Web3.js and JSON-RPC

The RPC interface has been designed against the JSON-RPC 2.0 standard, and consequently it sends and receives data in JSON format. You can find more information on JSON-RPC in the sidebar.

If you want to communicate with geth directly through JSON-RPC, you have to do two things:

  1. Stop any instance of geth running in a standard operating system command shell or in a geth console.
  2. Start geth in RPC mode using the --rpc and --rpcapi options:
    C:program filesgeth>geth --rpc --rpcapi "eth,net,web3,personal"

When you launch geth in RPC mode, it’s accessible through an HTTP server that accepts HTTP requests, by default on

http://localhost:8545
JSON-RPC

JSON-RPC is a lightweight remote procedure call that uses JSON as a data format.

You invoke an RPC call by sending a request object to a server, typically over HTTP, or in any other way, such as socket or even messaging, because the transport layer isn’t part of the protocol.

The request object must contain the following members:

  • jsonrpc—This sets the protocol version, currently 2.0.
  • method—Name of the remote procedure to be called.
  • params—Array with procedure parameters.
  • id—A call identifier, typically a string or integer. It must be not null.

After the server processes the call, it replies with a response object, which contains the following members:

  • jsonrpc—This sets the protocol version, currently 2.0.
  • result—This field is present if the response is successful; it isn’t included if errors occur.
  • error—This field is present if errors occur; it isn’t included if the response is successful.
  • id—Same as specified in the request.

You’ll perform JSON-RPC calls to geth’s HTTP server using the cURL console command. To help you appreciate the differences between the Web3 API and the JSON-RPC API, I’ll show you how to execute in cURL the same operations you performed in Web3 through the interactive console.

Note

cURL is available in most operating systems, including Windows (version 7 and 10) and Linux. Alternatively, you can either download from the internet an open source version of cURL or perform HTTP requests through a graphical tool such as Postman, if you prefer.

Displaying version information

You can retrieve version information about the geth client with this call:

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":2
3} http://localhost:8545

{"jsonrpc":"2.0","id":23,"result":"Geth/v1.6.5-stable-cf87713d/windows-
amd64/go1.8.3"}

(If you’re using Windows, you must escape JSON double quotes, as explained in the sidebar.) The result is equivalent to what you got from web3.version.node.

cURL JSON escaping on Windows

cURL operations must escape the double-quote symbol " with " in the JSON POST data, in certain versions of Windows. For example, in a command shell in Windows, you perform the request this way:

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"i
d":23} http://localhost:8545

And in Linux:

$curl -H "Content-Type: application/json" -X POST --data
'{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":23}'
http://localhost:8545
Checking client connectivity

You can get connectivity information by performing several calls. For instance, to check whether the client is actively listening for network connection, you must execute this request:

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"net_listening","params":[],"id":23}
http://localhost:8545

And you’ll get

{"jsonrpc":"2.0","id":23,"result":true}

The result is equivalent to web3.net.listening.

To get the number of peers connected to the client, you must execute this call:

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":23}
http://localhost:8545

And you’ll get

{"jsonrpc":"2.0","id":23,"result":"0x6"}

The result, which contains numbers encoded in hexadecimal format, as explained in the sidebar, is equivalent to web3.net.peerCount.

Numbers through JSON-RPC

Ethereum’s JSON-RPC interface handles numbers differently than the official JSON-RPC 2.0 specification does. Numbers sent and returned through JSON-RPC must be encoded in hexadecimal format. Doing so makes sure each client implementation parses and processes large numbers appropriately, independent of the support for large numbers that the underlying language in which the client has been coded provides.

Hexadecimal encoding should include a 0x prefix and at least one valid digit with no leading zeros, as shown here:

0x4d2            1

  • 1 This is equivalent to 1234 in decimal.

Here are some examples of how numbers should be encoded into hexadecimal format:

Decimal format

Hexadecimal format

0 0x0
9 0x9
1234 0x4d2

And here are some examples of incorrectly encoded numbers:

Incorrect hex encoding

Reason

0x No digit has been specified after the 0x prefix.
42d No 0x prefix has been specified.
0x042d Leading 0 digits aren’t allowed.
Accessing the blockchain

You can get the latest blockchain block number this way:

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":23}
http://localhost:8545

And you’ll get

{"jsonrpc":"2.0","id":23,"result":"0x1a705d"}

Once you have the latest block number, you can inspect it by calling (replacing the block number in params with the one from your result):

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1a70
5d",true],"id":23} http://localhost:8545

And you’ll get

{"jsonrpc":"2.0","id":23,"result":{"difficulty":"0x3e37031","extraData":"0xd6
      83010700846765746885676...","gasLimit":"0x47e7c4","gasUsed":"0x323db6","
      hash":"0x0d6ae4b07a731834f5ca0d18859...",...
"miner":"0x22d1d502356c1c2d...","nonce":"0x3b886846920d3c81","number":"0x1a70
      5d","parentHash":"0x90fbbacbf8945fb8d4..."
...

Then you can inspect the first transaction of the block you retrieved in a way equivalent to how you did in Web3 through the interactive console (again, putting the block number you got in results into params):

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"eth_getTransactionByBlockNumberAndIndex",
"params":["0x1a705d","0x0"],"id":23} http://localhost:8545

And you’ll get

{"jsonrpc":"2.0","id":23,"result":{"blockHash":"0x0d6ae4b07a731834f5ca0d1885.
..","blockNumber":"0x1a705d","from":"0xcaf4a30e5fef5c0a...","gas":"0x47b760",
"gasPrice":"0x1bf08eb000","hash":"0x9acf62392d266086ec8..."
...

The result object is similar to that returned by the Web3 eth.getTransactionFromBlock call.

In the rest of the book, you’ll be interacting with geth mainly through Web3.js, but occasionally I’ll show you how to perform equivalent operations in JSON-RPC. If you’re interested in learning more about the JSON-RPC API, consult its wiki at https://github.com/ethereum/wiki/wiki/JSON-RPC.

3.3.4. Mining with the geth console

You can’t consider a section on Ethereum clients to be complete before at least mentioning how to perform mining through a client. You already performed some mining through the Ethereum wallet at the beginning of this chapter, to load your test accounts with Ether.

As you can imagine, performing operations through the wallet hides what happens under the hood. For example, have you asked yourself why the Ether you mined got assigned to account1? That happened because the etherbase account, which is the account associated with the miner thread, is set by default to eth.accounts[0]. But after restarting geth and reopening the geth console in attach mode, as you did previously (in case you shut it down), you can reconfigure the etherbase account to eth.accounts[1], if you prefer, through the implicitly instantiated miner object, as follows:

C:program filesgeth> geth attach ipc:\.pipegeth.ipc

> miner.setEtherbase(eth.accounts[1])

Regardless of whether your etherbase account is eth.accounts[0] or you’ve reconfigured it to eth.accounts[1], you can start mining as follows:

> miner.start()

At this point, the CPU of your machine will go to nearly 100%. Then you can stop mining:

> miner.stop()

In the unlikely event you’ve mined some Ether, this will now be assigned to your eth.accounts[1], or to eth.accounts[0] if you decided not to reconfigure it.

When you kicked off mining on the geth interactive window with miner.start(), you might have noticed output similar to the following:

INFO [09-29|18:08:23] Imported new chain segment               blocks=1
     txs=20  mgas=4.401   elapsed=25.066ms  mgasps=175.592 number=1732751
     hash=fa5a62...050eb5
INFO [09-29|18:08:25] Updated mining threads                   threads=0
INFO [09-29|18:08:25] Transaction pool price threshold updated
     price=18000000000
INFO [09-29|18:08:25] Starting mining operation
INFO [09-29|18:08:25] Commit new mining work                   number=1732752
     txs=5   uncles=0 elapsed=7.017ms
INFO [09-29|18:08:27] Generating DAG in progress               epoch=57
     percentage=0 elapsed=922.455ms
INFO [09-29|18:08:28] Generating DAG in progress               epoch=57
     percentage=1 elapsed=1.846s
INFO [09-29|18:08:29] Generating DAG in progress               epoch=57
     percentage=2 elapsed=2.772s

INFO [09-29|18:08:30] Generating DAG in progress               epoch=57
     percentage=3 elapsed=3.753s
INFO [09-29|18:08:31] Imported new chain segment               blocks=1
     txs=0   mgas=0.000   elapsed=6.016ms   mgasps=0.000   number=1732752
     hash=c98db8...2d044c
INFO [09-29|18:08:31] Commit new mining work                   number=1732753
     txs=6   uncles=0 elapsed=22.058ms
INFO [09-29|18:08:31] Generating DAG in progress               epoch=57
     percentage=4 elapsed=4.724s
INFO [09-29|18:08:31] Imported new chain segment               blocks=1
     txs=5   mgas=3.693   elapsed=21.056ms  mgasps=175.370 number=1732752
     hash=f4432f...8bae81

You might wonder what DAG is and why it takes such a long time to compute. DAG stands for directed acyclic graph, and it’s the data structure underlying Ethash, the Proof of Work (PoW) algorithm for mining on the Ethereum platform. DAG requires a relatively high amount of memory, so Ethash is considered a memory-intensive PoW algorithm. It consequently discourages mining through application-specific integrated circuit (ASIC) hardware, which is effective only for CPU-intensive PoW algorithms, such as the one used on the Bitcoin network. The Ethash algorithm encourages mining instead through commodity hardware, such as a GPU chipset (explained more in sidebar).

Mining is a specialized topic outside the scope of this book. If you’re interested in learning more about Ethash, I encourage you to consult the official notes at http://mng.bz/WaOw.

Now that you’ve experienced mining firsthand, you might ask yourself what happens if you have the luck to append a new block to the blockchain, get the related Ether reward in your etherbase account, and then decide to quit your mining activity by shutting down your node. Would the block you’ve created and appended to the blockchain still be valid, even if you’ve disappeared from the network? Would the transactions included in the block still be valid? Would you still be able to transfer the Ether in your etherbase account to another account?

The answer to all these questions is yes. Remember that the blockchain validation process, performed continuously by all active full nodes, only cares about the cryptographic consistency between a block hash and the public address of the miner who has generated the block, in the same way it cares about the consistency between a transaction hash and the public address of the account that has generated it. So whether the node that created a new block is active or inactive is as irrelevant to the block (and transaction) history as whether your computer is on or off after having transferred some Ether from an account of your desktop Ethereum wallet to another account.

GPU mining

If you want to try your luck and hope to get rich by generating Ether on the public production network with CPU mining, as you’ve done so far in the test network, I hate to break the news, but you’re more likely to get rich by winning the lottery. As you saw in chapter 1, the execution of the PoW algorithm is successful only if the hash obtained combining the block information and a nonce has certain characteristics—for example, a high number of leading zeros. PoW algorithms are designed so that you must try millions of nonce values before hitting the lucky one that generates a valid hash. Consequently, mining successfully means being able to generate more hashes per second than other miners.

With the best CPU chipset, you’ll be able to generate at most 1 megahash per second (Mh/s), where megahash means one million hashes. With good GPU chipsets, you might be able to generate up to 30 Mh/s—nearly 30 times the hashing capability of a standard CPU. Also consider that mining pools, which are organizations that pool various GPU miners together so they can share resources and rewards, can generate up to 30 Th/s (30 trillion hashes per second), which means up to 30 million times what a CPU is able to generate during the same time. Finally, consider that in the Ethereum space, around 40 mining pools have a hash rate ranging between 30 Gh/s and 30 Th/s.

Now you can understand why your chances of generating Ether using a CPU alone are slim. You might find this stark reality disappointing, and you might even think that the huge influence of mining pools on the mining process might bring into question Ethereum’s credibility, as far as decentralization is concerned. Many Ethereum participants believe that as long as many mining pools are competing, decentralization should be guaranteed. Also consider that the new consensus algorithm being implemented, Stake of Work, introduced in the previous chapter, might change completely how power is concentrated (or hopefully spread) in the Ethereum network. Here’s a quick summary of the hash rate that different hardware can achieve:

Hardware

Hashrate

Single CPU 1 Mh/s
Single GPU 30 Mh/s
GPU rig (10xGPUs) 300 Mh/s
Mining pool 30,000,000 Mh/s

3.3.5. Other clients

Although Go Ethereum is the most popular client, other implementations offer various benefits with respect to geth:

  • Parity, written in Rust, is the second most popular Ethereum client, and it’s regarded as the fastest, lightest, and most secure implementation. It comes with a console and a built-in wallet.
  • cpp-ethereum, written in C++ and known as eth, is another fast implementation, third in popularity, and well regarded for its portability. Ethminer, a specialized mining client, is a fork from cpp-ethereum.
  • pyethapp, written in Python, is built on two core components: pyethereum provides EVM, blockchain, and mining functionality, whereas pydevp2p supports access to the P2P network and node discovery mechanisms. Python developers especially appreciate this implementation for its extensibility.

You’ve learned about various components and tools of the Ethereum platform. Before leaving this chapter, you’ll reinforce your understanding of accounts, a key concept you must get familiar with to work effectively with Ethereum.

3.4. Managing accounts with geth

At the beginning of this chapter, while covering smart contracts, I touched briefly on accounts. I also helped you create some accounts through the Ethereum wallet UI so you could use them to transfer some Ether around. Armed with the geth console, you can now deepen your knowledge of accounts by creating them and interacting with them programmatically.

3.4.1. Ethereum accounts

As you know, the Ethereum platform supports two types of accounts:

  • Externally owned accounts (EOAs)—These impersonate end users, as well as miners and autonomous agents.
  • Contract accounts—These impersonate contracts.

For the rest of this chapter, we’ll deal only with EOAs, which I’ll call accounts.

As with most blockchain systems, the security of the Ethereum platform is based on public key cryptography. An account is therefore identified by a private/public key pair. The account’s address is represented by the last 20 bytes of the public key.

The private/public key pair associated with an account is stored in a text keyfile. The public key is visible in plain text, whereas the private key is encrypted with the password introduced at account creation. Account keyfiles are in the keystore folder within the Ethereum node’s data directory:

  • Windows: C:Usersusername\%appdata%RoamingEthereumkeystore
  • Linux: ~/.ethereum/keystore
  • Mac: ~/Library/Ethereum/keystore
Tip

It’s strongly recommended that you back up the keystore folder on a regular basis and keep a copy of the passwords you’ve introduced when creating each account in a secure place. Sorry if I keep pestering you with this, but if you haven't noticed, I do want to make a point of how sensitive key and password details are in the blockchain world!

Account portability

You can’t use an account that you’ve created on the public production network on a test network, for example Ropsten, and vice versa. This is because the keystore of each network is different and is located in a separate folder within the Ethereum folder:

  • Main prod network keystore: ~/.ethereum/keystore
  • Rinkeby test network keystore: ~/.ethereum/rinkeby/keystore
  • Ropsten test network keystore: ~/.ethereum/testnet/keystore

You can create accounts and interact with them through four different avenues:

  • The Ethereum wallet, as you saw earlier in this chapter
  • geth commands
  • Web3 on the geth console
  • JSON-RPC calls

You’ve already seen how to manage accounts with the Ethereum wallet. In the next several sections, you’ll manage accounts through geth commands and the geth console. You’ll also get a quick feel for how to perform some operations on accounts through the JSON-RPC API.

3.4.2. Managing accounts with the geth command

You can manage an account easily through your operating system console by entering specific geth commands from the directory of the geth executable (or from any directory if geth is in your PATH global variable).

Creating a new account

You can create a new account manually or using a plain text file:

  1. Manual creation

    1. To create a new account, enter
      C:program filesgeth>geth account new 
    2. You’ll be prompted to enter a password twice, and then you’ll be shown the address of the account you created:
      Your new account is locked with a password. Please give a password.
        Do not forget this password.
      Passphrase:
      Repeat passphrase:
      Address: {47e3d3948f46144afa7df2c1aa67f6b1b1e35cf1}
    Tip

    Get into the habit of choosing strong passwords or generating them through a strong password generator. I’m repeating myself; I know, I know! But this is important, believe me!

  2. Text file creation

    1. To avoid having to enter the password manually, you can store it in plain text in a text file.
    2. Execute the geth account command as follows:
      C:program filesgeth>geth --password passworddirectory/passwordfile
         account new 
Tip

As you can understand, although placing a password in a plaintext file might be acceptable in a test environment, this way of creating an account might pose much greater risks in a production environment, where you must make sure access to the password file is tightly restricted.

Listing accounts

Once you’ve created an account, you can verify it’s indeed present in your node by executing the following command:

C:program filesgeth>geth account list 

You’ll see the accounts you created through the geth account command and the geth console:

Account #0: {edde06bc0e45645e2f105972bdefc220ed37ae10}
     keystore://C:Users
oberAppDataRoamingEthereumkeystoreUTC--2017-
     06-24T08-49-46.377533700Z--edde06bc0e45645e2f105972bdefc220ed37ae10
Account #1: {4e6c30154768b6bc3da693b1b28c6bd14302b578}
     keystore://C:Users
oberAppDataRoamingEthereumkeystoreUTC--2017-
     06-24T13-26-18.696630000Z--4e6c30154768b6bc3da693b1b28c6bd14302b578
Account #2: {70e36be8ab8f6cf66c0c953cf9c63ab63f3fef02}
     keystore://C:Users
oberAppDataRoamingEthereumkeystoreUTC--2017-
     06-24T18-21-36.890638200Z--70e36be8ab8f6cf66c0c953cf9c63ab63f3fef02
Account #3: {c99048e9b98d3fcf8b5f0d5644794b562f9a2ea4}
     keystore://C:Users
oberAppDataRoamingEthereumkeystoreUTC--2017-
     06-24T18-21-47.794428600Z--c99048e9b98d3fcf8b5f0d5644794b562f9a2ea4
...
Updating accounts

After geth creates and saves an account in a keyfile in the keystore folder, a subsequent geth release might implement a new keyfile format. In that case, it becomes necessary to update the account. Another reason you might want to update an account is because you want to change the password.

You can update account 47e3d3948f46144afa7df2c1aa67f6b1b1e35cf1 you created earlier with the following geth command (obviously replace with your account number):

C:program filesgeth>geth account update
     47e3d3948f46144afa7df2c1aa67f6b1b1e35cf1

You’ll be prompted to enter the existing password, to unlock the account, and subsequently a new password, which you’ll have to type twice, as usual. You’ll then be shown the new address of the account:

Unlocking account 47e3d3948f46144afa7df2c1aa67f6b1b1e35cf1 | Attempt 1/3
Passphrase:
INFO [09-30|08:36:25] Unlocked account
     address=0x47e3d3948f46144afa7df2c1aa67f6b1b1e35cf1
Please give a new password. Do not forget this password.
Passphrase:
Repeat passphrase:

The geth account update command offers the same --password option that the geth account new command provides. But in this case you can also use it to unlock the account for the purpose of converting it into a new keyfile format.

3.4.3. Managing accounts with Web3 on the geth console

Let’s repeat some of the earlier account management operations through the interactive console.

Creating a new account

Go back to the interactive geth console. You can create accounts using the web3.personal object:

> personal.newAccount()

As for the geth account command, you’ll be asked to enter a password twice, and then you’ll be shown the account address:

Passphrase:
Repeat passphrase:
"0x70ff99d4bc8054b2e09269bcbfdddf8e1ae7d155"
Listing accounts

You can list accounts with the interactive console by displaying the value of the account property of the web3.eth object. You’ll get the same result set you obtained with the geth account list command:

> eth.accounts

will yield something like

["0xedde06bc0e45645e2f105972bdefc220ed37ae10",
     "0x4e6c30154768b6bc3da693b1b28c6bd14302b578",
     "0x70e36be8ab8f6cf66c0c953cf9c63ab63f3fef02",
     "0xc99048e9b98d3fcf8b5f0d5644794b562f9a2ea4", 
...

You also can directly reference a specific account of the eth.accounts array:

> eth.accounts[0]

This will yield something like

"0xedde06bc0e45645e2f105972bdefc220ed37ae10"
Checking an account’s Ether balance

You can check the amount of Ether stored in an account using the following call, which returns it in Wei:

> var balanceInWei = eth.getBalance(
"0x407d73d8a49eeb85d32cf465507dd71d507100c1")

Then you can convert it to Ether as usual:

> var balanceInEther = web3.fromWei(balanceInWei, "Ether")
Transferring Ether between accounts

You can try transferring 0.0025 Ether from accounts[1] to accounts[2]. First of all, check the current balances of these accounts, as you saw earlier:

> var balanceAcc1 = eth.getBalance(eth.accounts[1]);
> var balanceAcc2 = eth.getBalance(eth.accounts[2]);
> console.log('Balance account 1: ' + balanceAcc1 + '; Balance account 2: ' +
     balanceAcc2);
Balance account 1: 1938331059000000000; Balance account 2:
     1000741600000000000

Before transferring Ether from a certain account, for example accounts[1], you must unlock it:

> personal.unlockAccount(eth.accounts[1]);

As usual, you’ll be asked to enter the password associated with this account:

Unlock account 0x4e6c30154768b6bc3da693b1b28c6bd14302b578
Passphrase:
true

Then, you can transfer Ether between accounts with the web3.eth.sendTransaction function, which takes an amount in Wei, as follows:

> var sender = eth.accounts[1];
> var recipient = eth.accounts[2];
> var amount = web3.toWei(0.0025, "Ether");
> eth.sendTransaction({from:sender, to:recipient, value: amount});
"0xf1c342c668bcd1d59f3e95cfaf08acc6d7cda8adae02da05ceb76c8c3c137eef"

The value returned is the hash of the transaction sent.

After a couple of minutes, recheck the balances:

> console.log('Balance account 1: ' + eth.getBalance(eth.accounts[1]) + ';
      Balance account 2: ' + eth.getBalance(eth.accounts[2]));
Balance account 1: 1933311059000000000; Balance account 2:
     1003241600000000000

If the balance hasn’t been updated yet, it’s because the transaction hasn’t been mined yet.

3.4.4. Managing accounts with JSON-RPC

I’ll give you a quick example of how to perform account management operations in JSON-RPC. Open a new OS shell and you can list your accounts with the following JSON-RPC call:

C:>curl -H "Content-Type: application/json" -X POST --data
{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":23}
http://localhost:8545

This will yield something like

{"jsonrpc":"2.0","id":23,"result":["0xedde06bc0e45645e2f105972bdefc220ed37ae1
0","0x4e6c30154768b6bc3da693b1b28c6bd14302b578","0x70e36be8ab8f6cf66c0c953cf9
c63ab63f3fef02","0xc99048e9b98d3fcf8b5f0d5644794b562f9a2ea4",...

3.5. Revisiting SimpleCoin’s contract

We’ve covered quite a lot of ground in this chapter. If you’ve followed me up to this point, congratulations: you’ve completed the introduction to Ethereum covering the Ethereum wallet and the Go Ethereum client. You’ve also started interacting with the platform in many ways—through the geth commands, through Web3 instructions on the geth interactive console, and through direct JSON-RPC requests.

It’s been an intense ride. I bet you’re eager to get back to some coding! Let’s revisit your initial implementation of SimpleCoin, the basic cryptocurrency I introduced at the end of chapter 1, and try to improve it.

Reenter the SimpleCoin code you saw in the previous chapter into Remix (http://remix.ethereum.org), as shown in the following listing. As usual, ignore warnings for the moment: they’ll disappear as you improve the code in the next chapters.

Listing 3.1. SimpleCoin contract as you left it in chapter 1
pragma solidity ^0.4.0;   

contract SimpleCoin {   

  mapping (address => uint256) public coinBalance; 
 
  constructor() public { 
    coinBalance[0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C] = 10000;   
  }
 

  function transfer(address _to, uint256 _amount) public { 
    coinBalance[msg.sender] -= _amount;
    coinBalance[_to] += _amount;
  }
}

This code is rudimentary. Even if you don’t know the Solidity language yet, you can see a hardcoded value in the constructor and a lack of input validation in the transfer function. You can improve the code in several ways. First of all, you can parameterize the constructor so the initial money supply doesn’t get allocated to the address of an arbitrary test account, but to the address of the contract owner’s account. Then you can introduce some checks in the transfer function to prevent incorrect transfers. Finally, you can set things up so that when tokens get transferred, an event can be raised, and then clients of the smart contract can be notified or react to it.

3.5.1. Improving SimpleCoin’s contract

You’ll improve both the constructor and the transfer function. You can start from the constructor.

Parameterizing the constructor

Rewrite the constructor as follows:

  constructor(uint256 _initialSupply) public {
    coinBalance[msg.sender] = _initialSupply;   
}

You’ve already come across the special property msg.sender, whose value is the address of the message sender (or function caller). When it comes to the constructor, the message sender is the account that instantiates the contract, which consequently becomes its owner. As a result, when the constructor gets called, the amount of tokens specified in the _initialSupply parameter gets allocated to the contract owner.

Making transfers more robust

Rewrite the transfer function as shown in the following listing.

Listing 3.2. A more robust transfer function with checks on the input
  function transfer(address _to, uint256 _amount) {
    require(coinBalance[msg.sender] >= _amount);      1
    require(coinBalance[_to] + _amount >= 
       coinBalance[_to]);                             2
    coinBalance[msg.sender] -= _amount;  
    coinBalance[_to] += _amount;         
}

  • 1 Checks that the sender account has an amount of coins equal to or larger than what you’re trying to transfer
  • 2 Checks that an arithmetic overflow hasn’t been produced on the recipient’s balance during the transfer operation. (This can happen if the balance, because of the amount received from the sender, becomes bigger than uint256.)

The require special function throws an exception if the condition isn’t met. You can also throw the exception directly with the throw keyword, but this way of validating input is being deprecated. For example

require(coinBalance[msg.sender] > _amount);

could have been previously written as

if (coinBalance[msg.sender] < _amount) throw;
Raising an event

A contract can declare one or more events that can be raised in any of its functions. A client that’s monitoring the state of a contract can handle an event. For instance, you can declare an event that notifies that a transfer of SimpleCoin tokens has taken place:

event Transfer(address indexed from, address indexed to, uint256 value);

You’ll raise this event at the bottom of the transfer function:

    function transfer(address _to, uint256 _amount) {
        ...


        emit Transfer(msg.sender, _to, _amount);  
    }

3.5.2. Trying out the amended code

The amended SimpleCoin contract will now look like the following listing.

Listing 3.3. SimpleCoin with parameterized constructor, input validation, and event
pragma solidity ^0.4.0;

contract SimpleCoin {
    mapping (address => uint256) public coinBalance;
    
    event Transfer(address indexed from, address indexed to, uint256 value);

    constructor(uint256 _initialSupply) public {
        coinBalance[msg.sender] = _initialSupply;   
    }

    function transfer(address _to, uint256 _amount) public {
        require(coinBalance[msg.sender] > _amount);
        require(coinBalance[_to] + _amount >= coinBalance[_to] );
        coinBalance[msg.sender] -= _amount;  
        coinBalance[_to] += _amount;   
        emit Transfer(msg.sender, _to, _amount);  
    }
}
Trying out the amended constructor

Reopen Remix if you closed it, and copy the code in listing 3.3 into the editor. Then pick a test account address from the Transaction Origin drop-down list; for example, 0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db. This will be the account executing the constructor, and it’ll consequently become the contract owner.

Click the Run tab on the right panel. You can now enter the initial supply of SimpleCoin tokens next to the Deploy button, say 10,000, and then click Deploy. As usual, the coinBalance and transfer buttons will appear on the lower part of the screen, as in the previous chapter, as shown in the screenshot in figure 3.13.

Figure 3.13. The Deploy operation now accepts the constructor input. After you instantiate the contract by clicking Deploy, the CoinBalance and Transfer buttons appear.

You can check the contract owner’s address balance in the coinBalance mapping. As expected, you’ll get 10,000. You can also double-check that the balances of the other addresses are zero, as shown in table 3.6.

Table 3.6. The balances of the SimpleCoin accounts

Account address

Account balance

0xca35b7d915458ef540ade6068dfe2f44e8fa733c 0
0x14723a09acff6d2a60dcdf7aa4aff308fddc160c 0
0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db 10,000
0x583031d1113ad414f02576bd6afabfb302140225 0
0xdd870fa1b7c4700f2bd7f44238821c26f7392148 0
Trying out the amended transfer function

Try to transfer some SimpleCoin tokens from an account that doesn’t have any; for example, 0x583031d1113ad414f02576bd6afabfb302140225. Select this address from the Transaction Origin drop-down list and enter the following comma-delimited value into the transfer text box:

"0xdd870fa1b7c4700f2bd7f44238821c26f7392148", 150

After clicking Transfer, you’ll get the following error message, thanks to the require check you added earlier:

transact to browser/SimpleCoin.sol:SimpleCoin.transfer errored: VM error:
     invalid opcode.
  The constructor should be payable if you send value.
  The execution might have thrown.
  Debug the transaction to get more information.

Now try to transfer 150 tokens from the contract owner’s account to the same recipient you just tried. You need to select the account starting with 0x4b0897b on the Transaction Origin drop-down list and reenter the following comma-delimited value into the transfer text box:

"0xdd870fa1b7c4700f2bd7f44238821c26f7392148", 150

The operation will now be successful, as you can see in the output on the left side of the screen shown in figure 3.14.

Figure 3.14. Output of successful transfer operation

If you click the arrow next to Debug, you can verify in the logs property that the Transfer event has been raised at the end of the function call:

[
  {
    "event": "Transfer",
    "args": [
      "0000000000000000000000004b0897b0513fdc7c541b6d9d7e929c4e5364d2db",
      "000000000000000000000000dd870fa1b7c4700f2bd7f44238821c26f7392148",
      "150"
    ]
  }
]

After rechecking all the balances, the results should match table 3.7.

Table 3.7. The new balances of the SimpleCoin accounts

Account address

Account balance

0xca35b7d915458ef540ade6068dfe2f44e8fa733c 0
0x14723a09acff6d2a60dcdf7aa4aff308fddc160c 0
0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db 9,850
0x583031d1113ad414f02576bd6afabfb302140225 0
0xdd870fa1b7c4700f2bd7f44238821c26f7392148 150

Congratulations! You’ve completed this exercise. The improvements you’ve made weren’t particularly challenging, but making them should have helped you gain more familiarity with contracts.

3.5.3. How does the coin transfer execute in the Ethereum network?

You might have understood the Solidity code that performs the coin transfer but...if this transfer was taking place on a real Ethereum network rather than on the Remix JavaScript EVM emulator, would you know where within the network it would be executed? And would you know what effect a transfer of SimpleCoin tokens would have on the blockchain? You can get the answers to these questions by looking at the diagram in figure 3.15. I’ve adapted it for SimpleCoin from the transactional view you saw in figure 1.8 (chapter 1).

You’ll see other transaction lifecycle diagrams similar to this for all Dapps I’ll cover in the book. The lifecycle of an Ethereum transaction will be cemented in your head progressively throughout the book, until it becomes second nature to you.

Figure 3.15. The lifecycle of a SimpleCoin transfer transaction. A transfer transaction is created when a SimpleCoin wallet invokes the transfer() function on the SimpleCoin smart contract on a local node of the Ethereum network. This is then validated and propagated throughout the network until it’s included on a new blockchain block by a mining node. The new block is then propagated throughout the network, and finally it gets back to the local node.

Summary

  • The Ethereum wallet is a GUI that allows you to interact with the platform by creating accounts and transferring Ether intuitively.
  • The most popular Ethereum client is Go Ethereum, also known as geth. It comes with an interactive console that references Web3.js, a high-level interface to Ethereum clients.
  • It’s possible to interact with geth, for instance to create accounts, through various avenues:

    • geth commands executed in the operating system command shell
    • Web3.js instructions executed in the geth interactive console
    • HTTP JSON-RPC commands executed through cURL or a UI tool such as Postman
  • Ethereum smart contracts, or just contracts, are written in a high-level language such as Solidity, compiled into EVM bytecode, deployed on the Ethereum network, and stored in the blockchain.
  • It’s possible to communicate with contracts using calls, transactions, and events. A transaction involves the consumption of computational and network resources, which is calculated in a unit called gas and settled in Ether, the cryptocurrency of the Ethereum platform.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset